From 4f9e29e5e7619224ebe8aecb173a3e380ae4e536 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sun, 22 Mar 2026 13:29:33 -0700 Subject: [PATCH 1/2] fix(canvas): persist deletions immediately to prevent resurrection Destructive operations (forget, delete, remember) now flush to IndexedDB + localStorage immediately instead of using 2s debounce, preventing deleted items from reappearing on page reload. Co-Authored-By: Claude Opus 4.6 --- lib/community-sync.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/community-sync.ts b/lib/community-sync.ts index f83103f..44239e1 100644 --- a/lib/community-sync.ts +++ b/lib/community-sync.ts @@ -699,7 +699,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'forgotten', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -734,7 +734,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'present', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -756,7 +756,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'deleted', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -1013,6 +1013,18 @@ export class CommunitySync extends EventTarget { }, 2000); } + /** Flush doc to IndexedDB immediately (no debounce). Use for destructive ops. */ + #saveImmediate(): void { + if (!this.#offlineStore) return; + if (this.#saveDebounceTimer) { + clearTimeout(this.#saveDebounceTimer); + this.#saveDebounceTimer = null; + } + const binary = Automerge.save(this.#doc); + this.#offlineStore.saveDocImmediate(this.#communitySlug, binary); + this.#offlineStore.saveDocEmergency(this.#communitySlug, binary); + } + #persistSyncState(): void { if (!this.#offlineStore) return; From 8eb2738b657112a805bbd4bd71e53d50eddae8b4 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sun, 22 Mar 2026 13:29:39 -0700 Subject: [PATCH 2/2] refactor(shell): move history & settings icons next to space switcher Both dropdown-wrap buttons now sit in header-left directly after the space switcher, keeping space-related controls grouped together. Co-Authored-By: Claude Opus 4.6 --- server/shell.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server/shell.ts b/server/shell.ts index 469a51f..ab66d29 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -228,6 +228,14 @@ export function renderShell(opts: ShellOptions): string { ${spaceEncrypted ? '🔒' : ''} +
+ + +
+
+ + +
@@ -237,14 +245,6 @@ export function renderShell(opts: ShellOptions): string { -
- - -
-
- - -