diff --git a/src/islands/draw/Whiteboard.tsx b/src/islands/draw/Whiteboard.tsx index 21209bd..dc36fd7 100644 --- a/src/islands/draw/Whiteboard.tsx +++ b/src/islands/draw/Whiteboard.tsx @@ -29,6 +29,7 @@ const TR: Record('saved'); + const [saveState, setSaveState] = useState<'saved' | 'unsaved' | 'saving' | 'error'>('saved'); // Optionally hide the navbar (only while expanded) for maximum canvas space. const [navHidden, setNavHidden] = useState(false); @@ -138,10 +141,19 @@ export default function Whiteboard({ lang = 'en' }: { lang?: Lang }) { saving.current = true; dirty.current = false; const scene = latestScene.current; - savedKey.current = computeSceneKey(scene.elements, scene.files, sceneVersionOf.current); + const key = computeSceneKey(scene.elements, scene.files, sceneVersionOf.current); setSaveState('saving'); - await saveScene(scene); + const ok = await saveScene(scene); saving.current = false; + if (!ok) { + // The write failed — re-mark dirty so it retries, and show it honestly + // rather than a false "Saved". Do NOT advance savedKey, or the change + // would look already-saved and never retry. + dirty.current = true; + setSaveState('error'); + return; + } + savedKey.current = key; // A change may have arrived during the write; only show "Saved" if still clean. setSaveState(dirty.current ? 'unsaved' : 'saved'); }; @@ -247,7 +259,16 @@ export default function Whiteboard({ lang = 'en' }: { lang?: Lang }) { return () => { window.removeEventListener('resize', measure); header.style.display = ''; }; }, [expanded, navHidden]); - const statusIndicator = saveState === 'unsaved' ? ( + const statusIndicator = saveState === 'error' ? ( + + ) : saveState === 'unsaved' ? (