Frontend redesign chunk 1: design tokens and type
Build & Deploy / Build & push images (push) Successful in 4m10s
Build & Deploy / Deploy to VM (push) Successful in 1m57s

Replace hardcoded dark-palette Tailwind classes with semantic CSS custom
properties (page/surface/raised/line/ink/accent/sev-moderate/sev-major/
map-*) defined on :root (light) and .dark (dark), wired through
tailwind.config.ts theme.extend.colors. Add IBM Plex Sans/Mono via
next/font/google: sans for everything a person reads, mono reserved for
machine identifiers only. Drop font-mono from body and Button's base
classes. Existing !important light-mode overrides kept temporarily so
nothing goes unreadable mid-migration (removed in chunk 4).

Per UI_REDESIGN.md chunk 1.
This commit is contained in:
Logan Cusano
2026-08-19 22:53:20 -04:00
parent d041c8648d
commit c6bc712b54
4 changed files with 105 additions and 6 deletions
+59 -1
View File
@@ -4,9 +4,67 @@
@import 'leaflet/dist/leaflet.css';
/* ── Design tokens ────────────────────────────────────────────────────────────
* Single source of truth for surface, ink and encoding colour. `:root` is the
* LIGHT theme; `.dark` on <html> (set by ThemeProvider, darkMode: ["class"])
* swaps the same names to their dark values. Tailwind reads these through
* theme.extend.colors, so components say `bg-surface` / `text-ink-muted`
* instead of `bg-gray-900` / `text-gray-400`.
*
* Colour encoding is validated for colour-blindness — see UI_REDESIGN.md §2.3.
* Severity is the ONLY hue channel. Incident type is shape. Node state is value.
* Do not add a hue here for a category; add a glyph.
*/
:root {
--page: #F4F6F9;
--surface: #FFFFFF;
--raised: #F7F9FB;
--line: rgba(11,17,27,.11);
--line-strong: rgba(11,17,27,.22);
--ink: #101620;
--ink-2: #46536A;
--ink-muted: #6B788C;
--accent: #2A78D6;
--sev-moderate: #B07800;
--sev-major: #C0281F;
--map-bg: #E8ECF1;
--map-block: #DFE4EB;
--map-road: #FFFFFF;
--map-water: #D3E2EE;
}
.dark {
--page: #0B0E13;
--surface: #141922;
--raised: #1B2230;
--line: rgba(255,255,255,.09);
--line-strong: rgba(255,255,255,.17);
--ink: #E8EBF0;
--ink-2: #A5B0C2;
--ink-muted: #77839A;
--accent: #3987E5;
--sev-moderate: #C98500;
--sev-major: #D03B3B;
--map-bg: #0E131B;
--map-block: #161C26;
--map-road: #232C3A;
--map-water: #12202E;
}
/* ── Base ─────────────────────────────────────────────────────────────────── */
html, body {
@apply bg-gray-950 text-gray-100 font-mono;
@apply bg-page text-ink;
font-family: var(--font-sans), system-ui, sans-serif;
}
/* Mono is for machine identifiers only — timestamps, talkgroups, unit
* callsigns, node ids, frequencies, incident ids, number columns. */
.font-mono, code, kbd, pre, samp {
font-family: var(--font-mono), ui-monospace, monospace;
}
/* ── Light mode overrides ─────────────────────────────────────────────────── */
+21 -2
View File
@@ -1,9 +1,26 @@
import type { Metadata } from "next";
import { IBM_Plex_Sans, IBM_Plex_Mono } from "next/font/google";
import { AuthProvider } from "@/components/AuthProvider";
import { ThemeProvider } from "@/components/ThemeProvider";
import { ChromeSwitcher } from "@/components/ChromeSwitcher";
import "./globals.css";
/* Sans for humans (headings, summaries, transcripts, buttons, nav);
* mono for machines (timestamps, talkgroups, unit ids). See UI_REDESIGN.md §2.1. */
const plexSans = IBM_Plex_Sans({
subsets: ["latin"],
weight: ["400", "500", "600"],
variable: "--font-sans",
display: "swap",
});
const plexMono = IBM_Plex_Mono({
subsets: ["latin"],
weight: ["400", "500"],
variable: "--font-mono",
display: "swap",
});
export const metadata: Metadata = {
title: "DRB — Public-Safety Radio Intelligence",
description: "Live incident awareness from field SDR nodes — transcribed, correlated, and mapped in real time.",
@@ -11,12 +28,14 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
// suppressHydrationWarning: the inline script below adds `.dark` to <html>
// before hydration, so the server/client className legitimately differs.
<html lang="en" suppressHydrationWarning className={`${plexSans.variable} ${plexMono.variable}`}>
<head>
{/* Prevent flash of wrong theme before React hydrates */}
<script dangerouslySetInnerHTML={{ __html: `(function(){try{var t=localStorage.getItem('drb-theme');if(t!=='light')document.documentElement.classList.add('dark');}catch(e){}})();` }} />
</head>
<body className="min-h-screen bg-gray-950">
<body className="min-h-screen bg-page text-ink">
<ThemeProvider>
<AuthProvider>
<ChromeSwitcher>{children}</ChromeSwitcher>