diff --git a/web/src/main.ts b/web/src/main.ts index 6169a9a..3184763 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -88,7 +88,7 @@ sidebar.el.addEventListener("click", (e) => { }); shellEl.append(sidebar.el, content, backdrop); -root.replaceChildren(renderTopbar(store), shellEl); +root.replaceChildren(renderTopbar(store, toggleDrawer), shellEl); // The pool owns attach connections independently of the route: navigating away // parks a session (keeps it streaming); navigating back re-mounts it instantly. @@ -188,7 +188,6 @@ mv = createMultiView({ onDisconnect: closePane, renderWelcome, onLayoutChange: scheduleSave, - onToggleSidebar: toggleDrawer, }); let contentShowsMv = false; function showMultiView(): void { diff --git a/web/src/multiview.ts b/web/src/multiview.ts index ff9cdeb..4bc014d 100644 --- a/web/src/multiview.ts +++ b/web/src/multiview.ts @@ -36,8 +36,6 @@ export interface MultiViewOptions { /** Called after any layout change (structure, focus, or divider resize) so the * shell can persist it (issue #34). */ onLayoutChange?: () => void; - /** Toggle the mobile sidebar drawer (the ☰ button in the tab bar, issue #35). */ - onToggleSidebar?: () => void; } export interface MultiView { @@ -251,14 +249,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { function renderTabs(): void { tabBar.replaceChildren(); - // Mobile-only ☰ to open the sidebar drawer (CSS hides it on desktop). - const menu = document.createElement("button"); - menu.type = "button"; - menu.className = "mv-mobile-menu"; - menu.title = "Sessions"; - menu.textContent = "☰"; - menu.addEventListener("click", () => opts.onToggleSidebar?.()); - tabBar.appendChild(menu); for (const t of layout.tabs) { const tab = document.createElement("button"); tab.type = "button"; @@ -338,18 +328,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { render(); } - // The floating ☰ that stands in for the collapsed tab bar on mobile (single - // tab), keeping the sidebar drawer reachable from the welcome + pane views. - function makeMobileFab(): HTMLButtonElement { - const fab = document.createElement("button"); - fab.type = "button"; - fab.className = "mv-mobile-fab"; - fab.title = "Sessions"; - fab.textContent = "☰"; - fab.addEventListener("click", () => opts.onToggleSidebar?.()); - return fab; - } - // ---- top-level render ---- function render(): void { @@ -363,7 +341,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { if (!tab.root) { pool.setVisible([]); pool.setFocus(null); - if (isMobile && layout.tabs.length === 1) canvas.appendChild(makeMobileFab()); canvas.appendChild(renderWelcome()); sidebar.setHighlights({ open: openSessions(layout), focused: null, colors: colorMap() }); persist(); @@ -396,10 +373,6 @@ export function createMultiView(opts: MultiViewOptions): MultiView { const wrap = document.createElement("div"); wrap.className = "mv-mobile"; - // With a single tab the tab bar (and its ☰) is hidden — float a ☰ so the - // sidebar drawer stays reachable. - if (layout.tabs.length === 1) wrap.appendChild(makeMobileFab()); - if (ls.length > 1) { const bar = document.createElement("div"); bar.className = "mv-panebar"; diff --git a/web/src/styles.css b/web/src/styles.css index 23fb99d..45e97f5 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -378,6 +378,25 @@ textarea { backdrop-filter: blur(8px); } +/* Hamburger to the left of the brand — toggles the off-canvas session drawer. + Mobile only (desktop keeps the sidebar permanently in view). */ +.app-menu { + display: none; + place-items: center; + flex: none; + width: 32px; + height: 32px; + border: none; + border-radius: var(--r-1); + background: transparent; + color: var(--ink); + font-size: var(--fs-17); + cursor: pointer; +} +.app-menu:hover { + background: var(--surface-2); +} + /* Three-part header: brand (left), status (centered), actions (right). Equal flex on the outer two keeps the status group truly centered. */ .app-header .brand { @@ -765,15 +784,6 @@ textarea { color: var(--faint); } -.folder-count { - font-size: var(--fs-11); - color: var(--muted); - padding: 1px 8px; - border-radius: var(--r-pill); - background: var(--surface-2); - border: 1px solid var(--border); -} - .tree-leaf { display: flex; align-items: center; @@ -2234,9 +2244,6 @@ textarea { multi-view mobile (#35): below 860px the split tree projects to a pill strip with one pane visible; the sidebar becomes an off-canvas drawer (☰). ========================================================================= */ -.mv-mobile-menu { - display: none; /* desktop: hidden — the sidebar is always present */ -} .mv-backdrop { display: none; } @@ -2256,29 +2263,6 @@ textarea { border-radius: 0; box-shadow: none; } -/* Floating ☰ that replaces the collapsed tab bar, tucked into the header bar. */ -.mv-mobile-fab { - position: absolute; - top: 0; - left: 0; - z-index: var(--z-sticky); - display: inline-grid; - place-items: center; - width: 34px; - height: var(--bar-h); - border: none; - background: transparent; - color: var(--ink); - font-size: var(--fs-15); - cursor: pointer; -} -/* Make room for the ☰: shift the title (single pane) or pad the pill strip. */ -.mv-mobile-fab + .mv-pane .attach-title { - margin-left: 30px; -} -.mv-mobile-fab + .mv-panebar { - padding-left: 38px; -} .mv-panebar { display: flex; gap: 4px; @@ -2319,24 +2303,8 @@ textarea { } @media (max-width: 859px) { - /* ☰ lives in the tab bar */ - .mv-mobile-menu { + .app-menu { display: inline-grid; - place-items: center; - align-self: center; - width: 28px; - height: 28px; - margin-right: var(--sp-1); - border: none; - border-radius: var(--r-1); - background: transparent; - color: var(--ink); - font-size: var(--fs-15); - cursor: pointer; - flex: none; - } - .mv-mobile-menu:hover { - background: var(--surface-2); } /* sidebar → off-canvas drawer (override the route-based show/hide) */