feat(ui): single-URL game app-shell (in-memory screens/views) #35

Merged
developer merged 8 commits from feature/ui-app-shell into development 2026-05-23 20:18:09 +00:00

8 Commits

Author SHA1 Message Date
Ilia Denisov 1dadf08672 docs(ui): clarify lobby re-enter starts at the map, only refresh restores
Tests · UI / test (pull_request) Successful in 2m32s
The single-URL restore replays the saved screen/view on an in-place
refresh only. Re-entering a game from the lobby resets activeView to the
map (lobby calls activeView.reset() before appScreen.go("game")), and
browser Back / the return-to-lobby control exit to the lobby. Spell this
out so the refresh-restore is not mistaken for a per-re-enter restore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:14:15 +02:00
Ilia Denisov c1672224a6 fix(ui): pin the mobile game shell to the viewport
Tests · UI / test (push) Successful in 2m49s
The app-shell migration surfaced a mobile-only e2e failure: taps on the
bottom-tab bar, the map-toggles menu, and the planet sheet were
intercepted by sibling elements despite the targets being on top.

Root cause: `.game-shell` used `min-height: 100vh`, so sub-pixel content
overflowed the viewport and made the document scrollable. On mobile that
scroll toggles the browser's dynamic toolbar, which resizes the viewport
and every `position: fixed` overlay (their sizes derive from `100vh`)
mid-gesture — defeating Playwright's actionability hit-test, and making
the real controls jittery to tap.

Pin the shell with `position: fixed; inset: 0` on the mobile breakpoint
so it leaves document flow: the document can no longer scroll, the
toolbar stays put, the viewport and overlays stay stable, and the
active-view area remains the single internal scroll region. Desktop is
unchanged (the rule is scoped to max-width: 767.98px).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:40:06 +02:00
Ilia Denisov e31fb2c17a 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>
2026-05-23 21:04:11 +02:00
Ilia Denisov 4e0058d46c test(ui): migrate suite to the app-shell (state-driven navigation)
- Unit: repoint moved screen imports (lib/screens, lib/game), mock
  $lib/app-nav (appScreen/activeView) instead of $app/navigation, drop the
  removed gameId props, assert screen/view selection.
- e2e: add a dev-only window.__galaxyNav affordance; specs enter a game via
  enterGame(...) instead of a /games/:id URL; URL assertions become content
  assertions (the URL stays /game/); reload uses waitUntil:"commit" (shallow
  routing) and mocks /rpc on game entry.
- Remove the obsolete report scroll-restore test (it relied on a SvelteKit
  route Snapshot that no longer exists); update the missing-membership test
  to the new lobby-redirect+toast behaviour. Fix a stale report.svelte
  docstring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:49:35 +02:00
Ilia Denisov 80545e9f9d feat(ui): app-shell behaviour — restore validation, return-to-lobby, push
- A restored game that no longer exists (cancelled/removed/revoked) drops to
  the lobby with a toast instead of the in-game error state: game-state
  exposes a `notFound` flag and the shell redirects via appScreen.go("lobby").
- Add a visible "return to lobby" control to the in-game header.
- Push/toast deep-links use activeView.select(...) (no URL); fix a latent
  visibility-listener double-install on in-place game switches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:11:54 +02:00
Ilia Denisov be7f06e163 feat(ui): screen-level history for the app-shell (Back → lobby)
Mirror the screen into browser history via SvelteKit shallow routing
(pushState/replaceState with page.state) so Back/Forward move between
screens while the URL stays at /game/. Overlays (game, lobby-create) push;
lobby/login replace. A popstate→page.state effect syncs the store back
without re-pushing (no loop); the boot stamp puts a restored overlay above
the load entry so Back falls through to lobby. In-game view switches never
touch history.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:07:03 +02:00
Ilia Denisov b6770d394c feat(ui): app-shell core — single-route dispatcher, route collapse, nav→state
Collapse the game UI to one route (`/`): a screen dispatcher renders
login/lobby/lobby-create/game from `appScreen`/`activeView` state instead of
URL routes. Move screen components to lib/screens & lib/game; the game shell
reads the game id from `appScreen.gameId` and re-inits per-game stores via an
$effect; in-game views render from `activeView`. Flip ~23 goto/href nav sites
to store mutations; drop the `?sidebar=` URL coupling. Auth gate is now
state-based. WIP: browser-history (Back→lobby), restore-validation, the
return-to-lobby button, push deep-links, and the test migration are follow-ups
on this branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:04:04 +02:00
Ilia Denisov 182beebcd6 feat(ui): app-nav state stores (app-shell foundation)
Add `appScreen` + `activeView` rune singletons with a shared sessionStorage
snapshot — the in-memory source of truth that replaces URL-based screen/view
routing for the single-URL app-shell. Not wired in yet (additive).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:45:27 +02:00