From a94051a995871aedafcf7ed36a62af56eafd15f0 Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Fri, 20 Mar 2026 20:01:35 -0700 Subject: [PATCH] fix: add split pane button to tab bar for discoverability (#135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add split pane button to tab bar for discoverability The split pane feature was only accessible via right-click context menu or Ctrl+\ keyboard shortcut. Add a subtle split icon (⧉) to the tab bar that appears at low opacity in single-pane mode. Hidden in multi-pane mode where pane headers already provide split/close controls. * fix: address review — change tab-bar from tablist to toolbar role The tab bar contains both tabs and action buttons (new workstream, split pane), which is invalid for role=tablist. Change to role=toolbar which correctly describes a container of mixed interactive controls. * fix: address design review — WCAG contrast, ARIA structure, mobile - Drop opacity approach, use border: dashed var(--border) matching #new-tab-btn pattern (fixes WCAG contrast failure at 35% opacity) - Nest tabs in #tab-list[role=tablist] inside toolbar (fixes invalid role=tab children inside role=toolbar) - Hide split button on mobile (<600px) where splits can't work - Add aria-keyshortcuts to both action buttons --- turnstone/ui/static/app.js | 18 ++++++++++++++++-- turnstone/ui/static/index.html | 6 ++++-- turnstone/ui/static/style.css | 24 +++++++++++++++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/turnstone/ui/static/app.js b/turnstone/ui/static/app.js index 8f3daffd..6b26cb37 100644 --- a/turnstone/ui/static/app.js +++ b/turnstone/ui/static/app.js @@ -1112,6 +1112,19 @@ function updatePaneHeaders() { } else { root.classList.remove("multi-pane"); } + // Hide tab-bar split button when already in multi-pane mode + var splitBtn = document.getElementById("split-btn"); + if (splitBtn) { + if (leafCount > 1) { + splitBtn.classList.add("hidden"); + } else { + splitBtn.classList.remove("hidden"); + } + } +} + +function splitFocusedPane() { + if (focusedPaneId) splitPane(focusedPaneId, "horizontal"); } // --- Tree helpers --- @@ -1860,10 +1873,11 @@ document // =========================================================================== var tabBar = document.getElementById("tab-bar"); +var tabList = document.getElementById("tab-list"); var newTabBtn = document.getElementById("new-tab-btn"); function renderTabBar() { - tabBar.querySelectorAll(".ws-tab").forEach(function (t) { + tabList.querySelectorAll(".ws-tab").forEach(function (t) { t.remove(); }); @@ -1910,7 +1924,7 @@ function renderTabBar() { tab.appendChild(close); } - tabBar.insertBefore(tab, newTabBtn); + tabList.appendChild(tab); }); } diff --git a/turnstone/ui/static/index.html b/turnstone/ui/static/index.html index 460a3dc5..570dd5a9 100644 --- a/turnstone/ui/static/index.html +++ b/turnstone/ui/static/index.html @@ -35,8 +35,10 @@ -
- +