Save downloads dashboard.json, Load opens a file picker and imports
through apply_import with errors reported in the modal, Clear asks for
confirmation then wipes to Dashboard::blank(). App provides the store
and ModalState and mounts the modal; init_hydrated starts autosave.
ModalState carries title/message/action as RwSignals; the action is
read at click time so a late confirm wins. Overlay click and Cancel
close; the confirm button runs the stored action. Edition-2024 note:
method calls on non-Copy captures move by value inside nested move
closures, so handlers touch state.open/state.action fields directly.
- STORAGE_KEY aex.dashboard, 500 ms debounced autosave via store.track()
- deferred load after hydration keeps SSR markup authoritative
- parse_dashboard version-checks the file (the migration hook), errors
are RU messages via ImportError (thiserror)
- clear writes the blank dashboard back so a reload stays blank
- export_download builds a Blob URL and revokes it after the click
- 5 unit tests: round trip, blank, garbage, newer and older versions
Store and serde derives coexist on all 23 dashboard types (prototype
confirmed). Settings carries the saved-format version (1) as the
migration hook anchor; Dashboard::blank() is the post-Clear empty
campaign. mock() now builds Settings via Default.
Remove unused imports (nav, sidebar, state, mock, inventory, item,
numput), the unused qty closure, the unused #![feature] gate, and a
module-scoped allow(dead_code) for the unmounted search stubs.
lazy_static removed from Cargo.toml (the only dependency removal for
now, per decision). ITEMS_REFS/ITEMS_NAMES are now LazyLock statics; the
duplicate foundry.json load is dropped and the no-op HashMap roundtrip
is gone. Cargo.lock is now tracked: the app is a binary and builds
should be reproducible.
Doc comments on all modules, components, entities, helpers and type
aliases; larger comments on the important entities (Dashboard, PlayerData,
Context, App, Numput, item data). No behavior changes.