From a863864644b2eedd66a2d3a4c58a6a3051151af0 Mon Sep 17 00:00:00 2001 From: srgooglo Date: Thu, 17 Sep 2020 21:23:11 +0200 Subject: [PATCH] *update: model improvement *add: contextual menu *update: ipc models *update: post cards ux handlers & events listeners --- .umirc.js | 1 - config/index.js | 1 + main/index.js | 21 +++-- package.json | 3 +- public/logo.svg | 21 ++--- src/components/Layout/ContextMenu/index.less | 29 +++++++ src/components/Layout/ContextMenu/index.tsx | 70 +++++++++++++++ .../Layout/Sider/default/index.less | 5 +- src/components/Layout/index.js | 3 +- src/components/PostCard/index.js | 69 ++++++++++----- src/components/PostCard/index.less | 2 + src/layouts/PrimaryLayout.js | 85 ++++++++++++++++--- src/models/app.js | 17 +++- src/pages/explore/index.js | 37 ++++---- 14 files changed, 285 insertions(+), 79 deletions(-) create mode 100644 src/components/Layout/ContextMenu/index.less create mode 100644 src/components/Layout/ContextMenu/index.tsx diff --git a/.umirc.js b/.umirc.js index 77350153..17ecb9fd 100755 --- a/.umirc.js +++ b/.umirc.js @@ -1,5 +1,4 @@ import { defineConfig } from 'umi'; - const { resolve, join } = require('path'); export default defineConfig({ diff --git a/config/index.js b/config/index.js index 0a3b4407..b5a76b30 100644 --- a/config/index.js +++ b/config/index.js @@ -11,6 +11,7 @@ module.exports = { api_prefix: 'ycorejs_apiv3', app_settings_storage: 'app_settings', + endpoint_global: 'https://comty.pw', session_token_storage: 'cid', session_data_storage: 'data', diff --git a/main/index.js b/main/index.js index e90bf1fd..5c8cd481 100644 --- a/main/index.js +++ b/main/index.js @@ -41,17 +41,16 @@ if (!gotTheLock) { app.quit(); } -function contextualMenu(cords){ - if (!cords) { +function contextualMenu(payload){ + if (!payload) { return false } - log.log(cords) const menu = new Menu() const menuItem = new MenuItem({ label: 'Inspect Element', click: () => { - mainWindow.inspectElement(cords.x, cords.y) + mainWindow.inspectElement(payload.x, payload.y) } }) menu.append(menuItem) @@ -156,8 +155,8 @@ function createWindow() { { label: '🔄 Reload', click: () => { - app.relaunch(); - mainWindow.close(); + mainWindow.close() + app.relaunch() } }, { @@ -264,11 +263,15 @@ ipcMain.handle('appRestart', () => { mainWindow.close(); }); -ipcMain.handle('app_notify', (payload) => { +ipcMain.handle('app_notify', (event, payload) => { notify(payload) }) -ipcMain.handle('contextualMenu', (payload) => { - log.log(payload) +ipcMain.handle('contextualMenu', (event, payload) => { contextualMenu(payload) +}) + +ipcMain.handle('inspectElement', (event, payload) => { + log.log(payload) + mainWindow.inspectElement(payload.x, payload.y) }) \ No newline at end of file diff --git a/package.json b/package.json index 0911edba..90b54dad 100755 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4", "title": "Comty™", "DevBuild": true, - "version": "0.9.17", + "version": "0.9.18", "stage": "dev-pre", "description": "", "author": "RageStudio", @@ -41,6 +41,7 @@ "babel-core": "^6.26.3", "classnames": "^2.2.6", "cookie_js": "^1.4.0", + "dotenv": "^8.2.0", "electron-config": "^2.0.0", "electron-context-menu": "^2.3.0", "electron-is": "^3.0.0", diff --git a/public/logo.svg b/public/logo.svg index e9c786ee..97bafc18 100755 --- a/public/logo.svg +++ b/public/logo.svg @@ -1,21 +1,18 @@ - + - + - + - - - - - - + + + + + + diff --git a/src/components/Layout/ContextMenu/index.less b/src/components/Layout/ContextMenu/index.less new file mode 100644 index 00000000..06e308ea --- /dev/null +++ b/src/components/Layout/ContextMenu/index.less @@ -0,0 +1,29 @@ +.contextualMenu { + position: absolute; + background-color: rgba(36, 36, 36, 0.7); + border-radius: 4px; + padding: 10px 5px; + z-index: 1000; + width: 250px; + height: auto; + color: #e3e3e3; + display: flex; + flex-direction: column; + font-size: 14px; + + > div{ + cursor: pointer; + display: flex; + + align-items: center; + border-radius: 4px; + padding: 0 0 0 10px; + color: #e3e3e3; + width: 100%; + height: 35px; + } + > div:hover{ + background-color: #e3e3e3; + color: rgba(36, 36, 36, 0.7); + } +} \ No newline at end of file diff --git a/src/components/Layout/ContextMenu/index.tsx b/src/components/Layout/ContextMenu/index.tsx new file mode 100644 index 00000000..d3226bec --- /dev/null +++ b/src/components/Layout/ContextMenu/index.tsx @@ -0,0 +1,70 @@ +import React from 'react' +import * as antd from 'antd' +import * as Icons from 'components/Icons' +import styles from './index.less' + +export interface ContextMenu_props { + visible: boolean; + fragment: object; + yPos: number; + xPos: number; + app: any; + dispatch: any; +} + +export default class ContextMenu extends React.Component{ + constructor(props){ + super(props) + this.setWrapperRef = this.setWrapperRef.bind(this) + this.handleClickOutside = this.handleClickOutside.bind(this) + + this.eventListener = document.addEventListener('click', this.handleClickOutside, false) + } + + + setWrapperRef(node){ + this.wrapperRef = node + } + + handleClickOutside(event) { + if ( this.props.visible || this.wrapperRef && !this.wrapperRef.contains(event.target)) { + window.contextMenu.toogle() + this.listening = false + document.removeEventListener('click', this.eventListener, false) + } + } + + componentDidUpdate(){ + if (!this.listening) { + this.listening = true + this.eventListener + } + } + + render(){ + if (this.props.visible) { + return( +
+ {this.props.fragment} +
+ ) + } + return null + } +} + + +ContextMenu.defaultProps = { + visible: false, + fragment: null, + xPos: 0, + yPos: 0 +} + diff --git a/src/components/Layout/Sider/default/index.less b/src/components/Layout/Sider/default/index.less index 38255c31..e734d152 100644 --- a/src/components/Layout/Sider/default/index.less +++ b/src/components/Layout/Sider/default/index.less @@ -2,6 +2,7 @@ .left_sider_wrapper { + -webkit-app-region: no-drag; user-select: none; border-color: transparent; font-size: 15px; @@ -29,6 +30,7 @@ } .ant-menu-item { + -webkit-app-region: no-drag; transition: @transition-ease-inout; border-radius: 4px 8px 8px 4px; @@ -72,8 +74,9 @@ .left_sider_header { cursor: pointer; margin: 15px 0 0 22px; - + -webkit-user-drag: none; .logotype{ + -webkit-app-region: no-drag; max-height: 70px; height: 35px; } diff --git a/src/components/Layout/index.js b/src/components/Layout/index.js index 0dc764db..9b24adf8 100755 --- a/src/components/Layout/index.js +++ b/src/components/Layout/index.js @@ -1,5 +1,6 @@ import Sider from './Sider' import Overlay from './Overlay' import WindowNavbar from './WindowNavbar' +import ContextMenu from './ContextMenu/index.tsx' -export { Sider, Overlay, WindowNavbar } +export { Sider, Overlay, WindowNavbar, ContextMenu } diff --git a/src/components/PostCard/index.js b/src/components/PostCard/index.js index 4b658808..6f70abcd 100644 --- a/src/components/PostCard/index.js +++ b/src/components/PostCard/index.js @@ -9,8 +9,10 @@ import classnames from 'classnames' import settings from 'core/libs/settings' import { router } from 'core/cores' +import { notify } from 'core/libs/interface' import LikeBtn from './components/like' import { connect } from 'umi' +import config from 'config' const { Meta } = antd.Card @@ -45,6 +47,21 @@ export default class PostCard extends React.Component { }) } + generatePostURI(id){ + if(config.app_config.endpoint_global && id){ + return `${config.app_config.endpoint_global}/post/${id}` + } + return null + } + + goElementById(id){ + document.getElementById(id).scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "center" + }) + } + toogleMoreMenu(){ this.setState({ visibleMoreMenu: !this.state.visibleMoreMenu }) } @@ -53,6 +70,15 @@ export default class PostCard extends React.Component { } + writeToClipboard(text){ + navigator.clipboard.writeText(text) + .then(() => { + notify.info('Copy to clipboard') + }, () => { + /* failure */ + }) + } + renderReportedPost(){ if(this.state.ReportIgnore) return null return ( @@ -134,28 +160,27 @@ export default class PostCard extends React.Component { } render() { - const handleContextMenu = e => this.handleDispatchInvoke("contextualMenu", {cords: {x: e.clientX, y: e.clientY} }) - const actions = [ - , - , - 0 ? true : false}> - - , - ] + const actions = [ + , + , + 0 ? true : false}> + + , + ] - return ( -
- null} - onClick={this.handleClick} - onContextMenu={handleContextMenu} - actions={actions} - hoverable - > - {this.renderPost(this.state.payload)} - -
- ) + return ( +
+ null} + onClick={() => this.goElementById(this.state.payload.id)} + onContextMenu={() => this.writeToClipboard(this.generatePostURI(this.state.payload.id))} + actions={actions} + hoverable + > + {this.renderPost(this.state.payload)} + +
+ ) } } \ No newline at end of file diff --git a/src/components/PostCard/index.less b/src/components/PostCard/index.less index 82851121..3aed6d53 100644 --- a/src/components/PostCard/index.less +++ b/src/components/PostCard/index.less @@ -18,6 +18,7 @@ } .post_card_wrapper { + user-select: none; box-shadow: @post_card_wrapper_shadow; border-radius: @post_card_general_border-rd; max-width: 510px; @@ -182,6 +183,7 @@ margin: 23px 24px 23px 24px; h3 { + user-select: all; font-family: @__Global_general_font_family; color: @post_card_wrapper_post_content_color; font-weight: @post_card_wrapper_post_content_weight; diff --git a/src/layouts/PrimaryLayout.js b/src/layouts/PrimaryLayout.js index ec6d67f6..f92f6284 100755 --- a/src/layouts/PrimaryLayout.js +++ b/src/layouts/PrimaryLayout.js @@ -4,7 +4,7 @@ import React from 'react' import PropTypes from 'prop-types' import {withRouter, connect} from 'umi' import { - AppLayout, + AppLayout } from 'components' import { enquireScreen, unenquireScreen } from 'enquire-js' import store from 'store' @@ -13,26 +13,83 @@ import classnames from 'classnames' import { app_config } from 'config' import { theme } from 'core/libs/style' import * as antd from 'antd' +import * as Icons from 'components/Icons' import styles from './PrimaryLayout.less' +const contextMenuList = [ + { + key: "inspect_element", + title: "Inspect", + icon: + } +] + const { Content } = antd.Layout -const { Sider, Overlay } = AppLayout +const { Sider, Overlay, ContextMenu } = AppLayout const isActive = (key) => { return key? key.active : false } +const currentTheme = theme.get() @withRouter @connect(({ app, loading }) => ({ app, loading })) class PrimaryLayout extends React.Component { constructor(props) { - super(props); + super(props) this.state = { collapsed: app_config.default_collapse_sider ? true : false, - isMobile: false, + isMobile: false }, - window.PrimaryComponent = this; + + this.handleContextMenu = window.addEventListener("contextmenu", (e) => { + e.preventDefault() + window.contextMenu.open({ xPos: e.clientX, yPos: e.clientY, fragment: this.generateContextMenu() }) + },false ) + window.DarkMode = isActive(currentTheme["darkmode"])? true : false + + window.contextMenu = this.props.app.contextMenu + window.contextMenu.toogle = () => { + this.props.dispatch({ + type: "app/updateState", + payload: {contextMenu: {...this.props.app.contextMenu, visible: !this.props.app.contextMenu.visible} } + }) + } + window.contextMenu.open = (payload) => { + if (!payload) return false + const fragment = payload.fragment || null + const xPos = payload.xPos || null + const yPos = payload.yPos || null + this.props.dispatch({ + type: "app/updateState", + payload: {contextMenu: {...this.props.app.contextMenu, xPos, yPos, fragment, visible: true}} + }) + } + } + + handleContextMenuActions = { + inspect_element: (e) =>{ + this.props.dispatch({ + type: "app/ipcInvoke", + payload: { + key: "inspectElement", + payload: { x: e.clientX, y: e.clientY } + } + }) + } + } + + generateContextMenu() { + return contextMenuList.map((e) => { + return( +
+ {e.icon}{e.title} +
+ ) + }) } componentDidMount() { + this.handleContextMenu + this.enquireHandler = enquireScreen(mobile => { const { isMobile } = this.state if (isMobile !== mobile) { @@ -44,6 +101,7 @@ class PrimaryLayout extends React.Component { } componentWillUnmount() { + window.removeEventListener("contextmenu", this.handleContextMenu) unenquireScreen(this.enquireHandler) } @@ -54,10 +112,10 @@ class PrimaryLayout extends React.Component { } render() { - const { location, dispatch, children } = this.props + const { location, dispatch, children, app } = this.props const { collapsed, isMobile } = this.state const { onCollapseChange } = this - const currentTheme = theme.get() + const { contextMenu } = app const app_theme = isActive(currentTheme["darkmode"])? "dark" : null const breakpoint = { @@ -83,9 +141,16 @@ class PrimaryLayout extends React.Component { app_theme } - window.DarkMode = isActive(currentTheme["darkmode"])? true : false + return ( - + + {isActive(currentTheme['backgroundImage']) ?
: null} - +
', payload) const ipc = state.electron.ipcRenderer + ipc.invoke(payload.key, payload.payload) }, + ipcSend(state, {payload}){ + if (!payload || !state.embedded) { + return false + } + console.log('send INVOKING => ', payload) + const ipc = state.electron.ipcRenderer + ipc.send(payload.key, payload.payload) + }, allNotificationsRead(state) { state.notifications = []; }, diff --git a/src/pages/explore/index.js b/src/pages/explore/index.js index 16f50ed0..86537cba 100644 --- a/src/pages/explore/index.js +++ b/src/pages/explore/index.js @@ -37,38 +37,35 @@ export default class Explore extends React.Component { if (this.props.app.session_valid) { this.request() } - window.addEventListener('contextmenu', (e) => { - this.props.dispatch({ - type: "app/ipcInvoke", - payload: { key: "contextualMenu", payload: {x: e.clientX, y: e.clientY} } - }) - },false) } + render() { + + if(!this.props.app.session_valid){ + return () + } + if (!this.state.feed){ return ( - ) + ) } return( - <> - - +
( -
- -
- )} - /> - + //loadMore={loadMore} + dataSource={this.state.feed} + renderItem={item => ( +
+ +
+ )} + /> +
) - } }