feat(desktop): the left sidebar resizes between standard bounds and folds past its least width
What
Middle of a three-PR stack: (A) #1841 right panel full screen / shared resize hook → (B, this) resizable left sidebar → (C) open/close animations.
The left sidebar's right border is now a resize edge, using PR A's useResizableEdge (no second resize primitive).
- Bounds: min 200px, max 400px, default 264px (the sidebar's width today). These are
SIDEBAR_WIDTHinsidebar-collapse.ts. A drag is clamped to them, and the sidebar is never dragged wider than the window minus 360px for the work column. - Overshoot: if the pointer goes 80px past the min (the same
SNAP_OVERSHOOTas the right panel), the sidebar folds on release. While dragging, the sidebar fades to show the pending fold (data-snap="collapse"), the same way the side panel does. The fold restores the width from before the drag, so the toggle or ⌘B reopens the sidebar at the width it had. Past the max there is no overshoot action; the sidebar stays at the max. - Double-click the edge sets the default width. Keyboard: the separator is focusable. Arrows step 16px (→ widens, since the edge is on the right), Home goes to min, End to max, Enter to default. The keyboard never folds the sidebar.
- Persistence: the width is kept next to the existing fold in the renderer's storage (
luke.sidebar-width). It is decoded withSchema.FiniteFromStringand clamped, so an out-of-range or unreadable value opens within bounds or at the default. A fixture run draws the default width and writes nothing, following the same staged-state pattern as the fold (#1827/#1839). - Layout: the width sets
--sidebar-widthon the app stage, so one variable drives the shell grid, the sidebar, Settings' page list (which uses the same width and has no edge of its own; that was the least complex option), and the centring of the captions over the work column. The sidebar toggle stays next to the traffic lights. The toolbar clearance while folded is unchanged, and while the sidebar is open the toolbar starts past it at any width (200px or more).
Out of scope: animations (PR C).
Tests
desktop-shell.test.ts covers the real useSidebarCollapse under DesktopShell:
- dragging between the bounds, and holding at max and min
- dragging past the min folds on release, and the toggle and ⌘B reopen at the old width
- a drag that comes back inside the bounds doesn't fold
- double-click and Enter reset to the default
- the arrows, Home and End (and the keyboard never folds)
- the width survives a fold, a visit to Settings, and a relaunch
- an out-of-range or unreadable stored width
- a fixture run draws the default and keeps nothing
Mac verification
CI could not verify the Mac UI, and ./scripts/verify.sh was not run. I built this on a Linux cloud VM. LUKE-159 is the manual Mac pass. I checked the layout by rendering DesktopShell with the built stylesheet in headless Chrome at 200, 264 and 400px and in the fold preview, but those screenshots are not uploaded. Drag regions and real pointer drags can only be checked on a Mac.
./scripts/check.sh exits 0.
🤖 Generated with Claude Code