diff --git a/web/src/App.tsx b/web/src/App.tsx index 59ea093..21f9d46 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,9 +1,6 @@ import { Routes, Route, Navigate } from 'react-router-dom'; -import { useSelector } from 'react-redux'; import { Box, Button, Card, CardContent, Toolbar, Typography } from '@mui/material'; import PeopleIcon from '@mui/icons-material/People'; -import { selectSidebarOpen } from './app/slices/uiSlice'; -import type { RootState } from './app/store'; import ProtectedRoute, { RoleGuard } from './components/ProtectedRoute'; import Topbar from './components/Topbar'; import Sidebar from './components/Sidebar'; @@ -15,11 +12,8 @@ import ProposalDetailPage from './pages/proposals/detail/ProposalDetailPage'; import ProposalListPage from './pages/proposals/list/ProposalListPage'; import AdminDashboard from './pages/admin/dashboard/AdminDashboard'; import AdminWorkspace from './pages/admin/workspace/AdminWorkspace'; -import { DRAWER_WIDTH } from './constants'; export default function App() { - const sidebarOpen = useSelector((state: RootState) => selectSidebarOpen(state)); - return ( } /> @@ -36,9 +30,8 @@ export default function App() { component="main" sx={{ flexGrow: 1, + minWidth: 0, p: 1.25, - ml: sidebarOpen ? `${DRAWER_WIDTH}px` : 0, - transition: 'margin-left 250ms ease', minHeight: '100vh', }} > diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx index 03ad977..6d6d518 100644 --- a/web/src/components/Sidebar.tsx +++ b/web/src/components/Sidebar.tsx @@ -179,12 +179,6 @@ export default function Sidebar() { {navItems.map((item) => renderNavItem(item))} - {user && !isCollapsed && ( - - {user.displayName} - {user.role} - - )} ); } diff --git a/web/src/components/Topbar.tsx b/web/src/components/Topbar.tsx index 28062c7..9a04831 100644 --- a/web/src/components/Topbar.tsx +++ b/web/src/components/Topbar.tsx @@ -35,7 +35,7 @@ export default function Topbar() { sx={{ background: '#FEF3C7', color: '#92400E', - border: '1px solid #FCD34D', + border: '1px solid #FDE68A', height: 22, borderRadius: '999px', fontSize: '11px', @@ -55,7 +55,7 @@ export default function Topbar() { {user && ( - + {initials} diff --git a/web/src/constants/index.ts b/web/src/constants/index.ts index f1d639b..36ebcb3 100644 --- a/web/src/constants/index.ts +++ b/web/src/constants/index.ts @@ -28,13 +28,14 @@ export const STATUS_LABELS: Record = { Revised: 'Revised', }; +// Sea Haven Ops status chips — flat fill + thin border + bold label (tokens/base.css). export const STATUS_CHIP_STYLES: Record = { - Draft: { bgcolor: '#F1F5F9', color: '#334155', border: '1px solid #CBD5E1' }, + Draft: { bgcolor: '#F3F4F6', color: '#374151', border: '1px solid #D1D5DB' }, InReview: { bgcolor: '#E0F2FE', color: '#075985', border: '1px solid #7DD3FC' }, Approved: { bgcolor: '#DCFCE7', color: '#166534', border: '1px solid #86EFAC' }, - Sent: { bgcolor: '#DBEAFE', color: '#1E40AF', border: '1px solid #93C5FD' }, + Sent: { bgcolor: '#DBEAFE', color: '#1E40AF', border: '1px solid #BFDBFE' }, Revised: { bgcolor: '#F3E8FF', color: '#6B21A8', border: '1px solid #C084FC' }, - Rejected: { bgcolor: '#FEE2E2', color: '#991B1B', border: '1px solid #FCA5A5' }, + Rejected: { bgcolor: '#FEE2E2', color: '#991B1B', border: '1px solid #FECACA' }, }; export const DRAWER_WIDTH = 216; @@ -42,13 +43,13 @@ export const DRAWER_WIDTH = 216; export const PRIORITY_LABELS: Record = { Standard: 'Standard', Urgent: 'Urgent', - Emergency: 'Emergency Dispatch', + Emergency: 'Emergency', }; export const PRIORITY_CHIP_STYLES: Record = { - Standard: { bgcolor: '#E2E8F0', color: '#334155', border: '1px solid #CBD5E1' }, - Urgent: { bgcolor: '#FFEDD5', color: '#9A3412', border: '1px solid #FDBA74' }, - Emergency: { bgcolor: '#FEE2E2', color: '#991B1B', border: '1px solid #F87171' }, + Standard: { bgcolor: '#F3F4F6', color: '#374151', border: '1px solid #D1D5DB' }, + Urgent: { bgcolor: '#FFEDD5', color: '#9A3412', border: '1px solid #FED7AA' }, + Emergency: { bgcolor: '#FEE2E2', color: '#991B1B', border: '1px solid #FECACA' }, }; export const PRIORITY_ROW_SX: Record = { diff --git a/web/src/pages/admin/dashboard/AdminDashboard.tsx b/web/src/pages/admin/dashboard/AdminDashboard.tsx index 45381c2..40289c4 100644 --- a/web/src/pages/admin/dashboard/AdminDashboard.tsx +++ b/web/src/pages/admin/dashboard/AdminDashboard.tsx @@ -50,13 +50,13 @@ const TAB_STATUSES = ['', 'InReview', 'Approved', 'Sent', 'Revised'] as const; function StatCard({ icon, label, value, color, subtitle }: { icon: React.ReactNode; label: string; value: string; color: string; subtitle?: string }) { return ( - + {icon} {label} - + {value} {subtitle && ( diff --git a/web/src/pages/admin/workspace/AdminWorkspace.tsx b/web/src/pages/admin/workspace/AdminWorkspace.tsx index 20d75f9..7da0db5 100644 --- a/web/src/pages/admin/workspace/AdminWorkspace.tsx +++ b/web/src/pages/admin/workspace/AdminWorkspace.tsx @@ -310,7 +310,7 @@ export default function AdminWorkspace() { component="button" underline="hover" onClick={() => guardedNavigate('/admin')} - sx={{ fontSize: 14, color: '#0B5A73', cursor: 'pointer' }} + sx={{ fontSize: 14, color: '#2563EB', cursor: 'pointer' }} > Admin Queue @@ -452,7 +452,7 @@ export default function AdminWorkspace() { {/* Action Bar */} - + {dirty && ( Unsaved changes diff --git a/web/src/pages/auth/LoginPage.tsx b/web/src/pages/auth/LoginPage.tsx index 20cc749..9f2e7a2 100644 --- a/web/src/pages/auth/LoginPage.tsx +++ b/web/src/pages/auth/LoginPage.tsx @@ -67,7 +67,7 @@ export default function LoginPage() { alignItems: 'center', justifyContent: 'flex-start', pt: '7%', - background: 'linear-gradient(135deg, #073B4C 0%, #172554 100%)', + background: 'linear-gradient(135deg, #111827 0%, #172554 100%)', }} > @@ -79,22 +79,22 @@ export default function LoginPage() { alignItems: 'center', justifyContent: 'center', bgcolor: '#fff', - borderBottom: '1px solid #D6E0EA', + borderBottom: '1px solid #E5E7EB', px: 3, }} > - + Sea Haven Industries @@ -120,7 +120,7 @@ export default function LoginPage() { startIcon={} onClick={() => handleDevLogin('SysAdmin')} disabled={loading} - sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#0B5A73', '&:hover': { bgcolor: '#084A5F' } }} + sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#2563EB', '&:hover': { bgcolor: '#1D4ED8' } }} > SysAdmin @@ -134,7 +134,7 @@ export default function LoginPage() { startIcon={} onClick={() => handleDevLogin('Admin')} disabled={loading} - sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#0B5A73', '&:hover': { bgcolor: '#084A5F' } }} + sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#2563EB', '&:hover': { bgcolor: '#1D4ED8' } }} > Admin @@ -148,7 +148,7 @@ export default function LoginPage() { startIcon={} onClick={() => handleDevLogin('Dispatcher')} disabled={loading} - sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#0B5A73', '&:hover': { bgcolor: '#084A5F' } }} + sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#2563EB', '&:hover': { bgcolor: '#1D4ED8' } }} > Dispatcher @@ -172,7 +172,7 @@ export default function LoginPage() { fullWidth startIcon={} href={buildLoginUrl()} - sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#0B5A73', '&:hover': { bgcolor: '#084A5F' } }} + sx={{ py: 1.5, height: 64, borderRadius: '8px', bgcolor: '#2563EB', '&:hover': { bgcolor: '#1D4ED8' } }} > Sign in with Google diff --git a/web/src/pages/dashboard/Dashboard.tsx b/web/src/pages/dashboard/Dashboard.tsx index 5fd09de..7f3383a 100644 --- a/web/src/pages/dashboard/Dashboard.tsx +++ b/web/src/pages/dashboard/Dashboard.tsx @@ -32,13 +32,13 @@ import { useDocumentTitle } from '../../hooks/useDocumentTitle'; function KpiCard({ icon, label, value, subtitle }: { icon: React.ReactNode; label: string; value: string; subtitle?: string }) { return ( - + - {icon} + {icon} {label} - + {value} {subtitle && ( diff --git a/web/src/pages/proposals/form/ProposalFormPage.tsx b/web/src/pages/proposals/form/ProposalFormPage.tsx index df5548e..eb466b2 100644 --- a/web/src/pages/proposals/form/ProposalFormPage.tsx +++ b/web/src/pages/proposals/form/ProposalFormPage.tsx @@ -176,7 +176,7 @@ export default function ProposalFormPage() { }, [form.workOrderNumber, form.customerAddress, form.serviceCategory, form.scopeOfWork, customCategory]); return ( - + New Proposal Request diff --git a/web/src/theme.ts b/web/src/theme.ts index 6efd302..353e284 100644 --- a/web/src/theme.ts +++ b/web/src/theme.ts @@ -1,53 +1,56 @@ import { createTheme } from '@mui/material/styles'; +// Sea Haven Ops design system — flat, dense, border-driven enterprise UI. +// Neutral navy/slate/gray structure; action-blue #2563EB is the only brand accent. +// Tokens mirror the Sea Haven Ops design bundle (tokens/colors.css, spacing.css, typography.css). export const theme = createTheme({ palette: { primary: { - main: '#0B5A73', - light: '#0E7490', - dark: '#073B4C', + main: '#2563EB', // action blue — primary buttons, links, selected + light: '#3B82F6', + dark: '#1D4ED8', // contained-button hover/pressed contrastText: '#FFFFFF', }, secondary: { - main: '#475569', - light: '#64748B', - dark: '#334155', + main: '#4B5563', // slate-600 + light: '#6B7280', + dark: '#374151', contrastText: '#FFFFFF', }, success: { - main: '#2E7D32', + main: '#16A34A', light: '#DCFCE7', - dark: '#1B5E20', + dark: '#166534', contrastText: '#FFFFFF', }, warning: { - main: '#F97316', + main: '#D97706', // orange — Urgent light: '#FFEDD5', - dark: '#C2410C', + dark: '#9A3412', contrastText: '#FFFFFF', }, error: { - main: '#DC2626', + main: '#DC2626', // red — Emergency / overdue / destructive light: '#FEE2E2', dark: '#991B1B', contrastText: '#FFFFFF', }, info: { - main: '#0284C7', - light: '#E0F2FE', - dark: '#075985', + main: '#2563EB', + light: '#DBEAFE', + dark: '#1E40AF', contrastText: '#FFFFFF', }, background: { - default: '#F4F7FA', + default: '#F3F4F6', // gray-100 page background paper: '#FFFFFF', }, text: { - primary: '#1E293B', - secondary: '#475569', - disabled: '#94A3B8', + primary: '#111827', // navy-900 + secondary: '#4B5563', // slate-600 + disabled: '#9CA3AF', // gray-400 }, - divider: '#E2E8F0', + divider: '#E5E7EB', // gray-200 }, typography: { @@ -60,12 +63,12 @@ export const theme = createTheme({ letterSpacing: '-0.02em', }, h5: { - fontWeight: 700, + fontWeight: 600, fontSize: '18px', lineHeight: 1.3, }, h6: { - fontWeight: 700, + fontWeight: 600, fontSize: '16px', lineHeight: 1.4, }, @@ -85,11 +88,11 @@ export const theme = createTheme({ caption: { fontSize: '12px', lineHeight: 1.35, - color: '#64748B', + color: '#6B7280', }, button: { fontSize: '14px', - fontWeight: 700, + fontWeight: 600, textTransform: 'none' as const, }, overline: { @@ -98,12 +101,12 @@ export const theme = createTheme({ fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase' as const, - color: '#94A3B8', + color: '#6B7280', }, }, shape: { - borderRadius: 8, + borderRadius: 6, }, components: { @@ -111,7 +114,7 @@ export const theme = createTheme({ styleOverrides: { body: { fontFeatureSettings: '"tnum"', - backgroundColor: '#F4F7FA', + backgroundColor: '#F3F4F6', }, }, }, @@ -122,8 +125,9 @@ export const theme = createTheme({ }, styleOverrides: { root: { - backgroundColor: '#073B4C', + backgroundColor: '#111827', // navy-900 boxShadow: 'none', + borderRadius: 0, borderBottom: '1px solid rgba(255,255,255,0.08)', }, }, @@ -133,7 +137,7 @@ export const theme = createTheme({ styleOverrides: { paper: { backgroundColor: '#FFFFFF', - borderRight: '1px solid #DDE3E8', + borderRight: '1px solid #E5E7EB', // border-subtle width: 216, }, }, @@ -144,9 +148,10 @@ export const theme = createTheme({ elevation: 0, }, styleOverrides: { + // Cards are border-driven — no shadow (overlays only). root: { - border: '1px solid #D6E0EA', - boxShadow: '0 1px 2px rgba(15, 23, 42, 0.06)', + border: '1px solid #E5E7EB', + boxShadow: 'none', borderRadius: 8, }, }, @@ -182,10 +187,11 @@ export const theme = createTheme({ }, }, outlined: { - borderColor: '#BFD0DF', + borderColor: '#D1D5DB', // border-default + color: '#111827', '&:hover': { - borderColor: '#0B5A73', - backgroundColor: '#E6F3F7', + borderColor: '#9CA3AF', // border-strong + backgroundColor: '#F9FAFB', // gray-50 }, }, }, @@ -210,13 +216,13 @@ export const theme = createTheme({ borderRadius: 6, minHeight: 38, '& .MuiOutlinedInput-notchedOutline': { - borderColor: '#BFD0DF', + borderColor: '#D1D5DB', }, '&:hover .MuiOutlinedInput-notchedOutline': { - borderColor: '#0E7490', + borderColor: '#9CA3AF', }, '&.Mui-focused .MuiOutlinedInput-notchedOutline': { - borderColor: '#0B5A73', + borderColor: '#2563EB', borderWidth: 2, }, }, @@ -231,9 +237,9 @@ export const theme = createTheme({ styleOverrides: { root: { fontSize: 13, - color: '#64748B', + color: '#6B7280', '&.Mui-focused': { - color: '#0B5A73', + color: '#2563EB', }, }, }, @@ -243,13 +249,13 @@ export const theme = createTheme({ styleOverrides: { root: { '& .MuiTableCell-head': { - color: '#334155', + color: '#374151', // slate-700 fontWeight: 700, fontSize: 13, paddingTop: 12, paddingBottom: 12, - borderBottom: '1px solid #DDE3E8', - backgroundColor: '#F8FAFC', + borderBottom: '1px solid #E5E7EB', + backgroundColor: '#F9FAFB', // gray-50 whiteSpace: 'nowrap', }, }, @@ -259,10 +265,10 @@ export const theme = createTheme({ MuiTableCell: { styleOverrides: { root: { - color: '#1E293B', + color: '#111827', fontSize: 14, padding: '12px 14px', - borderBottom: '1px solid #E2E8F0', + borderBottom: '1px solid #E5E7EB', }, }, }, @@ -271,7 +277,7 @@ export const theme = createTheme({ styleOverrides: { root: { '&:hover': { - backgroundColor: '#F8FAFC', + backgroundColor: '#F9FAFB', }, }, }, @@ -307,17 +313,20 @@ export const theme = createTheme({ marginLeft: 8, marginRight: 8, marginBottom: 4, - color: '#374151', + color: '#4B5563', '&.Mui-selected': { - backgroundColor: '#E6F2F8', - borderLeft: '3px solid #0B80B5', - color: '#1F2933', + backgroundColor: '#EFF6FF', // blue-50 + borderLeft: '3px solid #2563EB', + color: '#111827', + '& .MuiListItemIcon-root': { + color: '#2563EB', + }, '&:hover': { - backgroundColor: '#DCECF5', + backgroundColor: '#DBEAFE', // blue-100 }, }, '&:hover': { - backgroundColor: '#F1F5F9', + backgroundColor: '#F3F4F6', // gray-100 }, }, }, @@ -326,7 +335,7 @@ export const theme = createTheme({ MuiListItemIcon: { styleOverrides: { root: { - color: '#8A949E', + color: '#9CA3AF', // gray-400 — inactive nav icon minWidth: 36, }, }, @@ -336,7 +345,7 @@ export const theme = createTheme({ styleOverrides: { tooltip: { fontSize: 12, - backgroundColor: '#1F2933', + backgroundColor: '#1F2937', // navy-800 }, }, },