feat(THI-246 PR 1/3): Split layout foundation — switcher + skeleton - #113
Merged
Conversation
First of three PRs that land the Split view (4th display type in v0.3).
This one ships the smallest viable diff so the layout choice is
reachable end-to-end and the surface is ready for the substantial
follow-ups.
What ships:
- Layout union: "kanban" | "grid" | "list" → adds "split". Updates
every enumeration (LayoutSwitcher, suggestLayout, etc.).
- New "split" Icon glyph (rail + detail rectangles), stroke-matched
to the existing layout icons.
- 4th LayoutSwitcher button (Kanban · Grid · List · Split), aria-
labeled and tooltip'd consistently with the other three.
- New persistent settings:
* selectedPaneId: "" — which pane the detail pane shows; restored
on reload + layout swap.
* splitRailWidth: 280 — divider drag (PR 2) clamps to 200–460.
- New components/split/SplitView.tsx — CSS grid (`rail | 7px | detail`)
filling .main. PR-1 rail is a flat Session → Pane tree mirroring
Kanban's sortPendingFirst order; PR 2 swaps this to the
Repo → Worktree → Pane tree from THI-243's discovery feed.
- New components/split/SplitView.test.tsx (6 tests) covers empty
state, row rendering, click-to-select persistence, mount-time
restore, rail-width plumbing, focus-in-tmux callback.
- New .sb-* CSS block (~180 lines) using only existing tokens. PR 1
styles what PR 1 actually renders; PR 2 adds resize/collapse/drag
affordances; PR 3 styles the inline xterm chrome.
- App.tsx branches on `layout === "split"` → renders <SplitView/>.
Other views unchanged.
- suggestLayout never suggests Split (or out of it) — opt-in,
same as Grid.
Deferred to follow-ups (PR 2 + PR 3 in the same ticket):
- Rail: repo-grouped tree, collapse-to-44px, divider resize,
drag-to-reorder, "+ New tab" rows (consuming THI-244).
- Detail: inline xterm with reconnect-don't-recreate, header chips
panel, sidebar (Linked / Notes / Activity).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…split-foundation # Conflicts: # frontend/src/lib/settings.ts
This was referenced Jun 7, 2026
Merged
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
First of three PRs that ship the Split view (v0.3 Track 3). THI-246 is explicitly L-sized — 4 new components, drag-to-reorder, xterm reconnect logic, multiple new state pieces, a 600+ LOC prototype to recreate. Splitting it across 3 PRs so each one is reviewable and ships incrementally:
What ships in PR 1
Types + setting
Layoutunion extended:"kanban" | "grid" | "list" | "split". Updates every enumeration site.selectedPaneId: stringsetting (default""). Restored on reload + layout swap.splitRailWidth: numbersetting (default280). Divider drag (PR 2) will clamp to 200–460.UI surface
"split"glyph inIcon.tsx— rail + detail rectangles, stroke-matched to the other layout glyphs.LayoutSwitcherbutton inSubhead: Kanban · Grid · List · Split.components/split/SplitView.tsx(~180 LOC): CSS grid<railWidth>px 7px 1frfilling.main.sortPendingFirstorder). PR 2 swaps this to the Repo → Worktree → Pane tree from THI-243's discovery feed.App.tsxbranches onlayout === "split"→ renders<SplitView>. Other views unchanged.suggestLayoutnever auto-suggests Split (opt-in, same as Grid).Styles
.sb-*CSS block (~180 lines) using only existing tokens (--bg-elev,--hairline,--text-mute,--accent-soft, etc.). PR 1 styles only what PR 1 renders; PR 2 + PR 3 add their pieces.Tests
SplitView: empty-state, row rendering, click-to-select persistence, mount-time restore, rail-width plumbing, focus-in-tmux callback.settings.test.tscases for the two new fields.Subheadlayout-switcher test for the 4-button count.Test plan (automated)
npm test).npm run typecheck: clean.npm run build: clean.Manual smoke (needs a live session — only the user can run this)
Switcher + skeleton
Selection + persistence
Filter interactions
Themes
.sb-*surfaces use existing tokens, so colors should adapt without any white-on-white or hard-edged regression.Out of scope for this PR (don't test these)
🤖 Generated with Claude Code