docs: mark Phase 1.5 done; sync architecture, modernize, readme

- ROADMAP: all Phase 1.5 boxes checked; done-notes (clone snapshots,
  Copy handle, no Instant on wasm, button enables with the pending burst)
- ARCHITECTURE: undo/redo in the header tree and a paragraph on the
  snapshot history; gaps list no longer mentions undo
- README: undo/redo in 'What works today'
This commit is contained in:
yaroslav k 2026-08-16 12:32:25 +03:00
parent ff5ec498b2
commit bb304bed6a
3 changed files with 26 additions and 10 deletions

View File

@ -100,8 +100,8 @@ JSON as-is.
## Component tree ## Component tree
App App
├─ Header name, image, date steppers, session steppers, │ Save (download)/Load (file import)/Clear (wipe),
Save (download)/Load (file import)/Clear (wipe) ↩ Undo/redo (buttons + Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y)
├─ Modal overlay dialog: confirm (action) or error (close) ├─ Modal overlay dialog: confirm (action) or error (close)
├─ Sidebar ├─ Sidebar
│ ├─ Image portrait │ ├─ Image portrait
@ -133,6 +133,13 @@ then a debounced (500 ms) effect writes on any store change via
`Settings::VERSION` (the migration hook). `ModalState` holds title/message/ `Settings::VERSION` (the migration hook). `ModalState` holds title/message/
action as signals; the confirm button reads the action at click time. action as signals; the confirm button reads the action at click time.
Undo/redo lives in `state::undo`: the same store trigger feeds a
snapshot history (`HistoryHandle` in context). The first change of a
burst is remembered; when the burst goes quiet for 1 s, the pre-burst
state becomes an undo step. Undo/redo restore via `replace_state`
the autosave effect persists the undone state too. Clear and import
push a snapshot first, so they are undoable themselves.
`Numput` is the shared numeric input: `+n`/`-n` adjust relative to the `Numput` is the shared numeric input: `+n`/`-n` adjust relative to the
current value, a plain number sets absolutely, invalid input is reverted, current value, a plain number sets absolutely, invalid input is reverted,
and the value renders with thousands separators. `NumputChange` is the same and the value renders with thousands separators. `NumputChange` is the same
@ -157,8 +164,6 @@ currently mounted on any page.
## Current gaps ## Current gaps
- Quests, notes, contacts: models and mock data only - Quests, notes, contacts: models and mock data only
- No undo/redo (planned as Phase 1.5; snapshot-based, rides on the
persist machinery)
- `Character` and `Wiki` pages render placeholders - `Character` and `Wiki` pages render placeholders
- Prepared spells list is empty; `Spell` is a name-only stub; attunements - Prepared spells list is empty; `Spell` is a name-only stub; attunements
have no UI; `Settings` has only `version` have no UI; `Settings` has only `version`

View File

@ -8,6 +8,8 @@ game. The UI is in Russian.
- Campaign header: name, in-game date steppers, session counter, and - Campaign header: name, in-game date steppers, session counter, and
Save / Load / Clear: download `dashboard.json`, import a file back, Save / Load / Clear: download `dashboard.json`, import a file back,
wipe to a blank campaign wipe to a blank campaign
- Undo/redo: header buttons and Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y over
edit bursts; Clear and import are undoable too
- Character sidebar: portrait, names, class, level, XP, hit points with - Character sidebar: portrait, names, class, level, XP, hit points with
temp HP bar, hit dice, death saves, spell slots temp HP bar, hit dice, death saves, spell slots
- Inventories page (`/inv`): personal and party-common inventories, - Inventories page (`/inv`): personal and party-common inventories,

View File

@ -105,21 +105,30 @@ Snapshot-based undo rides on the Phase 1 machinery: serialize → push →
fires on any mutation, so no component changes are needed and every later fires on any mutation, so no component changes are needed and every later
phase's edits are undoable from day one. phase's edits are undoable from day one.
- [ ] `state::undo.rs` (hydrate-gated): undo/redo stacks of serialized - [x] `state::undo.rs` (hydrate-gated): undo/redo stacks of serialized
`Dashboard`, capped (e.g. 100); push coalesced on the store trigger `Dashboard`, capped (e.g. 100); push coalesced on the store trigger
(one snapshot per ~1 s window → one undo step = one edit burst) (one snapshot per ~1 s window → one undo step = one edit burst)
- [ ] a new edit after undo clears the redo stack; Clear and import push a - [x] a new edit after undo clears the redo stack; Clear and import push a
snapshot first, so they are undoable too snapshot first, so they are undoable too
- [ ] `undo()` / `redo()` call `replace_state`; expose stack depths as - [x] `undo()` / `redo()` call `replace_state`; expose stack depths as
`RwSignal<usize>` for button disabled states `RwSignal<usize>` for button disabled states
- [ ] header buttons: ↩ Отменить / Вернуть (disabled when empty) - [x] header buttons: ↩ Отменить / Вернуть (disabled when empty)
- [ ] shortcuts: Ctrl+Z, Ctrl+Shift+Z (Ctrl+Y); ignore when focus is in an - [x] shortcuts: Ctrl+Z, Ctrl+Shift+Z (Ctrl+Y); ignore when focus is in an
input/textarea/select, so typing never triggers undo input/textarea/select, so typing never triggers undo
- [ ] unit tests for stack semantics; e2e: edit → undo → redo; reload keeps - [x] unit tests for stack semantics; e2e: edit → undo → redo; reload keeps
the undone state (undo writes through autosave) the undone state (undo writes through autosave)
- **Acceptance:** every edit since the last window is reversible with a - **Acceptance:** every edit since the last window is reversible with a
keystroke; undo survives a reload. keystroke; undo survives a reload.
**Done (2026-08-16):** implementation in `src/state/undo.rs`; e2e-verified
in chromium (buttons, shortcuts, reload, undoable Clear). Notes:
- Snapshots are `Dashboard` clones, not JSON: the dashboard is small.
- `HistoryHandle` is `Copy` (RwSignal fields) — context-friendly and
capture-safe under edition-2024 closure rules.
- No `std::time::Instant`: it panics on wasm32; the settle timer is the
only clock. The undo button enables with the pending burst, so a
fresh edit is undoable before the 1 s window settles.
## Phase 2 — Character page (M, ~1-2 days) ## Phase 2 — Character page (M, ~1-2 days)
`/` currently renders the literal string "character". `/` currently renders the literal string "character".