feat(ui): map canvas follows light/dark theme; fix invisible gear control
The map view now selects a DARK_THEME or LIGHT_THEME palette from the resolved app theme and threads it through every primitive builder, so the canvas, planets, ship groups, cargo routes, battle/bombing markers, fog, reach + selection rings, pending-Send tracks, and the pick overlay all switch with the rest of the chrome. A theme flip remounts the renderer preserving the camera — Pixi bakes the background at init and every primitive bakes its colour at build, so a live re-tint is not possible on the same instance. This also fixes the reported bug: the gear-popover trigger and the loading overlay hardcoded a dark navy background, so in light theme the gear was invisible (dark icon on dark chip) until hover flipped it to a white chip. Both now use the --color-surface-overlay token and read correctly in both themes. The light palette mirrors the dark one role-for-role, darkened / saturated for contrast on a light background while keeping the incoming, battle, and bombing accents vivid. The values are a first pass meant to be refined during the F8 manual-QA loop. Removes the now-dead "Phase 35" references from the code and lifts the map-recoloring prohibition from the design-system / renderer docs; the battle scene stays a fixed-palette data-viz surface. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -5,11 +5,9 @@ import { describe, expect, it } from "vitest";
|
||||
import type { GameReport } from "../src/api/game-state";
|
||||
import {
|
||||
battleMarkerStrokeWidth,
|
||||
BATTLE_MARKER_COLOR,
|
||||
BOMBING_MARKER_COLOR_DAMAGED,
|
||||
BOMBING_MARKER_COLOR_WIPED,
|
||||
buildBattleAndBombingMarkers,
|
||||
} from "../src/map/battle-markers";
|
||||
import { DARK_THEME, LIGHT_THEME } from "../src/map/world";
|
||||
import { EMPTY_SHIP_GROUPS } from "./helpers/empty-ship-groups";
|
||||
|
||||
describe("battleMarkerStrokeWidth", () => {
|
||||
@@ -87,9 +85,10 @@ describe("buildBattleAndBombingMarkers", () => {
|
||||
const out = buildBattleAndBombingMarkers(report);
|
||||
const lines = out.primitives.filter((p) => p.kind === "line");
|
||||
expect(lines).toHaveLength(2);
|
||||
// Same yellow colour, 5 px wide for a 100-shot battle.
|
||||
// Same colour (dark-palette default), 5 px wide for a 100-shot
|
||||
// battle.
|
||||
for (const l of lines) {
|
||||
expect(l.style.strokeColor).toBe(BATTLE_MARKER_COLOR);
|
||||
expect(l.style.strokeColor).toBe(DARK_THEME.battleMarker);
|
||||
expect(l.style.strokeWidthPx).toBe(5);
|
||||
}
|
||||
// First line: top-left → bottom-right corner of the planet square.
|
||||
@@ -184,7 +183,61 @@ describe("buildBattleAndBombingMarkers", () => {
|
||||
const out = buildBattleAndBombingMarkers(report);
|
||||
const rings = out.primitives.filter((p) => p.kind === "circle");
|
||||
expect(rings).toHaveLength(2);
|
||||
expect(rings[0].style.strokeColor).toBe(BOMBING_MARKER_COLOR_DAMAGED);
|
||||
expect(rings[1].style.strokeColor).toBe(BOMBING_MARKER_COLOR_WIPED);
|
||||
expect(rings[0].style.strokeColor).toBe(DARK_THEME.bombingDamaged);
|
||||
expect(rings[1].style.strokeColor).toBe(DARK_THEME.bombingWiped);
|
||||
});
|
||||
|
||||
it("paints markers with the supplied palette's colours", () => {
|
||||
const report = makeReport({
|
||||
planets: [
|
||||
{
|
||||
number: 4,
|
||||
name: "Test",
|
||||
kind: "local",
|
||||
x: 10,
|
||||
y: 20,
|
||||
size: 50,
|
||||
resources: 0,
|
||||
industryStockpile: 0,
|
||||
materialsStockpile: 0,
|
||||
population: 0,
|
||||
colonists: 0,
|
||||
industry: 0,
|
||||
freeIndustry: 0,
|
||||
production: "MAT",
|
||||
owner: null,
|
||||
},
|
||||
],
|
||||
battles: [
|
||||
{ id: "11111111-1111-1111-1111-111111111111", planet: 4, shots: 3 },
|
||||
],
|
||||
bombings: [
|
||||
{
|
||||
planetNumber: 4,
|
||||
planet: "Test",
|
||||
owner: "X",
|
||||
attacker: "Y",
|
||||
production: "MAT",
|
||||
industry: 0,
|
||||
population: 0,
|
||||
colonists: 0,
|
||||
industryStockpile: 0,
|
||||
materialsStockpile: 0,
|
||||
attackPower: 1,
|
||||
wiped: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const out = buildBattleAndBombingMarkers(report, LIGHT_THEME);
|
||||
const lines = out.primitives.filter((p) => p.kind === "line");
|
||||
const rings = out.primitives.filter((p) => p.kind === "circle");
|
||||
for (const l of lines) {
|
||||
expect(l.style.strokeColor).toBe(LIGHT_THEME.battleMarker);
|
||||
}
|
||||
expect(rings[0].style.strokeColor).toBe(LIGHT_THEME.bombingWiped);
|
||||
// The accents are deliberately distinct between the palettes.
|
||||
expect(LIGHT_THEME.battleMarker).not.toBe(DARK_THEME.battleMarker);
|
||||
expect(LIGHT_THEME.bombingWiped).not.toBe(DARK_THEME.bombingWiped);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user