ui/phase-19: read-only ship-group inspector + sheet + tab dispatch
Closes Phase 19's UI surface. The inspector dispatches on the
selection variant: local / other groups render class, count, the
four tech levels, mass, cargo (type + amount when loaded),
location (planet name on-orbit, from/to/distance in hyperspace),
and — for local groups only — fleet membership + state. Incoming
groups surface origin / destination / distance / speed and the
inline ETA = ceil(distance / speed); zero speed collapses to the
designer's existing "—" placeholder. Unidentified groups render
just the (x, y) coordinates and the no-data hint, mirroring the
unidentified planet treatment.
Layout / inspector-tab plumbing:
- inspector-tab.svelte derives selectedShipGroup against the
rendered report and mounts <ShipGroup /> when the planet
branch doesn't match. Stale refs (an index that no longer
resolves after a turn refresh) collapse cleanly to the empty
state.
- +layout.svelte mounts <ShipGroupSheet /> alongside the
existing planet sheet on mobile; both share the
`effectiveTool === "map"` guard and clear-on-close.
i18n: en + ru both grow ~30 keys under
`game.inspector.ship_group.*`. Adding a key to one without the
other is a TS error (TranslationKey is `keyof typeof en`), so the
Russian mirror stays mandatory.
Tests:
- inspector-ship-group.test.ts exercises every variant —
on-planet local, in-hyperspace local, cargo-loaded local,
foreign, incoming with ETA, incoming with zero speed,
unidentified, plus the missing-planet `#NN` fallback.
- tests/e2e/inspector-ship-group.spec.ts is a smoke spec that
drives the DEV-only synthetic-report loader from /lobby
through navigation to /games/synthetic-XXX/map.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,8 @@ fresh.
|
||||
import Calculator from "$lib/sidebar/calculator-tab.svelte";
|
||||
import Order from "$lib/sidebar/order-tab.svelte";
|
||||
import PlanetSheet from "$lib/inspectors/planet-sheet.svelte";
|
||||
import ShipGroupSheet from "$lib/inspectors/ship-group-sheet.svelte";
|
||||
import type { ShipGroupSelection } from "$lib/inspectors/ship-group.svelte";
|
||||
import type { MobileTool, SidebarTab } from "$lib/sidebar/types";
|
||||
import { GameStateStore, GAME_STATE_CONTEXT_KEY } from "$lib/game-state.svelte";
|
||||
import {
|
||||
@@ -139,6 +141,35 @@ fresh.
|
||||
if (report === null) return null;
|
||||
return report.planets.find((p) => p.number === sel.id) ?? null;
|
||||
});
|
||||
const selectedShipGroup: ShipGroupSelection | null = $derived.by(() => {
|
||||
const sel = selection.selected;
|
||||
if (sel === null || sel.kind !== "shipGroup") return null;
|
||||
const report = renderedReport.report;
|
||||
if (report === null) return null;
|
||||
const ref = sel.ref;
|
||||
switch (ref.variant) {
|
||||
case "local": {
|
||||
const group = report.localShipGroups.find((g) => g.id === ref.id);
|
||||
if (group === undefined) return null;
|
||||
return { variant: "local", group };
|
||||
}
|
||||
case "other": {
|
||||
const group = report.otherShipGroups[ref.index];
|
||||
if (group === undefined) return null;
|
||||
return { variant: "other", group };
|
||||
}
|
||||
case "incoming": {
|
||||
const group = report.incomingShipGroups[ref.index];
|
||||
if (group === undefined) return null;
|
||||
return { variant: "incoming", group };
|
||||
}
|
||||
case "unidentified": {
|
||||
const group = report.unidentifiedShipGroups[ref.index];
|
||||
if (group === undefined) return null;
|
||||
return { variant: "unidentified", group };
|
||||
}
|
||||
}
|
||||
});
|
||||
const localShipClass = $derived(
|
||||
renderedReport.report?.localShipClass ?? [],
|
||||
);
|
||||
@@ -296,6 +327,12 @@ fresh.
|
||||
onMap={effectiveTool === "map"}
|
||||
onClose={() => selection.clear()}
|
||||
/>
|
||||
<ShipGroupSheet
|
||||
selection={selectedShipGroup}
|
||||
planets={inspectorPlanets}
|
||||
onMap={effectiveTool === "map"}
|
||||
onClose={() => selection.clear()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user