Files
galaxy-game/ui/docs/navigation.md
T
Ilia Denisov 460591c159 ui/phase-12: order composer skeleton
OrderDraftStore persists per-game command drafts in Cache; the
sidebar Order tab renders the list with a per-row delete control.
The layout passes a `historyMode` prop through Sidebar / BottomTabs
as a constant `false`, so Phase 26 only flips the source.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 23:26:58 +02:00

7.2 KiB
Raw Blame History

In-game shell — navigation model

This doc covers the chrome that wraps every in-game view: the responsive layout shell, the active-view router built on SvelteKit's file-system routes, the sidebar with three tools and its state-preservation rule, and the mobile bottom-tabs. The user-facing spec — view list, breakpoint diagrams, history-mode plans — lives in ../PLAN.md, section Information Architecture and Navigation. This doc is the source of truth for how those rules are implemented.

Active-view model

The client renders one active view at a time. Every active view is a SvelteKit route under routes/games/[id]/; the route file is a two-line wrapper that mounts the matching content component from src/lib/active-view/<name>.svelte. The "view router" mentioned in the plan is the file system plus those wrappers — there is no separate dispatch component.

URL Active view component Phase that fills it
/games/:id/map lib/active-view/map.svelte Phase 11
/games/:id/table/:entity lib/active-view/table.svelte Phase 11 / 17 / 19 / 22
/games/:id/report lib/active-view/report.svelte Phase 23
/games/:id/battle/:battleId? lib/active-view/battle.svelte Phase 27
/games/:id/mail lib/active-view/mail.svelte Phase 28
/games/:id/designer/ship-class/:id? lib/active-view/designer-ship-class.svelte Phase 17 / 18
/games/:id/designer/science/:id? lib/active-view/designer-science.svelte Phase 21

/games/:id (no trailing view) redirects to /games/:id/map. The optional :id? segments on the designer routes match SvelteKit's [[id]] syntax — they accept both the new-draft and editing URLs; later phases read the param when wiring real content.

The entity slug on the table route is kebab-case (planets, ship-classes, ship-groups, fleets, sciences, races); the table stub maps it to the matching game.view.table.<snake> i18n key.

Sidebar tools and state preservation

The desktop sidebar hosts three tools:

Tool Component Phase that fills it
Calculator lib/sidebar/calculator-tab.svelte Phase 30
Inspector lib/sidebar/inspector-tab.svelte Phase 13 / 19
Order lib/sidebar/order-tab.svelte Phase 12 / 14

The sidebar's selected-tab state is a $state rune inside lib/sidebar/sidebar.svelte. The component is mounted by the layout at routes/games/[id]/+layout.svelte, and SvelteKit keeps that layout instance alive while the user navigates between child routes (/games/:id/map/games/:id/report → …). The rune therefore survives every active-view switch automatically, with no URL coupling needed.

A ?sidebar=calc|calculator|inspector|order URL param is read once on mount and seeds the initial tab. Later phases that want to land the user on a particular tool (for example, Phase 14's first end-to-end command flow) can set it on navigation.

The Order entry is hidden when the layout's historyMode flag is true. Phase 12 plumbs the flag end-to-end as a prop — +layout.svelte passes a constant false to Sidebar, which forwards hideOrder to its TabBar; the same flag goes to BottomTabs so the mobile Order button is also suppressed. A ?sidebar=order URL seed that arrives while the flag is true falls back to inspector, and an $effect on the sidebar resets activeTab away from order if the flag flips on mid-session. Phase 26 introduces lib/history-mode.ts and replaces the constant with the live signal; the order draft survives the toggle because OrderDraftStore lives one level above the sidebar in the layout hierarchy. See order-composer.md for the draft-store side of the flow.

Layout breakpoints

Three discrete CSS modes matched to the IA section diagrams:

  • ≥ 1024 px (desktop) — the sidebar sits beside the active view and is always rendered. The header view-menu trigger uses the dropdown icon (▾). Bottom-tabs and the tablet sidebar-toggle are CSS-hidden.
  • 7681024 px (tablet) — the sidebar collapses behind a click toggle in the header right corner. Tapping the toggle slides the sidebar in as a fixed overlay above the active view; a close button on the sidebar dismisses it. The full swipe-from-right gesture in the IA section is deferred to Phase 35 polish — the click toggle satisfies the "layout switches at 768 px" acceptance criterion on Phase 10.
  • < 768 px (mobile) — the sidebar is hidden entirely and the bottom-tabs row appears at the bottom of the viewport. The view-menu trigger swaps to a hamburger icon (☰) that opens the drop-down as a full-width drawer below the header.

Inspector is intentionally unreachable on mobile in Phase 10. Per the IA section the mobile inspector is a bottom-sheet raised by tapping a map object, and that mechanism waits for Phase 13.

Mobile bottom-tabs and tool overlay

The bottom-tabs row is [Map, Calc, Order, More]. Map navigates to /games/:id/map and clears any tool overlay. Calc and Order navigate to /games/:id/map too — but they also flip the layout's mobileTool state to calc / order, which the layout uses to swap the active-view slot for the Calculator / Order tool component.

The tool overlay only applies when the URL is /map. Navigating to any other view through the More drawer or the header view-menu makes the layout's derived effectiveTool collapse back to map, so the user always sees the URL's active view rather than a stale overlay. The next time the user taps a Calc or Order bottom-tab, the navigation re-routes them to /map and re-applies the overlay.

The More button opens a drawer that mirrors the header view-menu content. The IA section's narrower "More" list (Mail, Battle log, Tables, History, Settings, Logout) is the polish target for Phase 35 — Phase 10 keeps a single source of truth for destinations.

Transient map overlays

Some views can push a transient overlay onto /map with a back affordance — for example, the ship-class designer pushes a range-preview overlay onto the map. The transient overlay clears when the user navigates to any other view via the header or the bottom-tabs.

Phase 10 documents this concept but does not implement the back-stack mechanism. Phase 34 lands the back-stack alongside its first user (multi-turn projection, range circles in the ship-class designer).

Auth gate

The root +layout.svelte redirects anonymous → /login for any non-/__debug/ path; the in-game shell inherits that gate without any extra check. When a session is revoked while the user is in the shell, the same redirect fires through the existing revocation watcher.