fix(rdocs): persist demo notebook state in localStorage

Demo mode edits were lost on page reload — now debounce-saved to
localStorage and restored on next visit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-13 13:26:11 -04:00
parent 432a3597de
commit 4d5c394e9e
1 changed files with 43 additions and 0 deletions

View File

@ -319,7 +319,46 @@ class FolkDocsApp extends HTMLElement {
// ── Demo data ── // ── Demo data ──
private static readonly DEMO_STORAGE_KEY = 'rdocs_demo_data';
private _demoSaveTimer: ReturnType<typeof setTimeout> | null = null;
/** Debounce-save demo notebooks to localStorage (500ms). */
private saveDemoState() {
if (this._demoSaveTimer) clearTimeout(this._demoSaveTimer);
this._demoSaveTimer = setTimeout(() => {
try {
const serializable = this.demoNotebooks.map(nb => ({
id: nb.id, title: nb.title, description: nb.description,
cover_color: nb.cover_color, note_count: nb.note_count,
updated_at: nb.updated_at, notes: nb.notes,
}));
localStorage.setItem(FolkDocsApp.DEMO_STORAGE_KEY, JSON.stringify(serializable));
} catch { /* localStorage full or unavailable */ }
}, 500);
}
private loadDemoData() { private loadDemoData() {
// Try restoring from localStorage first
try {
const saved = localStorage.getItem(FolkDocsApp.DEMO_STORAGE_KEY);
if (saved) {
const parsed = JSON.parse(saved);
if (Array.isArray(parsed) && parsed.length > 0) {
this.demoNotebooks = parsed;
this.notebooks = this.demoNotebooks.map(({ notes, ...nb }: any) => nb as Notebook);
for (const nb of this.demoNotebooks) {
this.notebookNotes.set(nb.id, nb.notes);
}
if (this.demoNotebooks.length > 0) {
this.expandedNotebooks.add(this.demoNotebooks[0].id);
}
this.loading = false;
this.render();
return;
}
}
} catch { /* corrupt data — fall through to defaults */ }
const now = Date.now(); const now = Date.now();
const hour = 3600000; const hour = 3600000;
const day = 86400000; const day = 86400000;
@ -483,6 +522,7 @@ Gear: EUR 400 (10%)</code></pre><p><em>Maya is tracking expenses in rF
} }
this.loading = false; this.loading = false;
this.render(); this.render();
this.saveDemoState(); // persist initial state
} }
private demoSearchNotes(query: string) { private demoSearchNotes(query: string) {
@ -549,6 +589,7 @@ Gear: EUR 400 (10%)</code></pre><p><em>Maya is tracking expenses in rF
this.renderNav(); this.renderNav();
this.renderMeta(); this.renderMeta();
this.mountEditor(newNote); this.mountEditor(newNote);
this.saveDemoState();
} }
private demoCreateNote(opts: CreateNoteOpts = {}) { private demoCreateNote(opts: CreateNoteOpts = {}) {
@ -584,6 +625,7 @@ Gear: EUR 400 (10%)</code></pre><p><em>Maya is tracking expenses in rF
this.renderNav(); this.renderNav();
this.renderMeta(); this.renderMeta();
this.mountEditor(newNote); this.mountEditor(newNote);
this.saveDemoState();
} }
// ── Mobile stack navigation ── // ── Mobile stack navigation ──
@ -3520,6 +3562,7 @@ Gear: EUR 400 (10%)</code></pre><p><em>Maya is tracking expenses in rF
note.updated_at = new Date().toISOString(); note.updated_at = new Date().toISOString();
} }
} }
this.saveDemoState();
} }
// ── Import/Export Dialog ── // ── Import/Export Dialog ──