Repository navigation
Mundus v0.7.96
Mundus v0.7.96 — Bugfixing Release
Fixes (5)
1. Modern dialogs (no more native boxes)
- NEW src/components/ConfirmDialog.tsx: promise-based in-app confirm host
(showConfirmDialog({title, message, detail, confirmLabel, tone/danger}) → Promise).
Styled like the rest of the app (rounded-2xl, border, backdrop blur, dark-mode aware,
danger=red / warning=amber / info=accent), Enter confirms, Esc + backdrop click cancel,
auto-focused confirm button, one-dialog-at-a-time. ConfirmDialogHost is mounted in BOTH
app branches (Atlas + writing). - Replaced window.confirm for snapshot restore (App.tsx handleRestoreBackupSnapshot,
now async) and for "Clear custom Firebase settings" (FirebaseConfigModal). - Replaced alert() for Firebase validation (inline red banner inside the modal instead of
a blocking box) and for "+ Dictionary" in TextEditor (transient green "Added …" chip that
outlives the button, which unmounts once the word joins the dictionary). - Bonus fix (latent React crash): FirebaseConfigModal returned null for closed state
before its useState calls — hook count changed between renders. Hooks now run
unconditionally; the form re-seeds via useEffect on open. - Swept the whole bundle: zero window.confirm/app-level alert( remain (the only alert(
strings in the bundle are inside the third-party libwebp decoder).
2. Duplicate shortcut warning
- src/lib/shortcutManager.ts: new bindingsEqual() + findBindingConflicts(bindings, excludeId, binding).
- Settings → Keyboard Shortcuts:
- Recording a combo that another action already uses shows an amber "Duplicate shortcut"
banner (naming the conflicting action(s), auto-dismiss 8s, manual dismiss). - Persistent badges: any action whose combo is shared shows an amber chip + warning icon
- "dup" tag until resolved; Reset Defaults clears everything.
- Esc now cancels recording instead of binding Escape as a shortcut.
- Shortcut groups lifted to module scope (KEYBINDING_GROUPS/KEYBINDING_LABELS) so the
warning can name actions.
- Recording a combo that another action already uses shows an amber "Duplicate shortcut"
3. Settings submenus from the Atlas
- Root cause: FirebaseConfigModal was rendered only in the writing-mode return. The Atlas
is an early return, so "Configure Firebase" set the open state with no modal in the Atlas tree;
it appeared only after opening a world. - Fix: extracted firebaseConfigModalElement and rendered it in both branches (same pattern
the settings modal already used since v0.7.91). Verified E2E: Settings → Configure Firebase
opens instantly on the Atlas.
4. Story Flow Graph layout survives backups
- Root cause: the graph's layout (placed scene ids + x/y) lived only in localStorage
(mundus_story_flow_nodes_ / mundus_story_flow_positions_). Backups carried story
links but never the layout, so restoring on a fresh install/other device dropped every scene
into default stacked positions; imports that renamed colliding ids also detached stored layouts. - NEW src/lib/storyFlowLayout.ts: readStoryFlowLayout, writeStoryFlowLayout,
normalizeStoryFlowLayout (untrusted payloads), remapStoryFlowLayout (collision renames),
mergeStoryFlowLayouts (backup wins for shared ids; local-only placed scenes kept — matches
merge-import semantics), clearStoryFlowLayout, key helpers. - Backup payloads now carry layouts (storyFlowLayouts per-world map in app-wide backups +
snapshots; storyFlowLayout in per-Mundus backups):- backupEngine.ts: ProjectBackupData, MundusBackupFile, export/build/parse for all three
payload types extended (old backups without layouts restore harmlessly). - App.tsx: manual app-wide export, per-Mundus export, scheduled auto-download, and all three
snapshot call sites (initial/timer/instant) capture layouts; app-wide import, snapshot
restore, and Atlas import write them back (Atlas import remaps ids through the same rename
table as items, then merges over the existing layout).
- backupEngine.ts: ProjectBackupData, MundusBackupFile, export/build/parse for all three
- Deleting a world now also clears its two layout keys (v0.7.95 had cleaned map data; layouts
were missed).
5. App-blanking crash (fixed)
- TextEditor's status bar rendered document.wordCount.toLocaleString() /
document.characterCount.toLocaleString() unguarded. A backup JSON missing characterCount
(hand-edited/third-party imports) crashed React with no error boundary → blank screen on
opening the world. - Fixed both ends: all five stat render sites guarded with || 0, StartMenu doc-row guarded,
and applyMundusImport now derives missing wordCount/characterCount from plainText on
the way in. E2E: the previously app-killing backup now imports and opens cleanly
("12 words · 13 chars" shown).
Files changed / added
New: src/components/ConfirmDialog.tsx, src/lib/storyFlowLayout.ts, scripts/test_v096_helpers.ts
Modified: src/App.tsx, src/components/SettingsModal.tsx, src/components/FirebaseConfigModal.tsx,
src/components/TextEditor.tsx, src/components/StartMenu.tsx, src/lib/backupEngine.ts,
src/lib/shortcutManager.ts, + the 6 version files.