Parent Issue
Part of #500 — used by #508 (sessions/[id] page)
Context
The /sessions/[id] page needs a side-by-side layout: agent chat on the left, terminal on the right. The divider should be draggable, each pane should be collapsible, and the split position should persist across page loads.
What to Build
New file: web-ui/src/components/sessions/SplitPane.tsx
Props:
interface SplitPaneProps {
left: React.ReactNode;
right: React.ReactNode;
defaultSplit?: number; // 0–100, default 45 (left gets 45%)
minPanePercent?: number; // minimum pane width %, default 15
storageKey?: string; // localStorage key for persistence, default "split-pane-position"
className?: string;
}
Behavior:
- Horizontal split (left | divider | right)
- Draggable divider:
mousedown on divider → mousemove on document → update split % → mouseup release
- Constrain to
[minPanePercent, 100 - minPanePercent]
- Collapse buttons on each pane edge (chevron icons):
- Left collapse: left pane shrinks to 0, right takes full width
- Right collapse: right pane shrinks to 0, left takes full width
- Click again to restore to last non-collapsed position
- Persist split position to
localStorage[storageKey] on drag end
- Restore from localStorage on mount
- Smooth CSS
transition: width 200ms only during collapse/expand (not during drag)
- Resize handle: 4px wide, hover: highlight with primary color, cursor:
col-resize
Responsive:
- On narrow viewports (< 768px): stack vertically, hide divider
- In vertical mode: chat on top (60%), terminal on bottom (40%)
Acceptance Criteria
Notes
- This is a general-purpose component — keep it generic, no session-specific logic
- No external drag library needed; native mouse events are sufficient
- Reference: Optio
apps/web/src/components/split-pane.tsx for the approach
Parent Issue
Part of #500 — used by #508 (sessions/[id] page)
Context
The
/sessions/[id]page needs a side-by-side layout: agent chat on the left, terminal on the right. The divider should be draggable, each pane should be collapsible, and the split position should persist across page loads.What to Build
New file:
web-ui/src/components/sessions/SplitPane.tsxProps:
Behavior:
mousedownon divider →mousemoveon document → update split % →mouseuprelease[minPanePercent, 100 - minPanePercent]localStorage[storageKey]on drag endtransition: width 200msonly during collapse/expand (not during drag)col-resizeResponsive:
Acceptance Criteria
Notes
apps/web/src/components/split-pane.tsxfor the approach