From c6bc712b5459e779c6fdeb91a850b2d4d3e95946 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Wed, 19 Aug 2026 22:53:20 -0400 Subject: [PATCH] Frontend redesign chunk 1: design tokens and type 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. --- drb-frontend/app/globals.css | 60 ++++++++++++++++++++++++++- drb-frontend/app/layout.tsx | 23 +++++++++- drb-frontend/components/ui/Button.tsx | 2 +- drb-frontend/tailwind.config.ts | 26 +++++++++++- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/drb-frontend/app/globals.css b/drb-frontend/app/globals.css index b0e35ae..76b77ab 100644 --- a/drb-frontend/app/globals.css +++ b/drb-frontend/app/globals.css @@ -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 (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 ─────────────────────────────────────────────────── */ diff --git a/drb-frontend/app/layout.tsx b/drb-frontend/app/layout.tsx index d09208c..75963af 100644 --- a/drb-frontend/app/layout.tsx +++ b/drb-frontend/app/layout.tsx @@ -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 ( - + // suppressHydrationWarning: the inline script below adds `.dark` to + // before hydration, so the server/client className legitimately differs. + {/* Prevent flash of wrong theme before React hydrates */}