Summary
Redesign the terminal pane toolbar (the + ▾ ⏐ ⎯ × controls) with real inline SVG icons and consolidate the two split buttons into a single Layout split-button with a dropdown. Also fixes a bug where the existing "new tab type" caret dropdown never appears.
All of this lives in one component: src/renderer/components/SplitPane/SurfaceTabBar.tsx (styled in src/renderer/styles/splitpane.css). PaneWrapper.tsx already wires up every handler needed (onNew, onNewTyped, onNewProfile, onSplitRight, onSplitDown, onClosePane), so this is a presentational redesign — no new plumbing.
Bug fixed by this work
The "new tab type" caret (▾) currently does nothing when clicked, even with profiles configured. Root cause: .surface-tab-bar has overflow: hidden and is only 28px tall (splitpane.css:52), while the dropdown renders at position: absolute; top: 30px (splitpane.css:151) — i.e. below the bar — so it is clipped away and never visible. The click and state toggle work fine; the menu is just invisible.
Fix: render both dropdowns through a React portal to document.body with position: fixed, anchored to the trigger button's getBoundingClientRect(). This removes any dependency on parent overflow and works for both the New menu and the new Layout menu.
Control cluster (right-aligned, ~10px gaps, rounded hover pills)
Compact split-button style: clicking the main icon performs the default action; the attached caret opens a dropdown.
| Control |
Icon |
Main click |
Caret dropdown |
Hover accent |
| New |
plus inside a rounded square |
open default terminal (onNew) |
Terminal · Browser · Markdown — separator — quick-launch profiles |
green |
| Layout |
two side-by-side panes |
split right (onSplitRight) |
Split right Ctrl+D · Split down Ctrl+Shift+D |
blue |
| Close |
clean X |
close pane (onClosePane) |
— |
red |
Implementation notes
- Icons: inline stroke-based SVG, extracted into a small
icons.tsx next to SurfaceTabBar.tsx — one component per glyph: IconAdd, IconSplit, IconSplitRight, IconSplitDown, IconClose, IconCaret. Keeps SurfaceTabBar.tsx readable.
- New dropdown: keep current contents (tab types + profiles). Main
+ click keeps the instant-default-terminal fast path.
- Layout dropdown: replaces today's two separate
⏐ / ⎯ split buttons. Main icon click = split right (fast path); caret = right/down menu.
- Dropdown menus: only one open at a time; close on outside-click and Escape (existing logic preserved); show keyboard hints in the Layout menu.
- Per-tab close
× on individual tabs is unchanged. Keyboard shortcuts unchanged.
Out of scope (follow-up issue)
- Migrating from hand-rolled inline SVG to
lucide-react — to be filed as a separate issue. We intentionally start with inline SVG (no new dependency) and keep lucide as a later option.
Testing
SurfaceTabBar is presentational — add/extend a render test asserting:
- the three controls (New / Layout / Close) render;
- clicking a caret toggles its menu's visibility;
- main-icon click vs. caret-click fire different handlers (e.g.
onNew vs. opening the menu; onSplitRight vs. opening the layout menu).
Acceptance criteria
Summary
Redesign the terminal pane toolbar (the
+ ▾ ⏐ ⎯ ×controls) with real inline SVG icons and consolidate the two split buttons into a single Layout split-button with a dropdown. Also fixes a bug where the existing "new tab type" caret dropdown never appears.All of this lives in one component:
src/renderer/components/SplitPane/SurfaceTabBar.tsx(styled insrc/renderer/styles/splitpane.css).PaneWrapper.tsxalready wires up every handler needed (onNew,onNewTyped,onNewProfile,onSplitRight,onSplitDown,onClosePane), so this is a presentational redesign — no new plumbing.Bug fixed by this work
The "new tab type" caret (
▾) currently does nothing when clicked, even with profiles configured. Root cause:.surface-tab-barhasoverflow: hiddenand is only 28px tall (splitpane.css:52), while the dropdown renders atposition: absolute; top: 30px(splitpane.css:151) — i.e. below the bar — so it is clipped away and never visible. The click and state toggle work fine; the menu is just invisible.Fix: render both dropdowns through a React portal to
document.bodywithposition: fixed, anchored to the trigger button'sgetBoundingClientRect(). This removes any dependency on parentoverflowand works for both the New menu and the new Layout menu.Control cluster (right-aligned, ~10px gaps, rounded hover pills)
Compact split-button style: clicking the main icon performs the default action; the attached caret opens a dropdown.
onNew)onSplitRight)Ctrl+D· Split downCtrl+Shift+DonClosePane)Implementation notes
icons.tsxnext toSurfaceTabBar.tsx— one component per glyph:IconAdd,IconSplit,IconSplitRight,IconSplitDown,IconClose,IconCaret. KeepsSurfaceTabBar.tsxreadable.+click keeps the instant-default-terminal fast path.⏐/⎯split buttons. Main icon click = split right (fast path); caret = right/down menu.×on individual tabs is unchanged. Keyboard shortcuts unchanged.Out of scope (follow-up issue)
lucide-react— to be filed as a separate issue. We intentionally start with inline SVG (no new dependency) and keep lucide as a later option.Testing
SurfaceTabBaris presentational — add/extend a render test asserting:onNewvs. opening the menu;onSplitRightvs. opening the layout menu).Acceptance criteria
+ ▾ ⏐ ⎯ ×glyphs).