feat(ui): F8-12 — map polish (zoom invariance, labels, selection, soft radius) (#55)
Tests · UI / test (push) Waiting to run
Tests · UI / test (pull_request) Failing after 5m16s

* Honest pixel-space sizing for `pointRadiusPx` / `strokeWidthPx`: the
  renderer divides by the current camera scale on every
  `viewport.zoomed` so thin lines / small markers stay the same on-screen
  size at any zoom.
* Known-size planets switch to `pointRadiusWorld`, softened against the
  reference scale by `PLANET_SIZE_ZOOM_ALPHA = 0.33`; unidentified
  planets pin to a 3-px disc.
* New planet label layer renders a two-line `name / #N` legend under
  each planet (`#N` only for unidentified or when the new `planetNames`
  toggle is off). Selection now paints an inverse-fill frame around the
  selected planet's label plus an outline on the disc; the old
  selection-ring primitive is retired.
* Bombing markers swap the separate CirclePrim for a planet-outline
  overlay (damaged / wiped colour); the report deep-link moves to a
  "view bombing report" link in the planet inspector.
* Docs + tests follow: `renderer.md` reflects the new sizing contract +
  label / outline layers, vitest covers the sizing math, label
  formatting, and the new toggle, and the map-toggles e2e adds a
  persistence case for `planetNames`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-27 23:51:16 +02:00
parent ba93a9092e
commit 680ebac919
30 changed files with 1240 additions and 322 deletions
@@ -19,6 +19,7 @@ the entry point, Escape (or unmounting the inspector) reverts.
<script lang="ts">
import { getContext, tick } from "svelte";
import type {
ReportBombing,
ReportLocalShipGroup,
ReportOtherShipGroup,
ReportPlanet,
@@ -36,6 +37,8 @@ the entry point, Escape (or unmounting the inspector) reverts.
type EntityNameInvalidReason,
} from "$lib/util/entity-name";
import { formatFloat } from "$lib/util/number-format";
import { scrollToBombingRow } from "$lib/report-nav";
import { activeView } from "$lib/app-nav.svelte";
import CargoRoutes from "./planet/cargo-routes.svelte";
import Production from "./planet/production.svelte";
import ShipGroups from "./planet/ship-groups.svelte";
@@ -52,6 +55,7 @@ the entry point, Escape (or unmounting the inspector) reverts.
localShipGroups: ReportLocalShipGroup[];
otherShipGroups: ReportOtherShipGroup[];
localRace: string;
bombing?: ReportBombing | null;
};
let {
planet,
@@ -65,8 +69,15 @@ the entry point, Escape (or unmounting the inspector) reverts.
localShipGroups,
otherShipGroups,
localRace,
bombing = null,
}: Props = $props();
function openBombingReport(): void {
if (bombing === null) return;
activeView.select("report");
scrollToBombingRow(bombing.planetNumber);
}
const kindKeyMap: Record<ReportPlanet["kind"], TranslationKey> = {
local: "game.inspector.planet.kind.local",
other: "game.inspector.planet.kind.other",
@@ -314,6 +325,23 @@ the entry point, Escape (or unmounting the inspector) reverts.
{i18n.t("game.inspector.planet.unidentified_no_data")}
</p>
{/if}
{#if bombing !== null}
<button
type="button"
class="bombing-link"
class:bombing-link--wiped={bombing.wiped}
data-testid="inspector-planet-view-bombing"
data-bombing-wiped={bombing.wiped ? "true" : "false"}
onclick={openBombingReport}
>
{i18n.t(
bombing.wiped
? "game.inspector.planet.view_bombing_wiped"
: "game.inspector.planet.view_bombing",
)}
</button>
{/if}
</section>
<style>
@@ -432,4 +460,28 @@ the entry point, Escape (or unmounting the inspector) reverts.
.icon-action--apply:not(:disabled) {
color: var(--color-success);
}
.bombing-link {
font: inherit;
font-size: 0.85rem;
padding: 0.4rem 0.6rem;
background: var(--color-surface-hover);
color: var(--color-text);
border: 1px solid var(--color-border);
border-left: 3px solid var(--color-warning, #f57f17);
border-radius: 3px;
cursor: pointer;
text-align: left;
}
.bombing-link:hover,
.bombing-link:focus-visible {
border-color: var(--color-accent);
border-left-color: var(--color-warning, #f57f17);
}
.bombing-link--wiped {
border-left-color: var(--color-danger);
}
.bombing-link--wiped:hover,
.bombing-link--wiped:focus-visible {
border-left-color: var(--color-danger);
}
</style>