summaryrefslogtreecommitdiffhomepage
path: root/src/app/App.svelte
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-09-05 01:20:28 +0900
committerAdam Malczewski <[email protected]>2026-09-05 01:20:28 +0900
commit985116fdc8961e656cd9d3027debcd1a6237d6c2 (patch)
tree43aed23977ea354d23d8c54f27d45bf5e0635dfc /src/app/App.svelte
parenta104c094b588560f955ff52dc7f949cf3c355f94 (diff)
downloaddispatch-web-985116fdc8961e656cd9d3027debcd1a6237d6c2.tar.gz
dispatch-web-985116fdc8961e656cd9d3027debcd1a6237d6c2.zip
feat(layout): plan 02 — provider consumption + layout WS + localStorage migration
Diffstat (limited to 'src/app/App.svelte')
-rw-r--r--src/app/App.svelte39
1 files changed, 11 insertions, 28 deletions
diff --git a/src/app/App.svelte b/src/app/App.svelte
index b7eb783..9eaba9c 100644
--- a/src/app/App.svelte
+++ b/src/app/App.svelte
@@ -10,18 +10,10 @@
<script lang="ts">
import type { LayoutTree } from "@dispatch/layout-contract";
import { untrack } from "svelte";
- import { createLocalStore } from "../adapters/local-storage";
- import {
- createCollapseStore,
- firstCollapsibleNodeId,
- firstPanelsNode,
- listPanelViews,
- TileRoot,
- } from "../features/layout";
+ import { createCollapseStore, firstCollapsibleNodeId, TileRoot } from "../features/layout";
import { RunModal, type HeartbeatRunView } from "../features/heartbeat";
import { SystemPromptBuilder } from "../features/system-prompt";
import type { AppStore } from "./store.svelte";
- import { seedLayout } from "../features/layout";
import type { AppViewPorts, ChatViewportBridge } from "./view-ports";
import ErrorModal from "./ErrorModal.svelte";
@@ -33,27 +25,18 @@
// closed). Holds a snapshot run view; the modal re-mounts per run (keyed).
let heartbeatRun = $state<HeartbeatRunView | null>(null);
- // --- The layout tree: seeded from DEFAULT_LAYOUT (the compatibility tree
- // that reproduces today's layout) with the sidebar selection overlaid from
- // localStorage — today's exact boot behavior (unknown/removed kinds dropped;
- // nothing valid stored → the tabs+model defaults).
- const sidebarStore = createLocalStore<readonly string[]>("dispatch.sidebar.views", {
- storage: untrack(() => store.storage),
- });
- let tree = $state<LayoutTree>(
- seedLayout(sidebarStore.load(), listPanelViews().map((v) => v.id)),
- );
+ // --- The layout tree (plan 02): the ACTIVE workspace's tile tree, served
+ // by the backend's layout provider plugin when one is active (probed on
+ // boot, on workspace switch, and on extensions-changed; `layout` WS pushes
+ // re-render live) and the built-in DEFAULT_LAYOUT otherwise (no-provider
+ // mode: edits are ephemeral, logged once, no error UI). The store owns the
+ // whole lifecycle; the shell just renders `tree` and forwards edits.
+ // `dispatch.sidebar.views` is RETIRED (D-L4): its only reader is the store's
+ // one-way §2.7 migration.
+ const tree = $derived(store.layout.tree);
- // Tile edits flow up from the panels; the OWNER decides persistence. The
- // panels selection is written back to the SAME key in the SAME format
- // (`dispatch.sidebar.views` — a JSON array of view ids) so the storage stays
- // byte-compatible with today (plan 02 migrates it).
function handleTreeChange(next: LayoutTree): void {
- tree = next;
- const panels = firstPanelsNode(next);
- if (panels !== null) {
- sidebarStore.save(panels.node.panels.map((p) => p.view));
- }
+ store.layout.onTreeChange(next);
}
// --- Sidebar collapse: renderer chrome state (per-node-id open/closed),