From 7a6fae8f6c7c4b83e64e9b79146f5dc9980d082c Mon Sep 17 00:00:00 2001 From: barkstone2 Date: Sun, 8 Feb 2026 21:59:45 +0900 Subject: [PATCH] feat: add draggable left sidebar resizing --- .../components/WorkspaceLeafResizeHandle.tsx | 9 ++--- .../src/containers/WorkspaceContainer.tsx | 34 ++++++++++++++++++- .../containers/WorkspaceSplitContainer.tsx | 25 ++++++++++---- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/react-app-internal/src/components/WorkspaceLeafResizeHandle.tsx b/react-app-internal/src/components/WorkspaceLeafResizeHandle.tsx index 537729d..409e9fa 100644 --- a/react-app-internal/src/components/WorkspaceLeafResizeHandle.tsx +++ b/react-app-internal/src/components/WorkspaceLeafResizeHandle.tsx @@ -1,10 +1,11 @@ -import {CSSProperties} from "react"; +import {CSSProperties, MouseEvent} from "react"; interface WorkspaceLeafResizeHandleProps { style?: CSSProperties; + onMouseDown?: (event: MouseEvent) => void; } -export function WorkspaceLeafResizeHandle({style}: WorkspaceLeafResizeHandleProps) { +export function WorkspaceLeafResizeHandle({style, onMouseDown}: WorkspaceLeafResizeHandleProps) { return ( -
+
) -} \ No newline at end of file +} diff --git a/react-app-internal/src/containers/WorkspaceContainer.tsx b/react-app-internal/src/containers/WorkspaceContainer.tsx index c6b67d4..f1d46e8 100644 --- a/react-app-internal/src/containers/WorkspaceContainer.tsx +++ b/react-app-internal/src/containers/WorkspaceContainer.tsx @@ -1,4 +1,4 @@ -import {ReactNode, useEffect, useState} from "react"; +import {MouseEvent as ReactMouseEvent, ReactNode, useCallback, useEffect, useState} from "react"; import {WorkspaceSplitContainer} from "./WorkspaceSplitContainer"; import TreeContainer from "../components/TreeContainer"; import {WorkspaceTabs} from "../components/tab-header/WorkspaceTabs"; @@ -33,6 +33,9 @@ export function resolveTocHeaders( const leftSideDockOpenedClassName = 'is-left-sidedock-open'; const rightSideDockOpenedClassName = 'is-right-sidedock-open'; +const defaultLeftSideDockWidth = 300; +const minLeftSideDockWidth = 220; +const maxLeftSideDockWidth = 560; export function WorkspaceContainer({children}: {children: ReactNode}) { const {'*': filePath } = useParams(); @@ -54,6 +57,7 @@ export function WorkspaceContainer({children}: {children: ReactNode}) { const [isLeftSideDockOpened, setIsLeftSideDockOpened] = useState(!isMobile); const [isRightSideDockOpened, setIsRightSideDockOpened] = useState(!isMobile); + const [leftSideDockWidth, setLeftSideDockWidth] = useState(defaultLeftSideDockWidth); useEffect(() => { setIsLeftSideDockOpened(!isMobile) @@ -69,11 +73,39 @@ export function WorkspaceContainer({children}: {children: ReactNode}) { workspaceClassName += ' ' + rightSideDockOpenedClassName; } + const handleLeftSidebarResizeMouseDown = useCallback((event: ReactMouseEvent) => { + if (isMobile || !isLeftSideDockOpened) { + return; + } + + event.preventDefault(); + const startX = event.clientX; + const startWidth = leftSideDockWidth; + + const handleMouseMove = (moveEvent: MouseEvent) => { + const nextWidth = Math.min( + maxLeftSideDockWidth, + Math.max(minLeftSideDockWidth, startWidth + (moveEvent.clientX - startX)), + ); + setLeftSideDockWidth(nextWidth); + }; + + const handleMouseUp = () => { + window.removeEventListener('mousemove', handleMouseMove); + window.removeEventListener('mouseup', handleMouseUp); + }; + + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); + }, [isLeftSideDockOpened, isMobile, leftSideDockWidth]); + return (
) => void; + children?: ReactNode; } -export function WorkspaceSplitContainer({modOrientation, isSideDock, modSplitDirection, isSideDockCollapse, children}: WorkspaceSplitContainerProps) { +export function WorkspaceSplitContainer({ + modOrientation, + isSideDock, + modSplitDirection, + isSideDockCollapse, + width, + onResizeMouseDown, + children, +}: WorkspaceSplitContainerProps) { const collapsedClass = isSideDockCollapse && "is-sidedock-collapsed"; - let styles: CSSProperties = isSideDock ? {width: '300px'} : {} + let styles: CSSProperties = isSideDock ? {width: `${width ?? 300}px`} : {} styles = isSideDockCollapse ? {width: 0, display: 'none'} : styles; return (
- + {children}
) -} \ No newline at end of file +}