From d137f85420e4ab4ee2dbc698211aebd58892bb23 Mon Sep 17 00:00:00 2001 From: Michael An <2331806369@qq.com> Date: Fri, 12 Jul 2024 15:52:10 +0800 Subject: [PATCH] 12.0 support drag side nav (#6340) * 01 optimize resize bar * 02 app side panel support resize * 03 side panel is folded do not support resize * 04 optimise code * 05 use localStorage --- frontend/src/app.js | 82 +++++++++++++++-- .../dir-view-mode/dir-column-view.js | 91 +++++-------------- .../src/components/resize-bar/constants.js | 4 + frontend/src/components/resize-bar/index.css | 43 +++++++++ frontend/src/components/resize-bar/index.js | 29 ++++++ frontend/src/components/side-panel.js | 9 +- frontend/src/css/lib-content-view.css | 44 --------- 7 files changed, 182 insertions(+), 120 deletions(-) create mode 100644 frontend/src/components/resize-bar/constants.js create mode 100644 frontend/src/components/resize-bar/index.css create mode 100644 frontend/src/components/resize-bar/index.js diff --git a/frontend/src/app.js b/frontend/src/app.js index a9e44a307a..46ce7c6db1 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -9,7 +9,13 @@ import SystemNotification from './components/system-notification'; import EventBus from './components/common/event-bus'; import Header from './components/header'; import SidePanel from './components/side-panel'; -import MainPanel from './components/main-panel'; +import ResizeBar from './components/resize-bar'; +import { + DRAG_HANDLER_HEIGHT, + INIT_SIDE_PANEL_RATE, + MAX_SIDE_PANEL_RATE, + MIN_SIDE_PANEL_RATE +} from './components/resize-bar/constants'; import FilesActivities from './pages/dashboard/files-activities'; import MyFileActivities from './pages/dashboard/my-file-activities'; import Starred from './pages/starred/starred'; @@ -48,11 +54,15 @@ class App extends Component { isSidePanelFolded: localStorage.getItem('sf_user_side_nav_folded') == 'true' || false, currentTab: '', pathPrefix: [], + inResizing: false, + sidePanelRate: parseFloat(localStorage.getItem('sf_side_panel_rate') || INIT_SIDE_PANEL_RATE), }; this.dirViewPanels = ['libraries', 'my-libs', 'shared-libs', 'org']; // and group window.onpopstate = this.onpopstate; const eventBus = new EventBus(); this.eventBus = eventBus; + this.resizeBarRef = React.createRef(); + this.dragHandlerRef = React.createRef(); } onpopstate = (event) => { @@ -207,9 +217,53 @@ class App extends Component { }); }; - render() { - const { currentTab, isSidePanelClosed, isSidePanelFolded } = this.state; + onResizeMouseUp = () => { + if (this.state.inResizing) { + this.setState({ + inResizing: false + }); + } + localStorage.setItem('sf_side_panel_rate', this.state.sidePanelRate); + }; + onResizeMouseDown = () => { + this.setState({ + inResizing: true + }); + }; + + onResizeMouseMove = (e) => { + let rate = e.nativeEvent.clientX / window.innerWidth; + this.setState({ + sidePanelRate: Math.max(Math.min(rate, MAX_SIDE_PANEL_RATE), MIN_SIDE_PANEL_RATE), + }); + }; + + onResizeMouseOver = (event) => { + if (!this.dragHandlerRef.current) return; + const { top } = this.resizeBarRef.current.getBoundingClientRect(); + const dragHandlerRefTop = event.pageY - top - DRAG_HANDLER_HEIGHT / 2; + this.setDragHandlerTop(dragHandlerRefTop); + }; + + setDragHandlerTop = (top) => { + this.dragHandlerRef.current.style.top = top + 'px'; + }; + + render() { + const { currentTab, isSidePanelClosed, isSidePanelFolded, sidePanelRate, inResizing } = this.state; + let mainPanelStyle = {}; + let sidePanelStyle = {}; + if (!isSidePanelFolded) { + mainPanelStyle = { + userSelect: inResizing ? 'none' : '', + flex: sidePanelRate ? `1 0 ${(1 - sidePanelRate) * 100}%` : `0 0 ${100 - INIT_SIDE_PANEL_RATE * 100}%`, + }; + sidePanelStyle = { + userSelect: inResizing ? 'none' : '', + flex: sidePanelRate ? `0 0 ${sidePanelRate * 100}%` : `0 0 ${INIT_SIDE_PANEL_RATE * 100}%`, + }; + } return ( @@ -220,7 +274,12 @@ class App extends Component { onSearchedClick={this.onSearchedClick} eventBus={this.eventBus} /> -
+
- + {!isSidePanelFolded && + + } +
@@ -263,7 +333,7 @@ class App extends Component { eventBus={this.eventBus} /> - +
diff --git a/frontend/src/components/dir-view-mode/dir-column-view.js b/frontend/src/components/dir-view-mode/dir-column-view.js index caf2e504b7..b72bf88445 100644 --- a/frontend/src/components/dir-view-mode/dir-column-view.js +++ b/frontend/src/components/dir-view-mode/dir-column-view.js @@ -5,6 +5,8 @@ import DirColumnFile from './dir-column-file'; import DirListView from './dir-list-view'; import DirGridView from './dir-grid-view'; import { SIDE_PANEL_FOLDED_WIDTH } from '../../constants'; +import ResizeBar from '../resize-bar'; +import { DRAG_HANDLER_HEIGHT, MAX_SIDE_PANEL_RATE, MIN_SIDE_PANEL_RATE } from '../resize-bar/constants'; const propTypes = { isSidePanelFolded: PropTypes.bool, @@ -73,19 +75,17 @@ const propTypes = { isDirentDetailShow: PropTypes.bool.isRequired }; -const DRAG_HANDLER_HEIGHT = 26; - class DirColumnView extends React.Component { constructor(props) { super(props); this.state = { inResizing: false, - navRate: 0.25, + navRate: parseFloat(localStorage.getItem('sf_dir_content_nav_rate') || 0.25), }; this.containerWidth = null; - this.resizeRef = null; - this.dragHandler = null; + this.resizeBarRef = React.createRef(); + this.dragHandlerRef = React.createRef(); this.viewModeContainer = React.createRef(); } @@ -95,7 +95,7 @@ class DirColumnView extends React.Component { inResizing: false }); } - this.setCookie('navRate', this.state.navRate); + localStorage.setItem('sf_dir_content_nav_rate', this.state.navRate); }; onResizeMouseDown = () => { @@ -107,65 +107,24 @@ class DirColumnView extends React.Component { onResizeMouseMove = (e) => { const { isSidePanelFolded } = this.props; - let sizeNavWidth = isSidePanelFolded ? SIDE_PANEL_FOLDED_WIDTH + 3 : this.containerWidth / 0.78 * 0.22 + 3; - + let sizeNavWidth = isSidePanelFolded ? SIDE_PANEL_FOLDED_WIDTH + 3 : window.innerWidth - this.containerWidth; let rate = (e.nativeEvent.clientX - sizeNavWidth) / this.containerWidth; - if (rate < 0.1) { - this.setState({ - inResizing: false, - navRate: 0.12, - }); - } - else if (rate > 0.4) { - this.setState({ - inResizing: false, - navRate: 0.38, - }); - } - else { - this.setState({ - navRate: rate - }); - } + this.setState({ + navRate: Math.max(Math.min(rate, MAX_SIDE_PANEL_RATE), MIN_SIDE_PANEL_RATE), + }); }; - onMouseOver = (event) => { - if (!this.dragHandler) return; - const { top } = this.resizeRef.getBoundingClientRect(); - const dragHandlerTop = event.pageY - top - DRAG_HANDLER_HEIGHT / 2; - this.setDragHandlerTop(dragHandlerTop); + onResizeMouseOver = (event) => { + if (!this.dragHandlerRef.current) return; + const { top } = this.resizeBarRef.current.getBoundingClientRect(); + const dragHandlerRefTop = event.pageY - top - DRAG_HANDLER_HEIGHT / 2; + this.setDragHandlerTop(dragHandlerRefTop); }; setDragHandlerTop = (top) => { - this.dragHandler.style.top = top + 'px'; + this.dragHandlerRef.current.style.top = top + 'px'; }; - setCookie = (name, value) => { - let cookie = name + '=' + value + ';'; - document.cookie = cookie; - }; - - getCookie = (cookiename) => { - let name = cookiename + '='; - let cookie = document.cookie.split(';'); - for (let i = 0, len = cookie.length; i < len; i++) { - let c = cookie[i].trim(); - if (c.indexOf(name) == 0) { - return c.substring(name.length, c.length) * 1; - } - } - return ''; - }; - - UNSAFE_componentWillMount() { - let rate = this.getCookie('navRate'); - if (rate) { - this.setState({ - navRate: rate, - }); - } - } - render() { const { currentMode, isTreePanelShown } = this.props; const { navRate, inResizing } = this.state; @@ -198,16 +157,14 @@ class DirColumnView extends React.Component { selectedDirentList={this.props.selectedDirentList} onItemsMove={this.props.onItemsMove} /> -
this.resizeRef = ref} - style={{ left: `calc(${navRate ? navRate * 100 + '%' : '25%'} - 1px)` }} - onMouseDown={this.onResizeMouseDown} - onMouseOver={this.onMouseOver} - > -
-
this.dragHandler = ref} style={{ height: DRAG_HANDLER_HEIGHT }}>
-
+ )}
{} : this.props.onItemsScroll}> diff --git a/frontend/src/components/resize-bar/constants.js b/frontend/src/components/resize-bar/constants.js new file mode 100644 index 0000000000..a2d1460bbd --- /dev/null +++ b/frontend/src/components/resize-bar/constants.js @@ -0,0 +1,4 @@ +export const DRAG_HANDLER_HEIGHT = 26; +export const INIT_SIDE_PANEL_RATE = 0.22; +export const MAX_SIDE_PANEL_RATE = 0.40; +export const MIN_SIDE_PANEL_RATE = 0.15; diff --git a/frontend/src/components/resize-bar/index.css b/frontend/src/components/resize-bar/index.css new file mode 100644 index 0000000000..1a5e23b721 --- /dev/null +++ b/frontend/src/components/resize-bar/index.css @@ -0,0 +1,43 @@ +.resize-bar { + height: 100%; + width: 6px; + position: absolute; + top: 0; + z-index: 8; + opacity: 0; + transition-duration: .2s; + transition-property: opacity; +} + +.resize-bar:hover { + opacity: 1; + cursor: col-resize; +} + +.resize-bar .resize-bar-line { + background-color: #aaa; + height: 100%; + width: 2px; + display: none; + user-select: none; +} + +.resize-bar:hover .resize-bar-line { + display: block; +} + +.resize-bar .resize-bar-drag-handler { + background: #2d7ff9; + border-radius: 10px; + margin-left: 1px; + position: absolute; + transform: translate(-50%); + width: 6px; + display: none; + z-index: 1; + user-select: none; +} + +.resize-bar:hover .resize-bar-drag-handler { + display: block; +} diff --git a/frontend/src/components/resize-bar/index.js b/frontend/src/components/resize-bar/index.js new file mode 100644 index 0000000000..8bf96b380e --- /dev/null +++ b/frontend/src/components/resize-bar/index.js @@ -0,0 +1,29 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './index.css'; + +function ResizeBar(props) { + return ( +
+
+
+
+ ); +} + +ResizeBar.propTypes = { + resizeBarRef: PropTypes.object.isRequired, + resizeBarStyle: PropTypes.object.isRequired, + dragHandlerRef: PropTypes.object.isRequired, + dragHandlerStyle: PropTypes.object.isRequired, + onResizeMouseDown: PropTypes.func.isRequired, + onResizeMouseOver: PropTypes.func.isRequired, +}; + +export default ResizeBar; diff --git a/frontend/src/components/side-panel.js b/frontend/src/components/side-panel.js index 350badc55b..c8d0ced9dd 100644 --- a/frontend/src/components/side-panel.js +++ b/frontend/src/components/side-panel.js @@ -12,6 +12,7 @@ const propTypes = { onCloseSidePanel: PropTypes.func, tabItemClick: PropTypes.func, children: PropTypes.object, + style: PropTypes.object, isSidePanelFolded: PropTypes.bool, toggleFoldSideNav: PropTypes.func }; @@ -19,10 +20,12 @@ const propTypes = { class SidePanel extends React.Component { render() { - const { children, isSidePanelFolded } = this.props; - const style = isSidePanelFolded ? { flexBasis: SIDE_PANEL_FOLDED_WIDTH } : {}; + const { children, isSidePanelFolded, style } = this.props; return ( -
+
diff --git a/frontend/src/css/lib-content-view.css b/frontend/src/css/lib-content-view.css index a8235d73eb..b0c7d60dbf 100644 --- a/frontend/src/css/lib-content-view.css +++ b/frontend/src/css/lib-content-view.css @@ -224,50 +224,6 @@ width: 100%; } -.dir-content-resize { - height: 100%; - width: 6px; - position: absolute; - top: 0; - z-index: 8; - opacity: 0; - transition-duration: .2s; - transition-property: opacity; -} - -.dir-content-resize:hover { - opacity: 1; - cursor: col-resize; -} - -.dir-content-resize .line { - background-color: #aaa; - height: 100%; - width: 2px; - display: none; - user-select: none; -} - -.dir-content-resize:hover .line { - display: block; -} - -.dir-content-resize .drag-handler { - background: #2d7ff9; - border-radius: 10px; - margin-left: 1px; - position: absolute; - transform: translate(-50%); - width: 6px; - display: none; - z-index: 1; - user-select: none; -} - -.dir-content-resize:hover .drag-handler { - display: block; -} - .readonly-tip-message { display: flex; padding: 0.25rem 0;