From dfbf45f8a495f6da9d8c37dcf58aec5bcddfda22 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 7 Oct 2025 11:55:51 -0700 Subject: [PATCH] refactor(admin): migrate ProjectForm to runes-based autosave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update ProjectForm to use new createAutoSaveStore with Svelte 5 runes - Fix $derived syntax in AutoSaveStatus (use $derived.by for multi-statement) - Add hasLoaded flag to prevent infinite loop on autosave completion - Move draft recovery from inline header to prominent banner below header - Style draft banner with blue info colors and slide-down animation - Fix draft persistence by clearing localStorage on restore/dismiss - Call beforeNavigate at top level for proper Svelte 5 lifecycle - Add keyboard shortcut (Cmd/Ctrl+S) and navigation guard effects - Update AutoSaveStatus to support both old stores and new reactive props 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/admin/AutoSaveStatus.svelte | 20 ++- src/lib/components/admin/ProjectForm.svelte | 168 +++++++++++++++--- 2 files changed, 156 insertions(+), 32 deletions(-) diff --git a/src/lib/components/admin/AutoSaveStatus.svelte b/src/lib/components/admin/AutoSaveStatus.svelte index adf48eb..4651012 100644 --- a/src/lib/components/admin/AutoSaveStatus.svelte +++ b/src/lib/components/admin/AutoSaveStatus.svelte @@ -2,16 +2,30 @@ import type { AutoSaveStatus } from '$lib/admin/autoSave' interface Props { - statusStore: { subscribe: (run: (v: AutoSaveStatus) => void) => () => void } + statusStore?: { subscribe: (run: (v: AutoSaveStatus) => void) => () => void } errorStore?: { subscribe: (run: (v: string | null) => void) => () => void } + status?: AutoSaveStatus + error?: string | null compact?: boolean } - let { statusStore, errorStore, compact = true }: Props = $props() + let { statusStore, errorStore, status: statusProp, error: errorProp, compact = true }: Props = $props() + + // Support both old subscription-based stores and new reactive values let status = $state('idle') let errorText = $state(null) $effect(() => { + // If using direct props (new runes-based store) + if (statusProp !== undefined) { + status = statusProp + errorText = errorProp ?? null + return + } + + // Otherwise use subscriptions (old store) + if (!statusStore) return + const unsub = statusStore.subscribe((v) => (status = v)) let unsubErr: (() => void) | null = null if (errorStore) unsubErr = errorStore.subscribe((v) => (errorText = v)) @@ -21,7 +35,7 @@ } }) - const label = $derived(() => { + const label = $derived.by(() => { switch (status) { case 'saving': return 'Saving…' diff --git a/src/lib/components/admin/ProjectForm.svelte b/src/lib/components/admin/ProjectForm.svelte index d7f70ed..a3b9220 100644 --- a/src/lib/components/admin/ProjectForm.svelte +++ b/src/lib/components/admin/ProjectForm.svelte @@ -1,5 +1,5 @@