store: what belongs to one document lives in a Tile

The open node, its draft, whether it is being written and whether that is
saved, the autosave timer and its back-off, the fresh-document marker,
the board to go back to and the editor's vim mode move out of Workspace
into a Tile. The workspace holds `tiles` and `focused`, always at least
one tile, and the old names are getters on the focused tile, so the call
sites read as before. Nothing visible changes yet: there is one tile.

`flush()` writes every dirty tile, deleting, moving, renaming, sharing or
sealing a node updates every tile that shows it, and the page warns before
unloading when any tile is dirty.

The panes and the editor are handed their tile, and fill the shared hooks
only while that tile has focus; the others stand by. Vim's actions are
defined once for the page and act on the editor the key was pressed in,
rather than on whichever editor happened to be mounted last.
This commit is contained in:
nvrl committed 2026-10-20 15:22:43 +02:00
1 parent c72eccf86b
commit e0de88938a
5 files changed
+369 -265

No files matched your search

+3 -3
View File
@@ -145,7 +145,7 @@
// Guard against losing a half-written entry to a stray refresh.
$effect(() => {
if (!workspace.dirty) return
if (!workspace.tiles.some((tile) => tile.dirty)) return
const warn = (event: BeforeUnloadEvent) => event.preventDefault()
window.addEventListener('beforeunload', warn)
return () => window.removeEventListener('beforeunload', warn)
@@ -851,9 +851,9 @@
onpointerdown={() => workspace.open && (workspace.pane = 'document')}
>
{#if workspace.open?.kind === 'file'}
<FilePane />
<FilePane tile={workspace.tile} />
{:else if workspace.open}
<DocumentPane />
<DocumentPane tile={workspace.tile} />
{:else}
<div class="placeholder">
<div class="standby resolve">