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:
@@ -1,10 +1,15 @@
|
||||
<!--
|
||||
Phase 29 gear popover. Sits in the top-right corner of the map
|
||||
canvas and exposes the per-game visibility / wrap toggles that the
|
||||
canvas and exposes the per-game visibility toggles that the
|
||||
`GameStateStore` already owns. The component is a thin view of the
|
||||
store — every checkbox / radio fires `store.setMapToggle(...)` or
|
||||
`store.setWrapMode(...)` and reads back the current state through
|
||||
the rune.
|
||||
store — every checkbox fires `store.setMapToggle(...)` and reads
|
||||
back the current state through the rune.
|
||||
|
||||
The wrap-scrolling toggle that used to live alongside the visibility
|
||||
flags was dropped in F8-05 (issue #48 п.8): wrap is a game-server
|
||||
feature, not a per-session UI affordance, so the renderer always
|
||||
runs in torus mode for now. The renderer-side `wrapMode` plumbing
|
||||
stays put for when the engine surfaces non-torus topologies.
|
||||
|
||||
Outside-click + Escape close the popover, matching the
|
||||
`header/view-menu.svelte` precedent. On mobile (<768 px) the
|
||||
@@ -16,7 +21,6 @@ bottom-tabs bar.
|
||||
import { i18n } from "$lib/i18n/index.svelte";
|
||||
import { restoreFocus } from "$lib/a11y/restore-focus";
|
||||
import type { MapToggles, GameStateStore } from "$lib/game-state.svelte";
|
||||
import type { WrapMode } from "../../map/world";
|
||||
|
||||
type Props = { store: GameStateStore };
|
||||
let { store }: Props = $props();
|
||||
@@ -35,18 +39,6 @@ bottom-tabs bar.
|
||||
void store.setMapToggle(key, event.currentTarget.checked as MapToggles[K]);
|
||||
}
|
||||
|
||||
/**
|
||||
* setWrap is wired to the radios' `onclick`, not `onchange`, so the
|
||||
* Playwright `.click()` action on the input fires the callback even
|
||||
* when the input is already checked (the `change` event suppresses
|
||||
* the second activation, which made the wrap-mode e2e flake).
|
||||
* `onclick` also fires reliably on touch / pointer activation.
|
||||
*/
|
||||
function setWrap(mode: WrapMode): void {
|
||||
if (store.wrapMode === mode) return;
|
||||
void store.setWrapMode(mode);
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent): void {
|
||||
if (event.key === "Escape" && open) {
|
||||
open = false;
|
||||
@@ -197,31 +189,6 @@ bottom-tabs bar.
|
||||
/>
|
||||
<span>{i18n.t("game.map.toggles.visible_hyperspace")}</span>
|
||||
</label>
|
||||
<div class="wrap-row">
|
||||
<span class="wrap-label">{i18n.t("game.map.toggles.wrap.label")}</span>
|
||||
<label class="radio">
|
||||
<input
|
||||
type="radio"
|
||||
name="map-toggles-wrap"
|
||||
data-testid="map-toggles-wrap-torus"
|
||||
value="torus"
|
||||
checked={store.wrapMode === "torus"}
|
||||
onclick={() => setWrap("torus")}
|
||||
/>
|
||||
<span>{i18n.t("game.map.toggles.wrap.torus")}</span>
|
||||
</label>
|
||||
<label class="radio">
|
||||
<input
|
||||
type="radio"
|
||||
name="map-toggles-wrap"
|
||||
data-testid="map-toggles-wrap-no-wrap"
|
||||
value="no-wrap"
|
||||
checked={store.wrapMode === "no-wrap"}
|
||||
onclick={() => setWrap("no-wrap")}
|
||||
/>
|
||||
<span>{i18n.t("game.map.toggles.wrap.no_wrap")}</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -295,27 +262,9 @@ bottom-tabs bar.
|
||||
label:hover {
|
||||
background: var(--color-surface-hover);
|
||||
}
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
input[type="checkbox"] {
|
||||
accent-color: var(--color-accent);
|
||||
}
|
||||
.wrap-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.wrap-label {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
width: 100%;
|
||||
}
|
||||
.radio {
|
||||
padding: 0.15rem 0.4rem;
|
||||
}
|
||||
@media (max-width: 767.98px) {
|
||||
.surface {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user