From 3fef52cbdb7c2a459a01535b955516a989aaff8e Mon Sep 17 00:00:00 2001 From: Guilhem Lemouel Date: Thu, 21 May 2026 00:08:40 +0200 Subject: [PATCH] refactor(raw_apps): per-pane tab bars with mirrored single-mode lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the single tab bar above the inner Splitpanes with one DraggableTabs per pane. Splitter now goes floor-to-ceiling through tabs AND content in split mode. In single mode both bars mirror the full tab list, so the visible pane always carries every tab — fixes the bug where activating Preview hid the tab strip. Clicking Preview while in split mode is a no-op (Preview is permanently visible in the right pane). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/raw_apps/RawAppEditor.svelte | 176 ++++++++++-------- 1 file changed, 99 insertions(+), 77 deletions(-) diff --git a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte index fd58ca4330..af18167f7e 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte @@ -213,13 +213,23 @@ ? 'file' : 'runnable' ) - // When split is on, the Preview tab moves out of the bar and lives in - // the right pane. The user only sees file/runnable tabs in the bar; - // the right pane is always preview. When split is off, the Preview - // tab is back in the bar like any other tab. - const displayedTabs = $derived( + // Per-pane tab lists. + // - Single mode: BOTH panes mirror the FULL tab list — whichever pane is + // visible (paneA when source is active, paneB when preview is active) + // carries every tab so the user can always switch. This is the fix + // for the bug where activating Preview hid every tab. + // - Split mode: each pane shows its own subset (VS Code-style): + // left = file/runnable tabs, right = just the Preview pseudo-header. + const leftPaneTabs = $derived( splitWithPreview ? tabs.filter((t) => t.id !== PREVIEW_TAB_ID) : tabs ) + const rightPaneTabs = $derived( + splitWithPreview ? tabs.filter((t) => t.id === PREVIEW_TAB_ID) : tabs + ) + // In split mode the Preview tab is permanently visible in the right pane; + // the right bar always shows it as the active tab regardless of which + // file/runnable tab is logically active in the left pane. + const rightPaneActiveId = $derived(splitWithPreview ? PREVIEW_TAB_ID : activeTabId) const showSource = $derived(activeTabKind === 'file') const showRunnable = $derived(activeTabKind === 'runnable') @@ -274,6 +284,11 @@ function activateTab(id: string) { const tab = tabs.find((t) => t.id === id) if (!tab) return + // Clicking the Preview tab while in split mode is a visual no-op — + // Preview is already permanently shown in the right pane, and + // promoting it to active would trigger the pane-sizing $effect and + // collapse the left pane (the bug being fixed here). + if (splitWithPreview && id === PREVIEW_TAB_ID) return activeTabId = id if (tab.id === PREVIEW_TAB_ID) { selectedRunnable = undefined @@ -1330,56 +1345,49 @@ {/if} -
- - activateTab(id)} - onClose={(id) => closeTab(id)} - onReorder={(next) => reorderTabs(next)} - > - {#snippet trailing()} -
- -
- {/snippet} -
- -
- - -
+ {#snippet trailing()} +
+ +
+ {/snippet} + +
- - -
-
-
- Preview -
-
+
+ + +
+ activateTab(id)} + onClose={(id) => closeTab(id)} + onReorder={(next) => reorderTabs(next)} + > + {#snippet trailing()} +
+
-
- -
- - -
+ {/snippet} + + +
+
+