Skip to content

Frontend: SplitPane layout component — draggable, collapsible, persistent #507

@frankbria

Description

@frankbria

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

  • Dragging the divider updates pane widths in real-time
  • Drag is smooth (no jank from state updates during mousemove — use ref for position, flush to state on mouseup)
  • Collapse/expand buttons work for each pane
  • Position persists in localStorage across page reloads
  • Minimum pane width is enforced (no pane collapses to < 15% via drag)
  • Transition is smooth on collapse/expand, absent during drag
  • On mobile (< 768px): vertical stack layout

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions