ui/phase-13: planet inspector — read-only
Plumbs the map → inspector pathway: a click on a planet selects it through the new SelectionStore, the sidebar Inspector tab swaps its empty-state copy for a per-kind read-only field set, and a mobile-only bottom-sheet mirrors the same content over the map. Field projection in api/game-state.ts now surfaces every documented planet field.
This commit is contained in:
@@ -1,29 +1,66 @@
|
||||
<!--
|
||||
Phase 10 stub for the Inspector sidebar tool. The empty-state copy
|
||||
matches the IA section verbatim — `select an object on the map` —
|
||||
so the user understands the intended interaction before Phase 13
|
||||
wires real planet selection.
|
||||
Inspector sidebar tool. Reads the per-game `SelectionStore` and the
|
||||
`GameStateStore` from context (both set by the in-game shell layout).
|
||||
When a planet selection resolves to a live `ReportPlanet` in the
|
||||
current report, the tab swaps the empty-state copy for the read-
|
||||
only planet inspector. A selection that points at a planet missing
|
||||
from the current report (e.g. visibility lost between turns) falls
|
||||
back to the empty state instead of holding stale data.
|
||||
|
||||
The empty-state copy still matches the IA section verbatim — `select
|
||||
an object on the map` — so the no-selection experience is unchanged
|
||||
from the Phase 10 stub.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
import { i18n } from "$lib/i18n/index.svelte";
|
||||
import {
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
type GameStateStore,
|
||||
} from "$lib/game-state.svelte";
|
||||
import {
|
||||
SELECTION_CONTEXT_KEY,
|
||||
type SelectionStore,
|
||||
} from "$lib/selection.svelte";
|
||||
import Planet from "$lib/inspectors/planet.svelte";
|
||||
|
||||
const gameState = getContext<GameStateStore | undefined>(
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
);
|
||||
const selection = getContext<SelectionStore | undefined>(
|
||||
SELECTION_CONTEXT_KEY,
|
||||
);
|
||||
|
||||
const selectedPlanet = $derived.by(() => {
|
||||
const sel = selection?.selected;
|
||||
if (sel === undefined || sel === null || sel.kind !== "planet") return null;
|
||||
const report = gameState?.report;
|
||||
if (report === undefined || report === null) return null;
|
||||
return report.planets.find((p) => p.number === sel.id) ?? null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<section class="tool" data-testid="sidebar-tool-inspector">
|
||||
<h3>{i18n.t("game.sidebar.tab.inspector")}</h3>
|
||||
<p>{i18n.t("game.sidebar.empty.inspector")}</p>
|
||||
{#if selectedPlanet !== null}
|
||||
<Planet planet={selectedPlanet} />
|
||||
{:else}
|
||||
<h3>{i18n.t("game.sidebar.tab.inspector")}</h3>
|
||||
<p>{i18n.t("game.sidebar.empty.inspector")}</p>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.tool {
|
||||
padding: 1rem;
|
||||
font-family: system-ui, sans-serif;
|
||||
}
|
||||
.tool h3 {
|
||||
.tool > h3 {
|
||||
margin: 0 0 0.5rem;
|
||||
padding: 1rem 1rem 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.tool p {
|
||||
.tool > p {
|
||||
margin: 0;
|
||||
padding: 0 1rem 1rem;
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user