UI Updates
This commit is contained in:
@@ -98,7 +98,7 @@ export default function AdminPage() {
|
||||
if (!isAdmin) return null;
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-2xl mx-auto space-y-8">
|
||||
<div className="max-w-2xl space-y-8">
|
||||
<h1 className="text-white text-xl font-bold font-mono">Admin</h1>
|
||||
|
||||
<section className="space-y-3">
|
||||
|
||||
@@ -197,7 +197,7 @@ export default function AlertsPage() {
|
||||
const unacked = alerts.filter((a) => !a.acknowledged);
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-7xl mx-auto space-y-6">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-white text-xl font-bold font-mono">Alerts</h1>
|
||||
{unacked.length > 0 && (
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function CallsPage() {
|
||||
<h2 className="text-sm font-semibold text-orange-400 uppercase tracking-wider mb-3">
|
||||
Live ({active.length})
|
||||
</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<div className="bg-gray-900 border border-gray-800 rounded-xl overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-xs text-gray-500 uppercase tracking-wider border-b border-gray-800">
|
||||
@@ -61,7 +61,7 @@ export default function CallsPage() {
|
||||
<p className="text-gray-600 text-sm font-mono">No calls recorded yet.</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="overflow-x-auto">
|
||||
<div className="bg-gray-900 border border-gray-800 rounded-xl overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-xs text-gray-500 uppercase tracking-wider border-b border-gray-800">
|
||||
|
||||
@@ -86,7 +86,7 @@ export default function DashboardPage() {
|
||||
{calls.length === 0 ? (
|
||||
<p className="text-gray-600 text-sm font-mono">No calls recorded yet.</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<div className="bg-gray-900 border border-gray-800 rounded-xl overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-xs text-gray-500 uppercase tracking-wider border-b border-gray-800">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ export default function IncidentsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-7xl mx-auto space-y-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<h1 className="text-white text-xl font-bold font-mono">Incidents</h1>
|
||||
|
||||
@@ -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 (
|
||||
<html lang="en" className="dark">
|
||||
<html lang="en">
|
||||
<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">
|
||||
<AuthProvider>
|
||||
<Nav />
|
||||
<main className="p-6">{children}</main>
|
||||
</AuthProvider>
|
||||
<ThemeProvider>
|
||||
<AuthProvider>
|
||||
<Nav />
|
||||
<main className="max-w-screen-2xl mx-auto px-4 md:px-6 py-6">{children}</main>
|
||||
</AuthProvider>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -50,26 +50,14 @@ export default function MapPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold text-white font-mono">Map</h1>
|
||||
<div className="flex items-center gap-4 text-xs font-mono text-gray-400">
|
||||
<span><span className="text-green-400">●</span> Online</span>
|
||||
<span><span className="text-orange-400 animate-pulse">●</span> Recording</span>
|
||||
<span><span className="text-indigo-400">●</span> Unconfigured</span>
|
||||
<span><span className="text-gray-600">●</span> Offline</span>
|
||||
<span className="border-l border-gray-700 pl-4"><span className="text-red-500">■</span> Fire</span>
|
||||
<span><span className="text-blue-500">■</span> Police</span>
|
||||
<span><span className="text-yellow-500">■</span> EMS</span>
|
||||
<span><span className="text-orange-500">■</span> Accident</span>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-xl font-bold text-white font-mono">Map</h1>
|
||||
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center h-96 text-gray-600 font-mono text-sm">
|
||||
Loading map…
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ height: "calc(100vh - 280px)", minHeight: "400px" }}>
|
||||
<div className="h-[50vh] sm:h-[65vh] min-h-[400px]">
|
||||
<MapView nodes={nodes} activeCalls={activeCalls} incidents={incidents} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -719,7 +719,7 @@ export default function SystemsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6 max-w-3xl">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold text-white font-mono">Systems</h1>
|
||||
<button
|
||||
|
||||
@@ -70,7 +70,7 @@ export default function TokensPage() {
|
||||
if (authLoading || !isAdmin) return null;
|
||||
|
||||
return (
|
||||
<div className="space-y-6 max-w-2xl">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white font-mono">Bot Token Pool</h1>
|
||||
|
||||
Reference in New Issue
Block a user