From 10a319881d1669aab740c2397bc39ac016a3afbd Mon Sep 17 00:00:00 2001 From: Cyril Date: Thu, 13 Nov 2025 09:49:00 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20preserve=20left=20panel?= =?UTF-8?q?=20width=20on=20window=20resize?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prevents automatic resizing to keep user-defined width stable Signed-off-by: Cyril --- CHANGELOG.md | 1 + .../components/ResizableLeftPanel.tsx | 74 +++++++------------ 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18749ca183..bea432028b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to ### Security - mitigate role escalation in the ask_for_access viewset #1580 +- 🐛(frontend) preserve left panel width on window resize #1588 ### Removed diff --git a/src/frontend/apps/impress/src/features/left-panel/components/ResizableLeftPanel.tsx b/src/frontend/apps/impress/src/features/left-panel/components/ResizableLeftPanel.tsx index 4c3cc22eec..e9b4960e40 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/ResizableLeftPanel.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/ResizableLeftPanel.tsx @@ -5,23 +5,12 @@ import { PanelGroup, PanelResizeHandle, } from 'react-resizable-panels'; -import { createGlobalStyle } from 'styled-components'; import { useCunninghamTheme } from '@/cunningham'; -interface PanelStyleProps { - $isResizing: boolean; -} - -const PanelStyle = createGlobalStyle` - ${({ $isResizing }) => $isResizing && `body * { transition: none !important; }`} -`; - // Convert a target pixel width to a percentage of the current viewport width. -// react-resizable-panels expects sizes in %, not px. -const calculateDefaultSize = (targetWidth: number) => { - const windowWidth = window.innerWidth; - return (targetWidth / windowWidth) * 100; +const pxToPercent = (px: number) => { + return (px / window.innerWidth) * 100; }; type ResizableLeftPanelProps = { @@ -37,60 +26,49 @@ export const ResizableLeftPanel = ({ minPanelSizePx = 300, maxPanelSizePx = 450, }: ResizableLeftPanelProps) => { - const [isResizing, setIsResizing] = useState(false); const { colorsTokens } = useCunninghamTheme(); const ref = useRef(null); - const resizeTimeoutRef = useRef(undefined); + const savedWidthPxRef = useRef(minPanelSizePx); - const [minPanelSize, setMinPanelSize] = useState(0); - const [maxPanelSize, setMaxPanelSize] = useState(0); + const [panelSizePercent, setPanelSizePercent] = useState(() => + pxToPercent(minPanelSizePx), + ); - // Single resize listener that handles both panel size updates and transition disabling + const minPanelSizePercent = pxToPercent(minPanelSizePx); + const maxPanelSizePercent = Math.min(pxToPercent(maxPanelSizePx), 40); + + // Keep pixel width constant on window resize useEffect(() => { const handleResize = () => { - // Update panel sizes (px -> %) - const min = Math.round(calculateDefaultSize(minPanelSizePx)); - const max = Math.round( - Math.min(calculateDefaultSize(maxPanelSizePx), 40), - ); - setMinPanelSize(min); - setMaxPanelSize(max); - - // Temporarily disable transitions to avoid flicker - setIsResizing(true); - if (resizeTimeoutRef.current) { - clearTimeout(resizeTimeoutRef.current); + const newPercent = pxToPercent(savedWidthPxRef.current); + setPanelSizePercent(newPercent); + if (ref.current) { + ref.current.resize?.(newPercent - (ref.current.getSize() || 0)); } - resizeTimeoutRef.current = window.setTimeout(() => { - setIsResizing(false); - }, 150); }; - handleResize(); - window.addEventListener('resize', handleResize); - return () => { window.removeEventListener('resize', handleResize); - if (resizeTimeoutRef.current) { - clearTimeout(resizeTimeoutRef.current); - } }; - }, [minPanelSizePx, maxPanelSizePx]); + }, []); + + const handleResize = (sizePercent: number) => { + const widthPx = (sizePercent / 100) * window.innerWidth; + savedWidthPxRef.current = widthPx; + setPanelSizePercent(sizePercent); + }; return ( <> - - + {leftPanel}