diff options
| author | Adam Malczewski <[email protected]> | 2026-06-27 02:17:24 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-27 02:17:24 +0900 |
| commit | 0e0601817712033b3247695646acd22d6496330a (patch) | |
| tree | 87af231c6b97b0cdca87820f25522e9885b5791c /src/app | |
| parent | 2fa03f8d7410c2b8d6be8e10ad088863e83d7177 (diff) | |
| download | dispatch-web-0e0601817712033b3247695646acd22d6496330a.tar.gz dispatch-web-0e0601817712033b3247695646acd22d6496330a.zip | |
feat(sidebar-tabs): move tab bar from top into sidebar as vertical list
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/App.svelte | 44 |
1 files changed, 26 insertions, 18 deletions
diff --git a/src/app/App.svelte b/src/app/App.svelte index 09be947..9a17999 100644 --- a/src/app/App.svelte +++ b/src/app/App.svelte @@ -40,7 +40,7 @@ import { parseMessageQueuePayload } from "../features/surface-host/logic/message-queue"; import { parseTodoPayload } from "../features/surface-host/logic/todo"; import TodoList from "../features/surface-host/ui/TodoList.svelte"; - import { manifest as tabsManifest, TabBar } from "../features/tabs"; + import { manifest as tabsManifest, TabList } from "../features/tabs"; import { manifest as viewsManifest, ViewSidebar } from "../features/views"; import { CwdField, @@ -99,6 +99,7 @@ // The view kinds offered in the sidebar's dropdown. Generic data — the // `viewContent` snippet below maps each kind id to its renderer. const viewKinds = [ + { id: "tabs", label: "Tabs" }, { id: "model", label: "Model" }, { id: "lsp", label: "Language Servers" }, { id: "mcp", label: "MCP Servers" }, @@ -111,8 +112,9 @@ { id: "settings", label: "Settings" }, ] as const; - // Default sidebar layout: just the Model view. - const DEFAULT_VIEWS: readonly string[] = ["model"]; + // Default sidebar layout: the Tabs list (the moved-from-top tab bar) plus the + // Model view, so a fresh user sees their conversations + model controls. + const DEFAULT_VIEWS: readonly string[] = ["tabs", "model"]; const sidebarStore = createLocalStore<readonly string[]>("dispatch.sidebar.views", { storage: untrack(() => store.storage), }); @@ -416,21 +418,12 @@ <main class="relative flex h-screen overflow-hidden"> <!-- LEFT: everything except the sidebar. The full-height sidebar is a sibling - (below), so opening it shrinks this ENTIRE column — tab row included, which - slides the hamburger left. --> + (below), so opening it shrinks this ENTIRE column. --> <div class="flex min-w-0 flex-1 flex-col overflow-hidden pt-[5px]"> - <!-- Tab row: the tab strip fills + scrolls internally (flex-1 min-w-0), with - a permanently seated hamburger pinned to the far right. --> - <div class="flex min-w-0 items-center"> - <TabBar - tabs={store.tabs} - activeConversationId={store.activeConversationId} - statusFor={(id) => store.conversationStatus(id)} - onSelect={(id) => store.selectTab(id)} - onClose={(id) => store.closeTab(id)} - onNewDraft={() => store.newDraft()} - onRename={(id, title) => store.renameTab(id, title)} - /> + <!-- Slim header: the tab bar moved into the sidebar (the "Tabs" view), so + the top row now holds only the build version + the sidebar toggle, + right-aligned. --> + <div class="flex items-center justify-end px-1"> <span class="shrink-0 select-none px-1 font-mono text-[10px] leading-none text-base-content/30" title="Build version (git short hash)" @@ -585,7 +578,22 @@ {/if} {#snippet viewContent(kind: string)} - {#if kind === "model"} + {#if kind === "tabs"} + <!-- The conversation tab list (moved out of the top bar into the sidebar). + Re-mount per workspace so the filtered tab set + scroll reset cleanly + on a workspace switch. --> + {#key store.activeWorkspaceId} + <TabList + tabs={store.tabs} + activeConversationId={store.activeConversationId} + statusFor={(id) => store.conversationStatus(id)} + onSelect={(id) => store.selectTab(id)} + onClose={(id) => store.closeTab(id)} + onNewDraft={() => store.newDraft()} + onRename={(id, title) => store.renameTab(id, title)} + /> + {/key} + {:else if kind === "model"} <div class="flex flex-col gap-3"> <ModelSelector models={store.models} selected={store.activeModel} onSelect={handleSelectModel} /> <!-- Keyed on the workspace conversation (active tab OR draft) so the inputs |
