Skip to content

feat(web): split-view divider controls, active-pane opening, and pane swap - #170

Merged
pandec merged 3 commits into
devfrom
t3code/improve-split-view-controls
Aug 23, 2026
Merged

feat(web): split-view divider controls, active-pane opening, and pane swap#170
pandec merged 3 commits into
devfrom
t3code/improve-split-view-controls

Conversation

@pandec

@pandec pandec commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Follow-ups to the two-pane split view (#163) after real use.

Problems. The secondary pane's switch/close buttons rendered in ChatView's absolute titlebar overlay, which only reserves 64px, so they covered the git actions. Sidebar clicks and ⌘K picks always retargeted the primary route, so the secondary pane's thread was effectively pinned, and clicking its thread while the primary showed a draft tripped the duplicate-thread guard and folded the whole split. There was also no way to swap the two panes, and the sidebar gave no hint which threads were open in the split.

Fixes.

  • Secondary-pane controls moved to a hover-revealed cluster on the resize divider: swap threads (ArrowLeftRight), switch split thread (Replace), close (X). The cluster is a sibling of the drag surface, stops pointerdown propagation, and hides while dragging, so it can never start or catch a resize.
  • "Open split view" is now a self-gated control at the end of the chat header's action row, between the git actions and the terminal toggle.
  • Sidebar clicks (incl. search results) and ⌘K thread picks route through planThreadOpen: the active pane receives the pick, and a thread already on screen just gets its pane focused instead of navigating, which is what fixes the split-folding bug. The palette snapshots its owner pane at open time because its own focus traffic moves the live value. Mod-click and shift-range selection are untouched.
  • New threadPane.swap command (default mod+shift+, ⌘K "Swap split threads", divider button). Swap sets the secondary to the old primary and navigates to the old secondary under a 5s store latch that the duplicate guard consults; expiry or rejection rolls back and toasts, and the same physical side stays active afterwards. Disabled while the primary shows a draft.
  • Sidebar rows for the two open threads carry PanelLeft/PanelRight glyphs while the split is mounted (one string-stable store subscription at list level; only the two affected rows re-render).

Verification. 35 focused tests across threadSplitStore.test.ts, threadOpenTarget.test.ts, splitPaletteItems.test.ts (the latch guard was mutation-tested); vp run typecheck 15/15; vp check 0 errors.

Implemented by Claude Fable 5 in Claude Code.

pandec added 3 commits August 23, 2026 13:39
… swap

The split-view pane controls lived in ChatView's titlebar overlay and
covered the git actions; sidebar and palette picks always retargeted the
primary route, and clicking the secondary pane's thread while the primary
showed a draft folded the whole split.

Secondary-pane controls now sit in a hover cluster on the resize divider
(swap / switch / close), and Open split view moved into the chat header's
action row. Sidebar clicks and cmd+K picks open into the active pane; a
thread already on screen just gets its pane focused, so a pick can never
fold the split. New threadPane.swap command (default mod+shift+\) trades
the two panes' threads under a store latch that keeps the duplicate-thread
guard quiet mid-swap. Sidebar rows mark the two open threads with pane
glyphs.
… controls

Review round (sol + opus on PR #170):

- The swap latch now expires through a store-owned timer; without one a
  stalled navigation left it (and every swap affordance) stuck, since the
  TTL was only read on re-renders. Mid-swap secondary picks keep the latch
  so the late route arrival is still recognized; abort already yields to
  the newer pick.
- mod+shift+\ never matched: Shift+Backslash types "|" and the resolver
  had no Backslash code alias. Added, with a regression test; both new
  behaviors were mutation-tested.
- Enter/Space row activation and archived-row opens now route through the
  active-pane helper like clicks; its primary branch delegates to the
  upstream navigateToThread instead of copying it.
- openThreadInActivePane returns the executed plan and the navigation
  promise, so palette picks surface rejections again; post-swap focus
  reclaim moved into swapThreadPanes so shortcut, palette, and divider
  paths behave alike; the overlay focus intent moved out of the store into
  the palette call sites so sidebar picks stop leaving stray intents.
- Divider: drag overhang biased off the primary pane's scrollbar lane,
  reveal delayed to stop crossing flashes, cluster pinned visible on
  coarse pointers, group label added, pane ring lowered below it, dead
  no-drag removed, disabled swap button's tooltip made reachable.
- Pane glyphs ride slim rows too; stale-named modules renamed
  (PaneControls, SplitPaneMarker).
…icks

Verification round follow-ups: a swap whose latch expired could still see
its navigation settle later and abort, toast over, or steal focus from a
newer swap — abortPaneSwap now takes the owning latch and stale
continuations no-op. Picking the in-flight swap's destination thread from
the sidebar or palette now focuses the primary pane (the route is already
heading there) instead of reopening it in the secondary, which folded the
split on arrival.
@pandec
pandec merged commit 5c90ea9 into dev Aug 23, 2026
1 check passed
pandec added a commit that referenced this pull request Aug 23, 2026
PR #170 landed on origin/dev mid-sync, touching ChatView.tsx and
Sidebar.tsx. The merge was conflict-free and holds up on inspection: the
slim-row split-pane marker sits after the provider icon and composes with
the pin indicator inserted after the title, and #170 already assumed a
settled thread can occupy a pane, which is exactly what pingdotgg#7969 makes common.

vp check, typecheck, focused split-view/sidebar/keybinding tests, and the
full suite all rerun and pass, except the documented PortScanner pair.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant