From 4c3b1fcc84256b5ee2908fc760bf0bf2ac2f27f1 Mon Sep 17 00:00:00 2001 From: Logan Date: Sun, 10 May 2026 21:47:34 -0400 Subject: [PATCH] UI Updates --- drb-frontend/app/admin/page.tsx | 2 +- drb-frontend/app/alerts/page.tsx | 2 +- drb-frontend/app/calls/page.tsx | 4 +- drb-frontend/app/dashboard/page.tsx | 2 +- drb-frontend/app/globals.css | 99 +++++++++++++ drb-frontend/app/incidents/page.tsx | 2 +- drb-frontend/app/layout.tsx | 17 ++- drb-frontend/app/map/page.tsx | 16 +-- drb-frontend/app/systems/page.tsx | 2 +- drb-frontend/app/tokens/page.tsx | 2 +- drb-frontend/components/MapView.tsx | 157 +++++++++++++-------- drb-frontend/components/Nav.tsx | 163 +++++++++++++++++----- drb-frontend/components/ThemeProvider.tsx | 34 +++++ drb-frontend/tailwind.config.ts | 1 + 14 files changed, 385 insertions(+), 118 deletions(-) create mode 100644 drb-frontend/components/ThemeProvider.tsx diff --git a/drb-frontend/app/admin/page.tsx b/drb-frontend/app/admin/page.tsx index 44aebfa..dccddc6 100644 --- a/drb-frontend/app/admin/page.tsx +++ b/drb-frontend/app/admin/page.tsx @@ -98,7 +98,7 @@ export default function AdminPage() { if (!isAdmin) return null; return ( -
+

Admin

diff --git a/drb-frontend/app/alerts/page.tsx b/drb-frontend/app/alerts/page.tsx index c3159cb..2bf0156 100644 --- a/drb-frontend/app/alerts/page.tsx +++ b/drb-frontend/app/alerts/page.tsx @@ -197,7 +197,7 @@ export default function AlertsPage() { const unacked = alerts.filter((a) => !a.acknowledged); return ( -
+

Alerts

{unacked.length > 0 && ( diff --git a/drb-frontend/app/calls/page.tsx b/drb-frontend/app/calls/page.tsx index 55eea20..dc542d5 100644 --- a/drb-frontend/app/calls/page.tsx +++ b/drb-frontend/app/calls/page.tsx @@ -28,7 +28,7 @@ export default function CallsPage() {

Live ({active.length})

-
+
@@ -61,7 +61,7 @@ export default function CallsPage() {

No calls recorded yet.

) : ( <> -
+
diff --git a/drb-frontend/app/dashboard/page.tsx b/drb-frontend/app/dashboard/page.tsx index c8e14b5..6201c9d 100644 --- a/drb-frontend/app/dashboard/page.tsx +++ b/drb-frontend/app/dashboard/page.tsx @@ -86,7 +86,7 @@ export default function DashboardPage() { {calls.length === 0 ? (

No calls recorded yet.

) : ( -
+
diff --git a/drb-frontend/app/globals.css b/drb-frontend/app/globals.css index 027aefa..e5fb56a 100644 --- a/drb-frontend/app/globals.css +++ b/drb-frontend/app/globals.css @@ -4,6 +4,105 @@ @import 'leaflet/dist/leaflet.css'; +/* ── Base ─────────────────────────────────────────────────────────────────── */ html, body { @apply bg-gray-950 text-gray-100 font-mono; } + +/* ── Light mode overrides ─────────────────────────────────────────────────── */ +/* + * The app's components use hardcoded dark-palette Tailwind classes (bg-gray-9xx, + * text-gray-xxx). Rather than adding dark: prefixes everywhere, we remap those + * classes here when the html element doesn't carry the .dark class. + */ + +/* Structural backgrounds */ +html:not(.dark), +html:not(.dark) body { background-color: #f1f5f9; color: #0f172a; } +html:not(.dark) .bg-gray-950 { background-color: #f1f5f9 !important; } +html:not(.dark) .bg-gray-950\/95 { background-color: rgba(241,245,249,0.95) !important; } +html:not(.dark) .bg-gray-900 { background-color: #ffffff !important; } +html:not(.dark) .bg-gray-900\/60 { background-color: rgba(255,255,255,0.85) !important; } +html:not(.dark) .bg-gray-900\/50 { background-color: rgba(255,255,255,0.75) !important; } +html:not(.dark) .bg-gray-900\/30 { background-color: rgba(255,255,255,0.50) !important; } +html:not(.dark) .bg-gray-800 { background-color: #f1f5f9 !important; } +html:not(.dark) .bg-gray-800\/40 { background-color: rgba(241,245,249,0.60) !important; } +html:not(.dark) .bg-gray-800\/30 { background-color: rgba(241,245,249,0.50) !important; } +html:not(.dark) .bg-gray-700 { background-color: #e2e8f0 !important; } + +/* Borders */ +html:not(.dark) .border-gray-800 { border-color: #e2e8f0 !important; } +html:not(.dark) .border-gray-700 { border-color: #cbd5e1 !important; } +html:not(.dark) .divide-gray-800 > * + * { border-color: #e2e8f0 !important; } + +/* Text */ +html:not(.dark) .text-white { color: #0f172a !important; } +html:not(.dark) .text-gray-100 { color: #1e293b !important; } +html:not(.dark) .text-gray-300 { color: #334155 !important; } +html:not(.dark) .text-gray-400 { color: #475569 !important; } +html:not(.dark) .text-gray-500 { color: #64748b !important; } +html:not(.dark) .text-gray-600 { color: #94a3b8 !important; } + +/* Hover states */ +html:not(.dark) .hover\:bg-gray-900:hover { background-color: #f8fafc !important; } +html:not(.dark) .hover\:bg-gray-900\/50:hover { background-color: rgba(255,255,255,0.75) !important; } +html:not(.dark) .hover\:bg-gray-800:hover { background-color: #f1f5f9 !important; } +html:not(.dark) .hover\:bg-gray-700:hover { background-color: #e2e8f0 !important; } +html:not(.dark) .active\:bg-gray-800:active { background-color: #f1f5f9 !important; } + +/* Hover text */ +html:not(.dark) .hover\:text-gray-300:hover { color: #334155 !important; } +html:not(.dark) .hover\:text-gray-200:hover { color: #1e293b !important; } + +/* ── Accent badge palette (dark → light) ─────────────────────────────────── */ + +/* Fire / Error */ +html:not(.dark) .bg-red-900 { background-color: #fef2f2 !important; } +html:not(.dark) .bg-red-950 { background-color: #fff1f2 !important; } +html:not(.dark) .text-red-300 { color: #b91c1c !important; } +html:not(.dark) .text-red-400 { color: #dc2626 !important; } +html:not(.dark) .border-red-800 { border-color: #fca5a5 !important; } + +/* Police */ +html:not(.dark) .bg-blue-900 { background-color: #eff6ff !important; } +html:not(.dark) .bg-blue-950 { background-color: #eff6ff !important; } +html:not(.dark) .text-blue-300 { color: #1d4ed8 !important; } +html:not(.dark) .border-blue-800 { border-color: #93c5fd !important; } + +/* EMS */ +html:not(.dark) .bg-yellow-900 { background-color: #fefce8 !important; } +html:not(.dark) .bg-yellow-950 { background-color: #fefce8 !important; } +html:not(.dark) .text-yellow-300 { color: #a16207 !important; } +html:not(.dark) .text-yellow-400 { color: #ca8a04 !important; } + +/* Accident / Recording */ +html:not(.dark) .bg-orange-900 { background-color: #fff7ed !important; } +html:not(.dark) .bg-orange-950 { background-color: #fff7ed !important; } +html:not(.dark) .text-orange-300 { color: #c2410c !important; } +html:not(.dark) .text-orange-400 { color: #ea580c !important; } +html:not(.dark) .border-orange-800 { border-color: #fdba74 !important; } + +/* Active / Online */ +html:not(.dark) .bg-green-900 { background-color: #f0fdf4 !important; } +html:not(.dark) .bg-green-950 { background-color: #f0fdf4 !important; } +html:not(.dark) .text-green-300 { color: #15803d !important; } +html:not(.dark) .text-green-400 { color: #16a34a !important; } +html:not(.dark) .border-green-800 { border-color: #86efac !important; } + +/* Unconfigured / Info */ +html:not(.dark) .bg-indigo-950 { background-color: #eef2ff !important; } +html:not(.dark) .bg-indigo-900 { background-color: #eef2ff !important; } +html:not(.dark) .text-indigo-300 { color: #4338ca !important; } +html:not(.dark) .text-indigo-400 { color: #6366f1 !important; } +html:not(.dark) .border-indigo-800 { border-color: #a5b4fc !important; } + +/* ── Form inputs ─────────────────────────────────────────────────────────── */ +html:not(.dark) input:not([type="submit"]):not([type="button"]):not([type="reset"]), +html:not(.dark) select, +html:not(.dark) textarea { + color: #0f172a; +} +html:not(.dark) input::placeholder, +html:not(.dark) textarea::placeholder { + color: #94a3b8; +} diff --git a/drb-frontend/app/incidents/page.tsx b/drb-frontend/app/incidents/page.tsx index 27972a3..d5aa8d3 100644 --- a/drb-frontend/app/incidents/page.tsx +++ b/drb-frontend/app/incidents/page.tsx @@ -253,7 +253,7 @@ export default function IncidentsPage() { } return ( -
+

Incidents

diff --git a/drb-frontend/app/layout.tsx b/drb-frontend/app/layout.tsx index 29cdbf8..355c372 100644 --- a/drb-frontend/app/layout.tsx +++ b/drb-frontend/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Nav } from "@/components/Nav"; import { AuthProvider } from "@/components/AuthProvider"; +import { ThemeProvider } from "@/components/ThemeProvider"; import "./globals.css"; export const metadata: Metadata = { @@ -10,12 +11,18 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - + + + {/* Prevent flash of wrong theme before React hydrates */} +