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:
co-authored by
Claude Opus 5.5
parent
3968b49b80
commit
bf206334e3
@@ -125,7 +125,7 @@ export default function NodeDetailPage() {
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return <p className="text-gray-500 font-mono text-sm">Loading node…</p>;
|
||||
return <p className="text-ink-muted font-mono text-sm">Loading node…</p>;
|
||||
}
|
||||
|
||||
const system = systemMap[node.assigned_system_id ?? ""];
|
||||
@@ -135,7 +135,7 @@ export default function NodeDetailPage() {
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white font-mono">{node.name}</h1>
|
||||
<p className="text-gray-500 text-sm font-mono">{node.node_id}</p>
|
||||
<p className="text-ink-muted text-sm font-mono">{node.node_id}</p>
|
||||
</div>
|
||||
<StatusBadge status={node.status} />
|
||||
</div>
|
||||
@@ -147,7 +147,7 @@ export default function NodeDetailPage() {
|
||||
<span className="text-base">⚠</span>
|
||||
<span>Local System Override Active</span>
|
||||
</div>
|
||||
<p className="text-gray-400 text-xs leading-relaxed">
|
||||
<p className="text-ink-2 text-xs leading-relaxed">
|
||||
This node is operating on a local system override.
|
||||
{node.override_timeout_at ? (
|
||||
<> Resets automatically on: <span className="text-white font-bold">{new Date(node.override_timeout_at).toLocaleString()}</span>.</>
|
||||
@@ -189,7 +189,7 @@ export default function NodeDetailPage() {
|
||||
)}
|
||||
|
||||
{/* Info */}
|
||||
<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">
|
||||
{[
|
||||
["System", system?.name ?? "Unassigned"],
|
||||
["Location", `${node.lat}, ${node.lon}`],
|
||||
@@ -208,12 +208,12 @@ export default function NodeDetailPage() {
|
||||
...(node.node_type !== "portable" ? [["Enforce Timeout", node.enforce_override_timeout ? "Yes" : "No"]] : []),
|
||||
].map(([label, value]) => (
|
||||
<div key={label} className="flex justify-between px-4 py-2.5">
|
||||
<span className="text-gray-500">{label}</span>
|
||||
<span className="text-gray-200">{value}</span>
|
||||
<span className="text-ink-muted">{label}</span>
|
||||
<span className="text-ink">{value}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex justify-between px-4 py-2.5">
|
||||
<span className="text-gray-500">Approval</span>
|
||||
<span className="text-ink-muted">Approval</span>
|
||||
<ApprovalBadge status={node.approval_status ?? null} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,7 +232,7 @@ export default function NodeDetailPage() {
|
||||
<button
|
||||
onClick={handleReject}
|
||||
disabled={approving}
|
||||
className="px-4 py-2 bg-red-900 hover:bg-red-800 disabled:opacity-50 text-gray-300 rounded-lg text-sm font-mono transition-colors"
|
||||
className="px-4 py-2 bg-red-900 hover:bg-red-800 disabled:opacity-50 text-ink-2 rounded-lg text-sm font-mono transition-colors"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
@@ -250,7 +250,7 @@ export default function NodeDetailPage() {
|
||||
<button
|
||||
disabled={sending}
|
||||
onClick={() => sendCommand("op25_restart")}
|
||||
className="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 bg-raised hover:bg-gray-700 text-ink-2 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
>
|
||||
Restart OP25
|
||||
</button>
|
||||
@@ -258,7 +258,7 @@ export default function NodeDetailPage() {
|
||||
<button
|
||||
disabled={sending}
|
||||
onClick={handleRequestUpdate}
|
||||
className="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 bg-raised hover:bg-gray-700 text-ink-2 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
>
|
||||
Update Node Software
|
||||
</button>
|
||||
@@ -283,16 +283,16 @@ export default function NodeDetailPage() {
|
||||
|
||||
{/* Recent calls */}
|
||||
<section>
|
||||
<h2 className="text-sm font-semibold text-gray-400 uppercase tracking-wider mb-3">Recent Calls</h2>
|
||||
<h2 className="text-sm font-semibold text-ink-2 uppercase tracking-wider mb-3">Recent Calls</h2>
|
||||
{/* Gate A / A2 (server-26#46) — each row expands to a transcript. */}
|
||||
{nodeCalls.length > 0 && <MachineOutputNotice variant="inline" className="mb-3" />}
|
||||
{nodeCalls.length === 0 ? (
|
||||
<p className="text-gray-600 text-sm font-mono">No calls recorded from this node.</p>
|
||||
<p className="text-ink-muted text-sm font-mono">No calls recorded from this node.</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-xs text-gray-500 uppercase tracking-wider border-b border-gray-800">
|
||||
<tr className="text-xs text-ink-muted uppercase tracking-wider border-b border-line">
|
||||
<th className="px-4 py-2 text-left">Time</th>
|
||||
<th className="px-4 py-2 text-left">Talkgroup</th>
|
||||
<th className="px-4 py-2 text-left">System</th>
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function NodesPage() {
|
||||
<button
|
||||
onClick={handleUpdateAll}
|
||||
disabled={updatingAll}
|
||||
className="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
className="px-4 py-2 bg-raised hover:bg-gray-700 text-ink-2 rounded-lg text-sm font-mono transition-colors disabled:opacity-50"
|
||||
>
|
||||
{updatingAll ? "Requesting…" : "Update All Nodes"}
|
||||
</button>
|
||||
@@ -88,13 +88,13 @@ export default function NodesPage() {
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-sm font-semibold text-gray-400 uppercase tracking-wider">
|
||||
<h2 className="text-sm font-semibold text-ink-2 uppercase tracking-wider">
|
||||
All Nodes ({nodes.length})
|
||||
</h2>
|
||||
{loading ? (
|
||||
<p className="text-gray-600 text-sm font-mono">Loading…</p>
|
||||
<p className="text-ink-muted text-sm font-mono">Loading…</p>
|
||||
) : nodes.length === 0 ? (
|
||||
<p className="text-gray-600 text-sm font-mono">No nodes registered yet. Boot a Pi to get started.</p>
|
||||
<p className="text-ink-muted text-sm font-mono">No nodes registered yet. Boot a Pi to get started.</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{nodes.map((n) => (
|
||||
|
||||
Reference in New Issue
Block a user