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
+15 -15
View File
@@ -23,7 +23,7 @@ function rowsFrom(priority: string[], pins: Record<string, string>): Row[] {
}
const selectClass =
"bg-gray-800 border border-gray-700 rounded px-2 py-1 text-gray-200 text-xs focus:outline-none focus:border-indigo-500 disabled:opacity-60 max-w-[13rem]";
"bg-raised border border-line-strong rounded px-2 py-1 text-ink text-xs focus:outline-none focus:border-indigo-500 disabled:opacity-60 max-w-[13rem]";
function DeviceSelect({
value, devices, devicesKnown, autoLabel, label, disabled, onChange,
@@ -116,18 +116,18 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
return (
<section>
<h2 className="text-sm font-semibold text-gray-400 uppercase tracking-wider mb-1">SDRs</h2>
<p className="text-xs text-gray-500 font-mono mb-3">
<h2 className="text-sm font-semibold text-ink-2 uppercase tracking-wider mb-1">SDRs</h2>
<p className="text-xs text-ink-muted font-mono mb-3">
{devicesKnown
? `This node reports ${devices.length} SDR${devices.length === 1 ? "" : "s"}.`
: "This node hasn't reported its SDRs yet."}
</p>
<div className="bg-gray-900 border border-gray-800 rounded-lg divide-y divide-gray-800 font-mono text-sm">
<div className="bg-surface border border-line rounded-lg divide-y divide-line font-mono text-sm">
<div className="flex flex-wrap items-center gap-3 px-4 py-2.5">
<div className="flex-1 min-w-0">
<div className="text-gray-200">OP25 SDR</div>
<div className="text-xs text-gray-500">
<div className="text-ink">OP25 SDR</div>
<div className="text-xs text-ink-muted">
{op25Moving
? "Saving restarts OP25 on the selected SDR."
: node.op25_sdr_serial
@@ -162,18 +162,18 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
: "Waiting for SDR";
return (
<div key={row.mode} className="flex flex-wrap items-center gap-3 px-4 py-2.5">
<span className="w-4 text-right text-gray-600 text-xs">{row.enabled ? ++rank : ""}</span>
<span className="w-4 text-right text-ink-muted text-xs">{row.enabled ? ++rank : ""}</span>
<input
type="checkbox"
checked={row.enabled}
disabled={!canEdit}
aria-label={`Enable ${meta.name}`}
onChange={(e) => edit(rows.map((r, j) => (j === i ? { ...r, enabled: e.target.checked } : r)))}
className="rounded bg-gray-800 border-gray-700 text-indigo-600 focus:ring-indigo-500 focus:ring-offset-gray-900"
className="rounded bg-raised border-line-strong text-indigo-600 focus:ring-indigo-500 focus:ring-offset-gray-900"
/>
<div className="flex-1 min-w-[7rem]">
<div className="text-gray-200">{meta.name}</div>
<div className="text-xs text-gray-500">{meta.hint}</div>
<div className="text-ink">{meta.name}</div>
<div className="text-xs text-ink-muted">{meta.hint}</div>
</div>
<DeviceSelect
value={row.pin}
@@ -191,7 +191,7 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
onClick={() => move(i, -1)}
disabled={i === 0}
aria-label={`Move ${meta.name} up`}
className="w-7 h-7 rounded bg-gray-800 hover:bg-gray-700 text-gray-300 disabled:opacity-30"
className="w-7 h-7 rounded bg-raised hover:bg-gray-700 text-ink-2 disabled:opacity-30"
>
▲
</button>
@@ -200,13 +200,13 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
onClick={() => move(i, 1)}
disabled={i === rows.length - 1}
aria-label={`Move ${meta.name} down`}
className="w-7 h-7 rounded bg-gray-800 hover:bg-gray-700 text-gray-300 disabled:opacity-30"
className="w-7 h-7 rounded bg-raised hover:bg-gray-700 text-ink-2 disabled:opacity-30"
>
▼
</button>
</div>
)}
<span className={`w-32 text-right text-xs ${state === "Running" ? "text-green-400" : "text-gray-500"}`}>
<span className={`w-32 text-right text-xs ${state === "Running" ? "text-green-400" : "text-ink-muted"}`}>
{state}
</span>
</div>
@@ -214,7 +214,7 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
})}
</div>
<p className="text-xs text-gray-500 font-mono mt-2">
<p className="text-xs text-ink-muted font-mono mt-2">
Every SDR besides OP25&apos;s runs the next enabled service, top first. Pin a service to the SDR with its
antenna, or leave it on &quot;Any spare SDR&quot;.
</p>
@@ -235,7 +235,7 @@ export function SdrSettings({ node, canEdit }: { node: NodeRecord; canEdit: bool
>
{saving ? "Saving…" : "Save"}
</button>
{message && <span className="text-xs text-gray-500 font-mono">{message}</span>}
{message && <span className="text-xs text-ink-muted font-mono">{message}</span>}
</div>
)}
</section>