feat(ui): F8-05 — game-mode chrome cleanup + inspector compact rows (#48)
Drains six F8 polish items (parent #43) in one feature: а) Chrome cleanup - п.6 — remove the AccountMenu (settings/sessions/theme/language/logout ∼ rudimentary in-game) and replace it with a single icon-button light/dark theme toggle. The toggle flips an in-memory `theme.override`; game-shell unmount calls `theme.clearOverride()` so the lobby (and any re-entry) re-projects the persisted lobby choice. - п.8 — remove the wrap-scrolling radio from the map gear popover. The per-game `wrapMode` store and the renderer's no-wrap path stay in place for a future engine-side topology feature; only the UI surface is dropped (wrap is a server-side concept, not a per-session UI affordance). б) Inspector compact rows (single idiom: select + ✓ apply / ✗ cancel, or contextual edit/remove/add) - п.13 — planet name is now click-to-edit: clicking the name opens an inline `<input>` + ✓ confirm icon; Escape cancels; the explicit Rename action button and Cancel button are gone. - п.14 — production becomes one row: primary `<select>` picks industry/materials/research/ship, conditional secondary `<select>` picks the target (tech / science / ship class) for research and ship contexts. Apply is gated until row state differs from the planet's current effective production; auto-submit-on-click is replaced by the apply-gate. - п.16 — cargo routes collapse to one row: a single dropdown (COL/CAP/MAT/EMP plus a placeholder that absorbs the old section title) and contextual action buttons (add / edit + remove) to the right. After a successful pick or remove the dropdown stays on the type the user just acted on. - п.32 — stationed ship groups hoist the race column into a dropdown above the table. The dropdown seeds with the player's own race when local groups are stationed here, otherwise the first race alphabetically; rendered only when more than one race is in orbit. The race column is dropped in both single- and multi-race modes — the dropdown's value already names the active race. Tests: unit and Playwright e2e updated for every changed test-id and flow; new coverage added for `theme.override`, the in-game toggle, the apply-gate behaviour, and the stationed-race dropdown. i18n keys for the removed menu items, the wrap radios, the cargo title, and the explicit `rename.cancel` are dropped from both locales; new `game.shell.theme_toggle.*`, `production.main/target.*`, `production.apply/cancel`, `cargo.placeholder`, and `ship_groups.race_filter.aria` keys land. Docs synced: `docs/FUNCTIONAL.md` §6.7 + `docs/FUNCTIONAL_ru.md` mirror drop the torus / no-wrap radio mention; `ui/docs/design-system.md` documents the lobby-owned persisted picker + the in-game ephemeral override channel. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -10,14 +10,24 @@ best-effort:
|
||||
typed contract does not carry per-group ownership outside
|
||||
battle rosters.
|
||||
|
||||
Phase 20 makes own-ship rows interactive: clicking a row pivots
|
||||
Phase 20 made own-ship rows interactive: clicking a row pivots
|
||||
the inspector to the corresponding ship-group inspector through
|
||||
the shared `SelectionStore`. The actions panel mounts on top of
|
||||
the existing ship-group inspector, so the row is the on-planet
|
||||
entry point for Send / Load / Modernize / etc. Foreign rows stay
|
||||
non-interactive — there are no actions to drive against another
|
||||
race's fleet. Phase 21+ will reuse the same row shape inside the
|
||||
ship-groups table view with an additional `(planet, race)` filter.
|
||||
race's fleet.
|
||||
|
||||
F8-05 (issue #48 п.32) moved the race column into a dropdown
|
||||
above the table: the previous "race | class | count | mass"
|
||||
layout overflowed horizontally on narrow viewports. The dropdown
|
||||
seeds with the player's own race when local groups are stationed
|
||||
here, otherwise with the first race alphabetically; both cases
|
||||
are after sorting `availableRaces` alphabetically so the picker
|
||||
is stable across re-mounts. When a single race is in orbit the
|
||||
dropdown is hidden — there is nothing to choose — and the table
|
||||
renders straight through. The race column is dropped in both
|
||||
modes because the dropdown already names the active race.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
@@ -91,6 +101,55 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
return rows;
|
||||
});
|
||||
|
||||
const ownStationedHere = $derived(
|
||||
stationedRows.some((r) => r.selectable),
|
||||
);
|
||||
|
||||
const availableRaces = $derived.by(() => {
|
||||
const set = new Set<string>();
|
||||
for (const row of stationedRows) set.add(row.race);
|
||||
return Array.from(set).sort((a, b) => a.localeCompare(b));
|
||||
});
|
||||
|
||||
const ownRaceLabel = $derived(
|
||||
localRace || i18n.t("game.inspector.planet.ship_groups.race.unknown"),
|
||||
);
|
||||
|
||||
function defaultRace(races: ReadonlyArray<string>): string {
|
||||
if (races.length === 0) return "";
|
||||
if (ownStationedHere && races.includes(ownRaceLabel)) return ownRaceLabel;
|
||||
return races[0]!;
|
||||
}
|
||||
|
||||
let selectedRace = $state<string>("");
|
||||
|
||||
$effect(() => {
|
||||
// Re-seed whenever the inspector switches planets or the
|
||||
// stationed roster changes (new arrivals after a turn).
|
||||
// Preserve the player's pick if it is still represented;
|
||||
// otherwise fall back to the documented default.
|
||||
void planet.number;
|
||||
const races = availableRaces;
|
||||
if (races.length === 0) {
|
||||
selectedRace = "";
|
||||
return;
|
||||
}
|
||||
if (selectedRace === "" || !races.includes(selectedRace)) {
|
||||
selectedRace = defaultRace(races);
|
||||
}
|
||||
});
|
||||
|
||||
const showFilter = $derived(availableRaces.length > 1);
|
||||
const filteredRows = $derived(
|
||||
showFilter
|
||||
? stationedRows.filter((r) => r.race === selectedRace)
|
||||
: stationedRows,
|
||||
);
|
||||
|
||||
function pickRace(event: Event): void {
|
||||
selectedRace = (event.target as HTMLSelectElement).value;
|
||||
}
|
||||
|
||||
function selectLocalGroup(groupId: string): void {
|
||||
if (selection === undefined) return;
|
||||
selection.selectShipGroup({ variant: "local", id: groupId });
|
||||
@@ -99,9 +158,26 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
|
||||
{#if stationedRows.length > 0}
|
||||
<section class="ship-groups" data-testid="inspector-planet-ship-groups">
|
||||
<h4>{i18n.t("game.inspector.planet.ship_groups.title")}</h4>
|
||||
<div class="head">
|
||||
<h4>{i18n.t("game.inspector.planet.ship_groups.title")}</h4>
|
||||
{#if showFilter}
|
||||
<select
|
||||
class="race-select"
|
||||
data-testid="inspector-planet-ship-groups-race-filter"
|
||||
aria-label={i18n.t(
|
||||
"game.inspector.planet.ship_groups.race_filter.aria",
|
||||
)}
|
||||
value={selectedRace}
|
||||
onchange={pickRace}
|
||||
>
|
||||
{#each availableRaces as race (race)}
|
||||
<option value={race}>{race}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
<ul class="rows">
|
||||
{#each stationedRows as row (row.key)}
|
||||
{#each filteredRows as row (row.key)}
|
||||
<li class="row" data-testid="inspector-planet-ship-groups-row">
|
||||
{#if row.selectable && row.groupId !== null}
|
||||
{@const groupId = row.groupId}
|
||||
@@ -111,9 +187,6 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
data-testid="inspector-planet-ship-groups-select"
|
||||
onclick={() => selectLocalGroup(groupId)}
|
||||
>
|
||||
<span class="race" data-testid="inspector-planet-ship-groups-race">
|
||||
{row.race}
|
||||
</span>
|
||||
<span class="class">{row.class}</span>
|
||||
<span class="count">
|
||||
{i18n.t("game.inspector.planet.ship_groups.row.count", {
|
||||
@@ -127,9 +200,6 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
</span>
|
||||
</button>
|
||||
{:else}
|
||||
<span class="race" data-testid="inspector-planet-ship-groups-race">
|
||||
{row.race}
|
||||
</span>
|
||||
<span class="class">{row.class}</span>
|
||||
<span class="count">
|
||||
{i18n.t("game.inspector.planet.ship_groups.row.count", {
|
||||
@@ -154,6 +224,12 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
@@ -161,6 +237,18 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
.race-select {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--color-surface-raised);
|
||||
color: var(--color-text);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rows {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -177,7 +265,7 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
.row > span,
|
||||
.row > .select {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr auto auto;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.select {
|
||||
@@ -195,9 +283,6 @@ ship-groups table view with an additional `(planet, race)` filter.
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-surface-hover);
|
||||
}
|
||||
.race {
|
||||
font-weight: 600;
|
||||
}
|
||||
.class {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user