docs(ui): sync docs to the app-shell; fix stale nav comments
Tests · UI / test (push) Failing after 9m28s

Rewrite ui/docs (navigation, order-composer, auth-flow, pwa-strategy,
game-state + secondary topic docs) and ui/README for the single-URL
app-shell (in-memory screens/views, Back→lobby via shallow routing,
sessionStorage restore + validation, return-to-lobby). ui/PLAN.md gets a
Phase-10 supersede note (implemented; standalone-compatible). Fix stale
code comments (session-store auth gate, report-sections spec contract).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-23 21:04:11 +02:00
parent 4e0058d46c
commit e31fb2c17a
17 changed files with 453 additions and 262 deletions
+18 -28
View File
@@ -107,36 +107,23 @@ visible area so that scrolling down advances the highlight
naturally. The observer is created on mount and torn down on
unmount.
The in-game shell layout (`routes/games/[id]/+layout.svelte`)
The in-game shell (`lib/game/game-shell.svelte`)
expands `<main class="active-view-host">` to fit content rather
than constraining it, so the document body is the actual scroll
container — not the host. The IntersectionObserver root is `null`
to match.
## Scroll save / restore
## Scroll position
`routes/games/[id]/report/+page.svelte` exports a SvelteKit
`Snapshot<{ scrollY: number }>`:
- `capture()` reads `window.scrollY` when SvelteKit's
`beforeNavigate` cycle runs.
- `restore(value)` schedules a short
`requestAnimationFrame` poll that waits for
`document.documentElement.scrollHeight` to grow tall enough to
honour the saved offset, then calls `window.scrollTo(0, value)`.
The poll caps at ~60 frames (≈ 1 second) so a never-tall-enough
body never pins a frame loop.
The capture / restore pair is keyed by route, so:
- Forward navigation from `/report` to `/map` lands `/map` at
scrollY 0 (no snapshot for `/map` to restore from).
- History-back from `/map` to `/report` restores the previously
captured scrollY — the user returns to the same section.
The Snapshot API does not capture the active sidebar slug; the
IntersectionObserver re-derives it from the restored scroll
position on the next animation frame, which keeps the TOC
highlight consistent without a second source of truth.
The report is the `report` active view; switching to another view is
an in-memory `activeView` state change, not a navigation, and the
report component is remounted when the user returns to it. The
single-URL app-shell therefore does not carry SvelteKit's route-keyed
`Snapshot` scroll save/restore — that mechanism was tied to the old
`/games/:id/report` route and was removed with it. A re-entered report
opens at the top; the IntersectionObserver re-derives the active TOC
slug from the scroll position on the next animation frame, so the
highlight stays consistent without a separate source of truth.
## i18n namespace
@@ -169,10 +156,13 @@ couple them silently.
/ IntersectionObserver are out of scope.
- **Playwright** — `tests/e2e/report-sections.spec.ts` exercises
the full integration: every TOC anchor lands its section in
view, the snapshot mechanism preserves `window.scrollY` on
history navigation, the back-to-map button reaches `/map`, the
mobile `<select>` scrolls to the chosen section on a narrow
viewport.
view, the back-to-map button switches to the map view
(`activeView.select("map")`), and the mobile `<select>` scrolls
to the chosen section on a narrow viewport. The spec drives the
app-shell through `window.__galaxyNav` (the dev-only nav surface)
instead of `page.goto` per-view URLs. The old "scroll position
survives a `/map` round-trip via SvelteKit `Snapshot`" case was
dropped — see the [scroll position](#scroll-position) note.
Test IDs follow the pattern `report-section-<slug>` for section
roots, `report-toc-<slug>` for TOC anchors, and per-section row