diff options
| author | Adam Malczewski <[email protected]> | 2026-09-05 00:34:45 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-09-05 00:34:45 +0900 |
| commit | a104c094b588560f955ff52dc7f949cf3c355f94 (patch) | |
| tree | 61983d5568f47fd23739705aaec815be1336b595 /src/features/layout/logic/panels-edit.ts | |
| parent | 60a726883be85c174e88ae832ef95f3c0f084ec9 (diff) | |
| download | dispatch-web-a104c094b588560f955ff52dc7f949cf3c355f94.tar.gz dispatch-web-a104c094b588560f955ff52dc7f949cf3c355f94.zip | |
feat(layout): plan 01 — tile engine + view registry
Diffstat (limited to 'src/features/layout/logic/panels-edit.ts')
| -rw-r--r-- | src/features/layout/logic/panels-edit.ts | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/features/layout/logic/panels-edit.ts b/src/features/layout/logic/panels-edit.ts new file mode 100644 index 0000000..8a56859 --- /dev/null +++ b/src/features/layout/logic/panels-edit.ts @@ -0,0 +1,33 @@ +/** + * Panel-edit → tree-op mapping: the pure decision logic behind TilePanels' + * dropdown swap / add / remove buttons. The component builds the ops; the + * renderer's owner (TileRoot → onTreeChange) applies them. Zero Svelte, zero + * DOM. + */ + +import type { LayoutOp, Path } from "@dispatch/layout-contract"; + +/** Swap the view a panel leaf mounts (panel `index` of the panels node at `path`). */ +export function swapPanelOp(path: Path, index: number, view: string): LayoutOp { + return { type: "replaceView", target: [...path, index], view }; +} + +/** Add a panel mounting `view` (appended to the panels node at `path`). */ +export function addPanelOp(path: Path, view: string): LayoutOp { + return { type: "insertPanel", panels: path, view }; +} + +/** Remove the panel at `index` from the panels node at `path`. */ +export function removePanelOp(path: Path, index: number): LayoutOp { + return { type: "removeNode", target: [...path, index] }; +} + +/** + * The view a new panel starts with. The tree schema has no "empty panel" + * state (a leaf's `view` is required — today's "Select a view" placeholder has + * no tree representation), so the + button pre-selects the first panel-eligible + * view. Returns null when nothing is eligible (the + button hides). + */ +export function firstPanelView(views: readonly { readonly id: string }[]): string | null { + return views[0]?.id ?? null; +} |
