fix(frontend): finish the token migration — raw grey classes -> theme tokens

UI_REDESIGN chunk 4 was never finished: 39 app/component files still used
raw Tailwind greys, kept readable in light mode only by the !important
override sheet. In dark mode text-gray-600 is ~2.3:1 on surface, and the
light override maps it to #94a3b8 (~2.6:1 on white) — unreadable in both.

Mechanical mapping (886 classes): gray-100/200 -> ink, 300/400 -> ink-2,
500/600/700 -> ink-muted, bg 950/900/800 -> page/surface/raised,
border 800 -> line, 700/600 -> line-strong, plus hover/divide/placeholder.
Alpha suffixes kept (tokens are color-mix, so /60 works). bg-gray-700,
text-white and marketing pages left alone. text-[9px] -> text-[10px].

Frontend unverified: no Node on the authoring box (#207).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-10-25 21:29:13 -04:00
co-authored by Claude Opus 5.5
parent 3968b49b80
commit bf206334e3
39 changed files with 655 additions and 655 deletions
+12 -12
View File
@@ -440,7 +440,7 @@ function RadarBadge({ meta, loop, loopClock, onLoop }: {
else text = `Radar valid ${hhmmLocal(meta.valid)} · ${ageMin} min old`;
return (
<div className={`flex items-center gap-1.5 bg-surface/90 border rounded px-2 py-1 text-xs text-ink-2 pointer-events-auto ${stale ? "border-accent" : "border-line"}`}>
{stale && <span className="bg-accent text-white rounded px-1 text-[9px] font-semibold tracking-wide"
{stale && <span className="bg-accent text-white rounded px-1 text-[10px] font-semibold tracking-wide"
title={`The newest radar frame is more than ${RADAR_STALE_MIN} min old, or its time could not be read`}>STALE</span>}
<span className="tabular-nums whitespace-nowrap">{text}</span>
{meta.valid && meta.error && <span className="text-ink-muted whitespace-nowrap" title={meta.error}>· time not refreshing</span>}
@@ -1233,8 +1233,8 @@ function FanNodeLayer({
className={idx < members.length - 1 ? "border-b border-gray-200 pb-2" : ""}
>
<p className="font-semibold text-sm text-gray-900">{node.name}</p>
<p className="text-xs text-gray-500 font-mono">{node.node_id}</p>
<p className="text-xs capitalize text-gray-700">{node.status}</p>
<p className="text-xs text-ink-muted font-mono">{node.node_id}</p>
<p className="text-xs capitalize text-ink-muted">{node.status}</p>
{activeByNode[node.node_id] && (
<p className="text-xs text-orange-600 mt-0.5">
● TG {activeByNode[node.node_id].talkgroup_id ?? "—"}{" "}
@@ -1346,8 +1346,8 @@ function FanIncidentLayer({
<p className="text-xs capitalize font-medium" style={{ color }}>
{isKnownSeverity(inc.severity) ? SEVERITY_LABEL[inc.severity] : "Unknown"} · {inc.type ?? "other"}
</p>
{inc.location && <p className="text-xs text-gray-600">{inc.location}</p>}
<p className="text-[11px] text-gray-500">Pin: {PIN_PRECISION_LABEL[pinPrecision(inc)]}</p>
{inc.location && <p className="text-xs text-ink-muted">{inc.location}</p>}
<p className="text-[11px] text-ink-muted">Pin: {PIN_PRECISION_LABEL[pinPrecision(inc)]}</p>
<a
href={`/incidents/${inc.incident_id}`}
onClick={(e) => { e.stopPropagation(); window.location.href = `/incidents/${inc.incident_id}`; e.preventDefault(); }}
@@ -1490,19 +1490,19 @@ function IncidentPathLayer({
>
<Popup minWidth={160}>
<div className="text-gray-900">
<p className="text-xs text-gray-500">{heading}</p>
<p className="text-xs text-ink-muted">{heading}</p>
<p className="font-semibold text-sm mt-0.5">{inc.title ?? "Incident"}</p>
{c.location && <p className="text-xs text-gray-600 mt-0.5">{c.location}</p>}
{c.location && <p className="text-xs text-ink-muted mt-0.5">{c.location}</p>}
{c.location_coords?.location_type === "GEOMETRIC_CENTER" && (
<p className="text-[11px] text-gray-500">Approximate: centre of a road, junction or place</p>
<p className="text-[11px] text-ink-muted">Approximate: centre of a road, junction or place</p>
)}
{s.dashedIn && !s.ghost && path.movement && (
<p className="text-[11px] text-gray-500">Dashed in: long gap or talkgroup change — route unknown</p>
<p className="text-[11px] text-ink-muted">Dashed in: long gap or talkgroup change — route unknown</p>
)}
{hasAudio(c) && (
<div className="flex items-center gap-1.5 mt-1">
<PlayButton callId={c.call_id} label={s.n != null ? `Play stop ${s.n}` : "Play this call"} />
<span className="text-xs text-gray-600">Play this call</span>
<span className="text-xs text-ink-muted">Play this call</span>
</div>
)}
<a href={`/incidents/${inc.incident_id}`} className="text-xs text-blue-600 hover:underline block mt-1">
@@ -1997,7 +1997,7 @@ function MapView({
<span className="text-ink-2">Call location (not a pursuit)</span>
</div>
<div className="flex items-center gap-2">
<span className="text-[9px] px-0.5 rounded border border-dashed border-line text-ink-2 leading-tight">merged?</span>
<span className="text-[10px] px-0.5 rounded border border-dashed border-line text-ink-2 leading-tight">merged?</span>
<span className="text-ink-2">Path &gt; {MAY_BE_MERGED_KM} km — may be 2+ events</span>
</div>
</div>
@@ -2114,7 +2114,7 @@ function MapView({
<span className="uppercase tracking-wide font-semibold text-[11px]" style={{ color }}>
{isKnownSeverity(inc.severity) ? SEVERITY_LABEL[inc.severity] : "Unknown"}
</span>
{live && <span className="ml-auto bg-accent text-white rounded px-1 text-[9px] font-semibold tracking-wide">ON AIR</span>}
{live && <span className="ml-auto bg-accent text-white rounded px-1 text-[10px] font-semibold tracking-wide">ON AIR</span>}
</div>
<p className="text-ink font-semibold leading-snug truncate">
{inc.title ?? "Incident"}