Sidebar widths and collapsed state
Both sidebars share width, drag and collapse behavior. Each sidebar owns only its navigation, state sources and main content.
State constraints
| State | Width rules | Behavior |
|---|---|---|
| Left expanded | 180–480px | Drag from the right edge; stop changing at the range limit |
| Right expanded | 240–720px | Drag from the left edge; stop changing at the range limit |
| Collapsed | Fixed at 49px | Both sides use the same 150ms width animation |
| Expand again | Restore the valid width from before collapse | Use the same width animation and retain the most recently adjusted width |
Implementation boundaries
components/layout/use-resizable-rail.ts is the sole implementation of width behavior: it saves expanded widths, enforces limits, handles pointer capture, generates expanded/collapsed styles and controls transitions. The sidebars supply their own limits and growth directions instead of maintaining separate event listeners. Handles share the rail-resize-handle style in base.css, with a hit area extending about 8px on either side of the divider without affecting layout width. The shell permits handle overflow while the inner content container remains clipped. Only the primary button starts a drag; touch panning and text selection on the handle are disabled.
Component boundaries
| File | Responsibility |
|---|---|
sidebar/sidebar.tsx | Left shell, persisted toggle, New chat, favorites and session composition |
sidebar/sidebar-primary-nav.tsx | Fixed navigation, route highlighting, navigation icon animation and Programs refresh |
right-sidebar/right-sidebar.tsx | Right shell, file entry and view container |
right-sidebar/detail-panel.tsx | Details/Context switching and detail rendering for the selected DAG node |
Do not split the session list or AppShell in this restructuring: their independent state and interaction boundaries require a change separate from moving sidebar shells.
Acceptance
Drag each sidebar to its limit and collapse it: it should smoothly become 49px wide within 150ms. Expanding again restores its previous width. Dragging can begin within about 8px on either side of the divider. Hovering and dragging change only the cursor, with no extra highlight. Dragging continues after the pointer leaves the handle. Release, pointer cancellation or window blur must restore the collapse animation. Window-level end events supplement captured handle events; a move event that detects a released button also ends the drag.
Implementation status
Implemented: both sidebars use the same width behavior module. Fixed navigation and detail rendering have moved out of the shell files; shell components only compose them.