Add split pane for terminal/changes area#743
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Install react-resizable-panels v4.12.1 dependency - Create Resizable component wrapping Group, Panel, and Separator - Exports ResizablePanelGroup, ResizablePanel, ResizableHandle for split-pane UI Co-Authored-By: Claude Opus 4.6 <[email protected]>
Adds per-agent split-pane state (mode, left/right CenterTab, sizes) backed by localStorage, following the existing atomWithLocalStorage + atomFamily + reconcile*Storage pattern used for media sidebar and diff view state. Also adds the useSplitPane hook that later tasks (tab bar, agents-view integration) will consume for drag-to-split behavior. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace INACTIVE_ATOM (localStorage-backed with empty string key) with inactiveSplitPaneStateAtom (plain in-memory atom) to avoid unnecessary persistence. Add guards to exitSplit and updateSizes for null agentId. Co-Authored-By: Claude Opus 4.6 <[email protected]>
- CenterPaneTabBar: tabs are now draggable (application/x-dispatch-tab MIME) and tabs currently shown in split panes are hidden from the bar. - New SplitDropZones overlay component providing left/right drop targets. - agents-view.tsx: pass placeholder isSplit/splitState/isMobile props to CenterPaneTabBar so the repo-wide typecheck (enforced by the pre-commit hook) stays green; Task 4 will replace these with real useSplitPane wiring and mount SplitDropZones. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Wires useSplitPane into AgentsView: renders ResizablePanelGroup with two panes and per-pane headers when split, tracks tab-drag state to show SplitDropZones, moves ChangesSettingsPopover into the pane header in split mode, and exits split mode when a tab is clicked in the center tab bar. Also reconciles split-pane localStorage against live agent ids alongside the existing media/diff-view reconciliation.
onLayoutChange fires on every pointer-move during resize, causing a synchronous localStorage write per mousemove. Switch to onLayoutChanged, which only fires when the drag gesture ends, per the library's docs. Also extract the duplicated TerminalPane/ChangesTab JSX (previously repeated across the left split pane, right split pane, and single-pane mode) into terminalElement/changesElement locals computed once per render.
Cover split state persistence across reload, unsplit button exit, tab bar hiding during split, post-unsplit tab switching, and drag-and-drop entry via synthesized DragEvents. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Move unsplit button above resize handle (no cursor conflict) - Use Split icon instead of Columns2 - Bigger button with proper padding - Add left padding to pane headers to clear unsplit button - Disable drag on active tab (no-op drop) - Center tab bar with grid layout (immune to icon changes) - Remove committed plan and spec files Co-Authored-By: Claude Opus 4.6 <[email protected]>
Move unsplit button outside ResizableHandle to fix cursor showing resize icon instead of pointer. Position button absolutely using ResizeObserver on the left panel for real-time tracking during resize drag. Button is vertically centered in the pane header row. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add document-level dragend listener to reset isDraggingTab state, preventing drop zones from staying visible if a drag operation ends without a clean dragleave event (browser quirk edge case). Co-Authored-By: Claude Opus 4.6 <[email protected]>
Resolve conflicts in agents-view.tsx (add useNavigate + Split imports, keep split pane code with new onReviewSubmitted prop) and use-media-sidebar-state.ts (add both reconcile functions). Co-Authored-By: Claude Opus 4.6 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Details
Entering split mode: Drag an inactive tab from the center tab bar into a left or right drop zone. Only inactive tabs are draggable (active tab drag is a no-op).
Exiting split mode: Click the unsplit button on the divider, or click any tab in the center tab bar while split.
Unsplit button: Positioned absolutely outside the
ResizableHandleto avoid cursor conflicts with the resize library. Uses aResizeObserveron the left panel for pixel-accurate tracking during drag. Vertically centered in the 32px pane header row.Tab centering: Header uses CSS grid (
grid-cols-[1fr_auto_1fr]) so tabs stay centered regardless of left/right icon counts.Safety: Document-level
dragendlistener prevents stuck drop zone overlays from browser DnD quirks.Files changed
agents-view.tsx— Main split pane integration, ResizeObserver tracking, drag statecenter-pane-tab-bar.tsx— Draggable tabs, split-aware filtering, typographic minussplit-drop-zones.tsx— Left/right drop zone overlays (new)use-split-pane.ts— Core hook: enter/exit/update/drop with duplicate-pane guard (new)store.ts— CenterTab type, SplitPaneState, atomFamily with localStorage (new types)resizable.tsx— shadcn wrapper for react-resizable-panels v4 (new)split-pane.spec.ts— 6 E2E tests (new)store.test.ts— Unit tests for split pane state atoms (new)Test plan
pnpm run check)pnpm run finalize:web)🤖 Generated with Claude Code