From 9a697a7c10c19ac9c58b3345f7abdf3d6794202f Mon Sep 17 00:00:00 2001 From: Robert Coroianu Date: Sun, 2 Nov 2025 20:47:46 +0200 Subject: [PATCH] [FEATURE] Adjustable Left Menu Width in Web Interface (#427) #234 Added to LeftSidebar.tsx functionality Update TopNavbar.tsx to use sidebar dynamic width Co-authored-by: Robert Coroianu --- src/ui/desktop/navigation/LeftSidebar.tsx | 88 +++++++++++++++++++++-- src/ui/desktop/navigation/TopNavbar.tsx | 3 +- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/ui/desktop/navigation/LeftSidebar.tsx b/src/ui/desktop/navigation/LeftSidebar.tsx index 0021283e..2afa54a8 100644 --- a/src/ui/desktop/navigation/LeftSidebar.tsx +++ b/src/ui/desktop/navigation/LeftSidebar.tsx @@ -241,6 +241,63 @@ export function LeftSidebar({ localStorage.setItem("leftSidebarOpen", JSON.stringify(isSidebarOpen)); }, [isSidebarOpen]); + // Sidebar width state for resizing + const [sidebarWidth, setSidebarWidth] = useState(() => { + const saved = localStorage.getItem("leftSidebarWidth"); + return saved !== null ? parseInt(saved, 10) : 320; + }); + + const [isResizing, setIsResizing] = useState(false); + const startXRef = React.useRef(null); + const startWidthRef = React.useRef(sidebarWidth); + + React.useEffect(() => { + localStorage.setItem("leftSidebarWidth", String(sidebarWidth)); + }, [sidebarWidth]); + + const handleMouseDown = (e: React.MouseEvent) => { + e.preventDefault(); + setIsResizing(true); + startXRef.current = e.clientX; + startWidthRef.current = sidebarWidth; + }; + + React.useEffect(() => { + if (!isResizing) return; + + const handleMouseMove = (e: MouseEvent) => { + if (startXRef.current == null) return; + const dx = e.clientX - startXRef.current; + const newWidth = Math.round(startWidthRef.current + dx); + const minWidth = 200; + const maxWidth = Math.round(window.innerWidth * 0.5); + if (newWidth >= minWidth && newWidth <= maxWidth) { + setSidebarWidth(newWidth); + } else if (newWidth < minWidth) { + setSidebarWidth(minWidth); + } else if (newWidth > maxWidth) { + setSidebarWidth(maxWidth); + } + }; + + const handleMouseUp = () => { + setIsResizing(false); + startXRef.current = null; + }; + + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + document.body.style.cursor = "col-resize"; + document.body.style.userSelect = "none"; + + return () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + document.body.style.cursor = ""; + document.body.style.userSelect = ""; + }; + }, [isResizing]); + const filteredHosts = React.useMemo(() => { if (!debouncedSearch.trim()) return hosts; const q = debouncedSearch.trim().toLowerCase(); @@ -293,8 +350,12 @@ export function LeftSidebar({ return (
- - + +
+ Termix @@ -416,8 +477,27 @@ export function LeftSidebar({ - - {children} + + + {/* Resizable divider */} + {isSidebarOpen && ( +
+
+
+ )} + + {children} +
{!isSidebarOpen && ( diff --git a/src/ui/desktop/navigation/TopNavbar.tsx b/src/ui/desktop/navigation/TopNavbar.tsx index 7d7ad169..b5fa7700 100644 --- a/src/ui/desktop/navigation/TopNavbar.tsx +++ b/src/ui/desktop/navigation/TopNavbar.tsx @@ -50,7 +50,8 @@ export function TopNavbar({ allSplitScreenTab: number[]; reorderTabs: (fromIndex: number, toIndex: number) => void; }; - const leftPosition = state === "collapsed" ? "26px" : "264px"; + // Use CSS variable for dynamic sidebar width + divider width (4px) + some padding + const leftPosition = state === "collapsed" ? "26px" : "calc(var(--sidebar-width) + 20px)"; const { t } = useTranslation(); const [toolsSheetOpen, setToolsSheetOpen] = useState(false);