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:
@@ -2,8 +2,8 @@
|
||||
// short arrow from the source planet to its destination, drawn as
|
||||
// three `LinePrim` segments — one shaft and two arrowhead wings —
|
||||
// styled per load type so the four cargo kinds are
|
||||
// distinguishable at a glance. Phase 16 ships placeholder
|
||||
// colours; Phase 35 polish picks final values.
|
||||
// distinguishable at a glance. The stroke colours come from the
|
||||
// active `Theme` (dark or light); the alpha and width are fixed.
|
||||
//
|
||||
// Geometry uses `torusShortestDelta` so an arrow that crosses the
|
||||
// torus seam takes the wrap, not the long way round, matching the
|
||||
@@ -13,35 +13,21 @@
|
||||
import type { GameReport, ReportPlanet } from "../api/game-state";
|
||||
import type { CargoLoadType } from "../sync/order-types";
|
||||
import { torusShortestDelta } from "./math";
|
||||
import type { LinePrim, PrimitiveID, Style } from "./world";
|
||||
import { DARK_THEME, type LinePrim, type PrimitiveID, type Style, type Theme } from "./world";
|
||||
|
||||
export const STYLE_ROUTE_COL: Style = {
|
||||
strokeColor: 0x4fc3f7,
|
||||
strokeAlpha: 0.95,
|
||||
strokeWidthPx: 2,
|
||||
};
|
||||
export const STYLE_ROUTE_CAP: Style = {
|
||||
strokeColor: 0xffb74d,
|
||||
strokeAlpha: 0.95,
|
||||
strokeWidthPx: 2,
|
||||
};
|
||||
export const STYLE_ROUTE_MAT: Style = {
|
||||
strokeColor: 0x81c784,
|
||||
strokeAlpha: 0.95,
|
||||
strokeWidthPx: 2,
|
||||
};
|
||||
export const STYLE_ROUTE_EMP: Style = {
|
||||
strokeColor: 0x90a4ae,
|
||||
strokeAlpha: 0.85,
|
||||
strokeWidthPx: 1,
|
||||
};
|
||||
|
||||
const STYLE_BY_LOAD_TYPE: Record<CargoLoadType, Style> = {
|
||||
COL: STYLE_ROUTE_COL,
|
||||
CAP: STYLE_ROUTE_CAP,
|
||||
MAT: STYLE_ROUTE_MAT,
|
||||
EMP: STYLE_ROUTE_EMP,
|
||||
};
|
||||
/**
|
||||
* routeStylesByLoadType builds the per-load-type stroke styles for the
|
||||
* active theme. A single `Style` object is shared by every line of a
|
||||
* given load type within one call so the renderer can dedupe them.
|
||||
*/
|
||||
function routeStylesByLoadType(theme: Theme): Record<CargoLoadType, Style> {
|
||||
return {
|
||||
COL: { strokeColor: theme.routeCol, strokeAlpha: 0.95, strokeWidthPx: 2 },
|
||||
CAP: { strokeColor: theme.routeCap, strokeAlpha: 0.95, strokeWidthPx: 2 },
|
||||
MAT: { strokeColor: theme.routeMat, strokeAlpha: 0.95, strokeWidthPx: 2 },
|
||||
EMP: { strokeColor: theme.routeEmp, strokeAlpha: 0.85, strokeWidthPx: 1 },
|
||||
};
|
||||
}
|
||||
|
||||
/** Per-load-type priority. Higher wins hit-test ties; planets sit
|
||||
* at 1..4 (`state-binding.ts.priorityFor`), so route arrows always
|
||||
@@ -91,13 +77,18 @@ const HEAD_HALF_ANGLE = (25 * Math.PI) / 180;
|
||||
* whose routes — outgoing or incoming — should be filtered out so the
|
||||
* arrows do not point at hidden glyphs. Empty / undefined means no
|
||||
* extra filtering, preserving the pre-Phase-29 contract.
|
||||
*
|
||||
* `theme` supplies the per-load-type stroke colours and defaults to
|
||||
* `DARK_THEME`.
|
||||
*/
|
||||
export function buildCargoRouteLines(
|
||||
report: GameReport,
|
||||
opts?: { skipPlanets?: ReadonlySet<number> },
|
||||
theme: Theme = DARK_THEME,
|
||||
): LinePrim[] {
|
||||
if (report.routes.length === 0) return [];
|
||||
const skip = opts?.skipPlanets;
|
||||
const styleByLoadType = routeStylesByLoadType(theme);
|
||||
const planetById = new Map<number, ReportPlanet>();
|
||||
for (const planet of report.planets) {
|
||||
planetById.set(planet.number, planet);
|
||||
@@ -131,7 +122,7 @@ export function buildCargoRouteLines(
|
||||
route.sourcePlanetNumber,
|
||||
entry.loadType,
|
||||
);
|
||||
const style = STYLE_BY_LOAD_TYPE[entry.loadType];
|
||||
const style = styleByLoadType[entry.loadType];
|
||||
const priority = PRIORITY_BY_LOAD_TYPE[entry.loadType];
|
||||
lines.push({
|
||||
kind: "line",
|
||||
|
||||
Reference in New Issue
Block a user