feat: dark / light theme almost complete
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 180 KiB |
BIN
frontend/public/images/logos/motovaultpro-logo-title.png
Normal file
BIN
frontend/public/images/logos/motovaultpro-logo-title.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
BIN
frontend/public/images/logos/motovaultpro-title-slogan.png
Normal file
BIN
frontend/public/images/logos/motovaultpro-title-slogan.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 MiB |
@@ -8,9 +8,7 @@ import { Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
|||||||
import { useAuth0 } from '@auth0/auth0-react';
|
import { useAuth0 } from '@auth0/auth0-react';
|
||||||
import { useIsAuthInitialized } from './core/auth/auth-gate';
|
import { useIsAuthInitialized } from './core/auth/auth-gate';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { ThemeProvider } from '@mui/material/styles';
|
import { ThemeProvider } from './shared-minimal/theme/ThemeContext';
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
|
||||||
import { md3Theme } from './shared-minimal/theme/md3Theme';
|
|
||||||
import { Layout } from './components/Layout';
|
import { Layout } from './components/Layout';
|
||||||
import { UnitsProvider } from './core/units/UnitsContext';
|
import { UnitsProvider } from './core/units/UnitsContext';
|
||||||
|
|
||||||
@@ -451,8 +449,7 @@ function App() {
|
|||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
if (mobileMode) {
|
if (mobileMode) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<Layout mobileMode={true}>
|
<Layout mobileMode={true}>
|
||||||
<div className="flex items-center justify-center h-64">
|
<div className="flex items-center justify-center h-64">
|
||||||
<div className="text-slate-500">Loading...</div>
|
<div className="text-slate-500">Loading...</div>
|
||||||
@@ -462,8 +459,7 @@ function App() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Loading...</div>
|
<div className="text-lg">Loading...</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -474,8 +470,7 @@ function App() {
|
|||||||
// Callback route requires authentication - handled by CallbackPage component
|
// Callback route requires authentication - handled by CallbackPage component
|
||||||
if (isCallbackRoute && isAuthenticated) {
|
if (isCallbackRoute && isAuthenticated) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<React.Suspense fallback={
|
<React.Suspense fallback={
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Processing login...</div>
|
<div className="text-lg">Processing login...</div>
|
||||||
@@ -490,8 +485,7 @@ function App() {
|
|||||||
|
|
||||||
if (shouldShowHomePage) {
|
if (shouldShowHomePage) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<HomePage />
|
<HomePage />
|
||||||
<DebugInfo />
|
<DebugInfo />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
@@ -501,8 +495,7 @@ function App() {
|
|||||||
// Signup route is public - no authentication required
|
// Signup route is public - no authentication required
|
||||||
if (isSignupRoute) {
|
if (isSignupRoute) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<React.Suspense fallback={
|
<React.Suspense fallback={
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Loading...</div>
|
<div className="text-lg">Loading...</div>
|
||||||
@@ -519,8 +512,7 @@ function App() {
|
|||||||
// (Auth0 blocks unverified users from logging in)
|
// (Auth0 blocks unverified users from logging in)
|
||||||
if (isVerifyEmailRoute) {
|
if (isVerifyEmailRoute) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<React.Suspense fallback={
|
<React.Suspense fallback={
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Loading...</div>
|
<div className="text-lg">Loading...</div>
|
||||||
@@ -539,8 +531,7 @@ function App() {
|
|||||||
|
|
||||||
if (isOnboardingRoute) {
|
if (isOnboardingRoute) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<React.Suspense fallback={
|
<React.Suspense fallback={
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Loading...</div>
|
<div className="text-lg">Loading...</div>
|
||||||
@@ -559,8 +550,7 @@ function App() {
|
|||||||
console.log('[DEBUG App] Auth gate not ready yet, showing loading state');
|
console.log('[DEBUG App] Auth gate not ready yet, showing loading state');
|
||||||
if (mobileMode) {
|
if (mobileMode) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<Layout mobileMode={true}>
|
<Layout mobileMode={true}>
|
||||||
<div className="flex items-center justify-center h-64">
|
<div className="flex items-center justify-center h-64">
|
||||||
<div className="text-slate-500">Initializing session...</div>
|
<div className="text-slate-500">Initializing session...</div>
|
||||||
@@ -570,8 +560,7 @@ function App() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<div className="text-lg">Initializing session...</div>
|
<div className="text-lg">Initializing session...</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -582,8 +571,7 @@ function App() {
|
|||||||
// Mobile app rendering
|
// Mobile app rendering
|
||||||
if (mobileMode) {
|
if (mobileMode) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<UnitsProvider>
|
<UnitsProvider>
|
||||||
<Layout mobileMode={true}>
|
<Layout mobileMode={true}>
|
||||||
<AnimatePresence mode="popLayout" initial={false}>
|
<AnimatePresence mode="popLayout" initial={false}>
|
||||||
@@ -881,8 +869,7 @@ function App() {
|
|||||||
|
|
||||||
// Desktop app rendering (fallback)
|
// Desktop app rendering (fallback)
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={md3Theme}>
|
<ThemeProvider>
|
||||||
<CssBaseline />
|
|
||||||
<UnitsProvider>
|
<UnitsProvider>
|
||||||
<Layout mobileMode={false}>
|
<Layout mobileMode={false}>
|
||||||
<RouteSuspense>
|
<RouteSuspense>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import React from 'react';
|
|||||||
import { useAuth0 } from '@auth0/auth0-react';
|
import { useAuth0 } from '@auth0/auth0-react';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import { Container, Paper, Typography, Box, IconButton, Avatar } from '@mui/material';
|
import { Container, Paper, Typography, Box, IconButton, Avatar } from '@mui/material';
|
||||||
import { useTheme } from '@mui/material/styles';
|
|
||||||
import DirectionsCarRoundedIcon from '@mui/icons-material/DirectionsCarRounded';
|
import DirectionsCarRoundedIcon from '@mui/icons-material/DirectionsCarRounded';
|
||||||
import LocalGasStationRoundedIcon from '@mui/icons-material/LocalGasStationRounded';
|
import LocalGasStationRoundedIcon from '@mui/icons-material/LocalGasStationRounded';
|
||||||
import BuildRoundedIcon from '@mui/icons-material/BuildRounded';
|
import BuildRoundedIcon from '@mui/icons-material/BuildRounded';
|
||||||
@@ -28,7 +27,6 @@ export const Layout: React.FC<LayoutProps> = ({ children, mobileMode = false })
|
|||||||
const { user, logout } = useAuth0();
|
const { user, logout } = useAuth0();
|
||||||
const { sidebarOpen, toggleSidebar, setSidebarOpen } = useAppStore();
|
const { sidebarOpen, toggleSidebar, setSidebarOpen } = useAppStore();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
// Ensure desktop has a visible navigation by default (only on mount)
|
// Ensure desktop has a visible navigation by default (only on mount)
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -67,7 +65,11 @@ export const Layout: React.FC<LayoutProps> = ({ children, mobileMode = false })
|
|||||||
{/* App header */}
|
{/* App header */}
|
||||||
<div className="px-5 pt-5 pb-3">
|
<div className="px-5 pt-5 pb-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="text-lg font-semibold tracking-tight">MotoVaultPro</div>
|
<img
|
||||||
|
src="/images/logos/motovaultpro-title-slogan.png"
|
||||||
|
alt="MotoVaultPro"
|
||||||
|
className="h-6 w-auto"
|
||||||
|
/>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<NotificationBell />
|
<NotificationBell />
|
||||||
<div className="text-xs text-slate-500">v1.0</div>
|
<div className="text-xs text-slate-500">v1.0</div>
|
||||||
@@ -107,31 +109,31 @@ export const Layout: React.FC<LayoutProps> = ({ children, mobileMode = false })
|
|||||||
flexDirection: 'column'
|
flexDirection: 'column'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Paper
|
<Box
|
||||||
elevation={0}
|
|
||||||
square
|
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
height: 64,
|
height: 64,
|
||||||
px: 3,
|
px: 2,
|
||||||
borderBottom: 1,
|
borderBottom: 1,
|
||||||
borderColor: 'divider',
|
borderColor: 'divider',
|
||||||
borderRadius: 0
|
gap: 1
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h6" sx={{ fontWeight: 700, color: 'primary.main' }}>
|
<img
|
||||||
MotoVaultPro
|
src="/images/logos/motovaultpro-title-slogan.png"
|
||||||
</Typography>
|
alt="MotoVaultPro"
|
||||||
|
style={{ height: 24, width: 'auto', maxWidth: 180 }}
|
||||||
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ color: 'text.secondary' }}
|
sx={{ color: 'text.secondary', flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Paper>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ mt: 3, px: 2, flex: 1 }}>
|
<Box sx={{ mt: 3, px: 2, flex: 1 }}>
|
||||||
{navigation.map((item) => {
|
{navigation.map((item) => {
|
||||||
@@ -152,14 +154,14 @@ export const Layout: React.FC<LayoutProps> = ({ children, mobileMode = false })
|
|||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
transition: 'all 0.2s',
|
transition: 'all 0.2s',
|
||||||
backgroundColor: isActive
|
backgroundColor: isActive
|
||||||
? theme.palette.primary.main + '12'
|
? 'primary.main'
|
||||||
: 'transparent',
|
: 'transparent',
|
||||||
color: isActive
|
color: isActive
|
||||||
? 'primary.main'
|
? '#FFFFFF'
|
||||||
: 'text.primary',
|
: 'text.primary',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: isActive
|
backgroundColor: isActive
|
||||||
? theme.palette.primary.main + '18'
|
? 'primary.dark'
|
||||||
: 'action.hover',
|
: 'action.hover',
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Vehicle</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Vehicle</label>
|
||||||
<select
|
<select
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
value={vehicleID}
|
value={vehicleID}
|
||||||
onChange={(e) => setVehicleID(e.target.value)}
|
onChange={(e) => setVehicleID(e.target.value)}
|
||||||
required
|
required
|
||||||
@@ -175,7 +175,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Document Type</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Document Type</label>
|
||||||
<select
|
<select
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
value={documentType}
|
value={documentType}
|
||||||
onChange={(e) => setDocumentType(e.target.value as DocumentType)}
|
onChange={(e) => setDocumentType(e.target.value as DocumentType)}
|
||||||
>
|
>
|
||||||
@@ -188,7 +188,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col md:col-span-2">
|
<div className="flex flex-col md:col-span-2">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Title</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Title</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
value={title}
|
value={title}
|
||||||
placeholder={
|
placeholder={
|
||||||
@@ -206,7 +206,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Insurance company</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Insurance company</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
value={insuranceCompany}
|
value={insuranceCompany}
|
||||||
onChange={(e) => setInsuranceCompany(e.target.value)}
|
onChange={(e) => setInsuranceCompany(e.target.value)}
|
||||||
@@ -215,7 +215,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Policy number</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Policy number</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
value={policyNumber}
|
value={policyNumber}
|
||||||
onChange={(e) => setPolicyNumber(e.target.value)}
|
onChange={(e) => setPolicyNumber(e.target.value)}
|
||||||
@@ -262,7 +262,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Bodily Injury (Person)</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Bodily Injury (Person)</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="$25,000"
|
placeholder="$25,000"
|
||||||
value={bodilyInjuryPerson}
|
value={bodilyInjuryPerson}
|
||||||
@@ -272,7 +272,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Bodily Injury (Incident)</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Bodily Injury (Incident)</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="$50,000"
|
placeholder="$50,000"
|
||||||
value={bodilyInjuryIncident}
|
value={bodilyInjuryIncident}
|
||||||
@@ -283,7 +283,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Property Damage</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Property Damage</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="$25,000"
|
placeholder="$25,000"
|
||||||
value={propertyDamage}
|
value={propertyDamage}
|
||||||
@@ -293,7 +293,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Premium</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Premium</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
placeholder="0.00"
|
placeholder="0.00"
|
||||||
@@ -309,7 +309,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">License Plate</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">License Plate</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="text"
|
type="text"
|
||||||
value={licensePlate}
|
value={licensePlate}
|
||||||
onChange={(e) => setLicensePlate(e.target.value)}
|
onChange={(e) => setLicensePlate(e.target.value)}
|
||||||
@@ -336,7 +336,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col md:col-span-2">
|
<div className="flex flex-col md:col-span-2">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Cost</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Cost</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 bg-white text-gray-900 border-slate-300 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
placeholder="0.00"
|
placeholder="0.00"
|
||||||
@@ -354,7 +354,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={scanForMaintenance}
|
checked={scanForMaintenance}
|
||||||
onChange={(e) => setScanForMaintenance(e.target.checked)}
|
onChange={(e) => setScanForMaintenance(e.target.checked)}
|
||||||
className="w-5 h-5 rounded border-slate-300 text-primary-600 focus:ring-primary-500"
|
className="w-5 h-5 rounded border-slate-300 text-primary-600 focus:ring-primary-500 dark:border-silverstone dark:focus:ring-abudhabi"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2 text-sm font-medium text-slate-700">
|
<span className="ml-2 text-sm font-medium text-slate-700">
|
||||||
Scan for Maintenance Schedule
|
Scan for Maintenance Schedule
|
||||||
@@ -367,7 +367,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col md:col-span-2">
|
<div className="flex flex-col md:col-span-2">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Notes</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Notes</label>
|
||||||
<textarea
|
<textarea
|
||||||
className="min-h-[88px] rounded-lg border border-slate-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="min-h-[88px] rounded-lg border px-3 py-2 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
value={notes}
|
value={notes}
|
||||||
onChange={(e) => setNotes(e.target.value)}
|
onChange={(e) => setNotes(e.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -376,7 +376,7 @@ export const DocumentForm: React.FC<DocumentFormProps> = ({ onSuccess, onCancel
|
|||||||
<div className="flex flex-col md:col-span-2">
|
<div className="flex flex-col md:col-span-2">
|
||||||
<label className="text-sm font-medium text-slate-700 mb-1">Upload image/PDF</label>
|
<label className="text-sm font-medium text-slate-700 mb-1">Upload image/PDF</label>
|
||||||
<input
|
<input
|
||||||
className="h-11 min-h-[44px] rounded-lg border border-slate-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
className="h-11 min-h-[44px] rounded-lg border px-3 py-2 bg-white text-gray-900 border-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary-500/10 file:text-primary-600 dark:file:bg-abudhabi/20 dark:file:text-abudhabi"
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/jpeg,image/png,application/pdf"
|
accept="image/jpeg,image/png,application/pdf"
|
||||||
onChange={(e) => setFile(e.target.files?.[0] || null)}
|
onChange={(e) => setFile(e.target.files?.[0] || null)}
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</p>
|
</p>
|
||||||
<input
|
<input
|
||||||
{...register('vin')}
|
{...register('vin')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 text-base"
|
className="w-full px-3 py-2 border rounded-md text-base bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
placeholder="Enter 17-character VIN (optional if License Plate provided)"
|
placeholder="Enter 17-character VIN (optional if License Plate provided)"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
/>
|
/>
|
||||||
@@ -438,7 +438,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
const year = parseInt(e.target.value);
|
const year = parseInt(e.target.value);
|
||||||
setValue('year', year);
|
setValue('year', year);
|
||||||
}}
|
}}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
<option value="">Select Year</option>
|
<option value="">Select Year</option>
|
||||||
@@ -461,7 +461,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
const make = e.target.value;
|
const make = e.target.value;
|
||||||
setValue('make', make);
|
setValue('make', make);
|
||||||
}}
|
}}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
disabled={loadingDropdowns || !watchedYear || makes.length === 0}
|
disabled={loadingDropdowns || !watchedYear || makes.length === 0}
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
@@ -493,7 +493,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
const model = e.target.value;
|
const model = e.target.value;
|
||||||
setValue('model', model);
|
setValue('model', model);
|
||||||
}}
|
}}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
disabled={loadingDropdowns || !watchedMake || models.length === 0}
|
disabled={loadingDropdowns || !watchedMake || models.length === 0}
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
@@ -528,7 +528,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
const trim = e.target.value;
|
const trim = e.target.value;
|
||||||
setValue('trimLevel', trim);
|
setValue('trimLevel', trim);
|
||||||
}}
|
}}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
|
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
@@ -556,7 +556,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
{...register('engine')}
|
{...register('engine')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
disabled={loadingDropdowns || !selectedTrim || engines.length === 0}
|
disabled={loadingDropdowns || !selectedTrim || engines.length === 0}
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
@@ -584,7 +584,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
{...register('transmission')}
|
{...register('transmission')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
disabled={loadingDropdowns || !selectedTrim || transmissions.length === 0}
|
disabled={loadingDropdowns || !selectedTrim || transmissions.length === 0}
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
>
|
>
|
||||||
@@ -612,7 +612,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
{...register('nickname')}
|
{...register('nickname')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
placeholder="e.g., Family Car"
|
placeholder="e.g., Family Car"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
/>
|
/>
|
||||||
@@ -625,7 +625,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
{...register('color')}
|
{...register('color')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
placeholder="e.g., Blue"
|
placeholder="e.g., Blue"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
/>
|
/>
|
||||||
@@ -637,7 +637,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
{...register('licensePlate')}
|
{...register('licensePlate')}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
placeholder="e.g., ABC-123 (required if VIN omitted)"
|
placeholder="e.g., ABC-123 (required if VIN omitted)"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
/>
|
/>
|
||||||
@@ -655,7 +655,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
|
|||||||
{...register('odometerReading', { valueAsNumber: true })}
|
{...register('odometerReading', { valueAsNumber: true })}
|
||||||
type="number"
|
type="number"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
|
className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna dark:focus:ring-abudhabi dark:focus:border-abudhabi"
|
||||||
placeholder="e.g., 50000"
|
placeholder="e.g., 50000"
|
||||||
style={{ fontSize: '16px' }}
|
style={{ fontSize: '16px' }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -24,39 +24,45 @@ export const HomePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white">
|
<div className="min-h-screen bg-nero text-avus">
|
||||||
{/* Navigation Bar */}
|
{/* Navigation Bar */}
|
||||||
<nav className="bg-white shadow-md sticky top-0 z-50">
|
<nav className="sticky top-0 z-50 bg-nero/90 backdrop-blur border-b border-white/10">
|
||||||
<div className="max-w-7xl mx-auto px-4 md:px-8">
|
<div className="max-w-7xl mx-auto px-4 md:px-8">
|
||||||
<div className="flex justify-between items-center h-16">
|
<div className="flex justify-between items-center h-16">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<h1 className="text-2xl font-bold text-primary-500">MotoVaultPro</h1>
|
<a href="#home" className="flex items-center">
|
||||||
|
<img
|
||||||
|
src="/images/logos/motovaultpro-title-slogan.png"
|
||||||
|
alt="MotoVaultPro - Precision Vehicle Management"
|
||||||
|
className="h-8 md:h-10 w-auto"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Desktop Menu */}
|
{/* Desktop Menu */}
|
||||||
<div className="hidden md:flex items-center space-x-8">
|
<div className="hidden md:flex items-center space-x-8">
|
||||||
<a href="#home" className="text-gray-700 hover:text-primary-500 transition-colors">
|
<a href="#home" className="text-white/75 hover:text-white transition-colors">
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#features"
|
href="#features"
|
||||||
className="text-gray-700 hover:text-primary-500 transition-colors"
|
className="text-white/75 hover:text-white transition-colors"
|
||||||
>
|
>
|
||||||
Features
|
Features
|
||||||
</a>
|
</a>
|
||||||
<a href="#about" className="text-gray-700 hover:text-primary-500 transition-colors">
|
<a href="#about" className="text-white/75 hover:text-white transition-colors">
|
||||||
About
|
About
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
onClick={handleSignup}
|
onClick={handleSignup}
|
||||||
className="border-2 border-primary-500 text-primary-500 hover:bg-primary-50 font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
|
className="border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 hover:border-primary-500 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
>
|
>
|
||||||
Sign Up
|
Sign Up
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleAuthAction}
|
onClick={handleAuthAction}
|
||||||
className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
|
className="bg-primary-500 hover:bg-primary-600 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
@@ -66,7 +72,7 @@ export const HomePage = () => {
|
|||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<button
|
<button
|
||||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||||
className="text-gray-700 hover:text-primary-500 focus:outline-none"
|
className="text-white/80 hover:text-white focus:outline-none"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
@@ -93,35 +99,35 @@ export const HomePage = () => {
|
|||||||
initial={{ opacity: 0, height: 0 }}
|
initial={{ opacity: 0, height: 0 }}
|
||||||
animate={{ opacity: 1, height: 'auto' }}
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
exit={{ opacity: 0, height: 0 }}
|
exit={{ opacity: 0, height: 0 }}
|
||||||
className="md:hidden py-4 space-y-3"
|
className="md:hidden py-4 space-y-3 bg-nero border-t border-white/10"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="#home"
|
href="#home"
|
||||||
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
|
className="block text-white/75 hover:text-white transition-colors py-2"
|
||||||
>
|
>
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#features"
|
href="#features"
|
||||||
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
|
className="block text-white/75 hover:text-white transition-colors py-2"
|
||||||
>
|
>
|
||||||
Features
|
Features
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="#about"
|
href="#about"
|
||||||
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
|
className="block text-white/75 hover:text-white transition-colors py-2"
|
||||||
>
|
>
|
||||||
About
|
About
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
onClick={handleSignup}
|
onClick={handleSignup}
|
||||||
className="w-full border-2 border-primary-500 text-primary-500 hover:bg-primary-50 font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
|
className="w-full border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
>
|
>
|
||||||
Sign Up
|
Sign Up
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleAuthAction}
|
onClick={handleAuthAction}
|
||||||
className="w-full bg-primary-500 hover:bg-primary-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
|
className="w-full bg-primary-500 hover:bg-primary-600 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
@@ -136,28 +142,31 @@ export const HomePage = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Welcome Section */}
|
{/* Welcome Section */}
|
||||||
<section className="py-16 px-4 md:px-8 bg-white">
|
<section className="py-16 px-4 md:px-8 bg-[#1D1A18] border-t border-white/5">
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<p className="text-primary-500 text-sm font-semibold uppercase tracking-wide mb-4">
|
{/* Full Logo */}
|
||||||
Welcome
|
<div className="mb-8">
|
||||||
</p>
|
<img
|
||||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
|
src="/images/logos/motovaultpro-logo-title.png"
|
||||||
Thank you for your interest in MotoVaultPro!
|
alt="MotoVaultPro - Precision Vehicle Management"
|
||||||
</h2>
|
className="w-[280px] sm:w-[380px] md:w-[520px] lg:w-[620px] max-w-[90vw] h-auto mx-auto"
|
||||||
<p className="text-lg text-gray-600 leading-relaxed mb-8">
|
loading="eager"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-lg text-titanio leading-relaxed mb-8">
|
||||||
We are pleased to provide comprehensive vehicle management solutions including Vehicle
|
We are pleased to provide comprehensive vehicle management solutions including Vehicle
|
||||||
Tracking, Fuel Log Management, Maintenance Records, Document Storage, Service Station
|
Tracking, Fuel Log Management, Maintenance Records, Document Storage, Service Station
|
||||||
Locations, and detailed Analytics for all your vehicles. A combination of these features
|
Locations, and detailed Analytics for all your vehicles. A combination of these features
|
||||||
can create a perfect management system for your fleet. Based on your specific needs, our
|
can create a perfect management system for your fleet. Based on your specific needs, our
|
||||||
platform will help you determine the best approach to managing your vehicles.
|
platform will help you determine the best approach to managing your vehicles.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-lg text-gray-600 leading-relaxed mb-8">
|
<p className="text-lg text-titanio leading-relaxed mb-8">
|
||||||
Do not hesitate to reach out for assistance in creating a custom workflow that best fits
|
Do not hesitate to reach out for assistance in creating a custom workflow that best fits
|
||||||
your needs.
|
your needs.
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={handleAuthAction}
|
onClick={handleAuthAction}
|
||||||
className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300"
|
className="bg-primary-500 hover:bg-primary-600 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
|
||||||
>
|
>
|
||||||
Get Started
|
Get Started
|
||||||
</button>
|
</button>
|
||||||
@@ -165,30 +174,30 @@ export const HomePage = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* About Section */}
|
{/* About Section */}
|
||||||
<section id="about" className="py-16 px-4 md:px-8 bg-gray-100">
|
<section id="about" className="py-16 px-4 md:px-8 bg-nero border-t border-white/5">
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="max-w-6xl mx-auto">
|
||||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-primary-500 uppercase tracking-wide mb-4">
|
<h3 className="text-sm font-semibold text-primary-500 uppercase tracking-wide mb-4">
|
||||||
About Us
|
About Us
|
||||||
</h3>
|
</h3>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
|
<h2 className="text-3xl md:text-4xl font-bold text-avus mb-6">
|
||||||
Overall, our goal is to meet each individual's needs with quality, passion, and
|
Overall, our goal is to meet each individual's needs with quality, passion, and
|
||||||
professionalism.
|
professionalism.
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-gray-600 leading-relaxed mb-6">
|
<p className="text-lg text-titanio leading-relaxed mb-6">
|
||||||
Most importantly, we treat each and every vehicle as if it were our own and strive to
|
Most importantly, we treat each and every vehicle as if it were our own and strive to
|
||||||
achieve perfection in vehicle management. If you are unsure of what you need for your
|
achieve perfection in vehicle management. If you are unsure of what you need for your
|
||||||
vehicles, we are happy to help talk you through the best options for comprehensive
|
vehicles, we are happy to help talk you through the best options for comprehensive
|
||||||
tracking.
|
tracking.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-lg text-gray-600 leading-relaxed">
|
<p className="text-lg text-titanio leading-relaxed">
|
||||||
We are proud to use the finest technology and best practices to provide quality and
|
We are proud to use the finest technology and best practices to provide quality and
|
||||||
satisfaction for our users.
|
satisfaction for our users.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-64 h-64 bg-primary-500 rounded-lg flex items-center justify-center">
|
<div className="w-64 h-64 bg-primary-500 rounded-lg border border-white/10 flex items-center justify-center shadow-lg shadow-black/30">
|
||||||
<div className="text-center text-white p-8">
|
<div className="text-center text-white p-8">
|
||||||
<svg
|
<svg
|
||||||
className="w-32 h-32 mx-auto mb-4"
|
className="w-32 h-32 mx-auto mb-4"
|
||||||
@@ -217,14 +226,14 @@ export const HomePage = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Bottom CTA */}
|
{/* Bottom CTA */}
|
||||||
<section className="py-16 px-4 md:px-8 bg-primary-500 text-white">
|
<section className="py-16 px-4 md:px-8 bg-gradient-to-r from-primary-700 via-primary-500 to-primary-700 text-white border-t border-white/10">
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<h2 className="text-2xl md:text-3xl font-bold mb-6">
|
<h2 className="text-2xl md:text-3xl font-bold mb-6">
|
||||||
We are a cloud-based platform accessible anywhere, anytime.
|
We are a cloud-based platform accessible anywhere, anytime.
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={handleAuthAction}
|
onClick={handleAuthAction}
|
||||||
className="bg-white text-primary-500 hover:bg-gray-100 font-semibold py-3 px-8 rounded-lg transition-colors duration-300"
|
className="bg-white/95 text-primary-500 hover:bg-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30 focus:outline-none focus:ring-2 focus:ring-white/50"
|
||||||
>
|
>
|
||||||
Get Started
|
Get Started
|
||||||
</button>
|
</button>
|
||||||
@@ -232,9 +241,9 @@ export const HomePage = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="bg-gray-900 text-white py-8 px-4 md:px-8">
|
<footer className="bg-black text-white py-8 px-4 md:px-8 border-t border-white/10">
|
||||||
<div className="max-w-7xl mx-auto text-center">
|
<div className="max-w-7xl mx-auto text-center">
|
||||||
<p className="text-gray-400">
|
<p className="text-white/50">
|
||||||
© {new Date().getFullYear()} MotoVaultPro. All rights reserved.
|
© {new Date().getFullYear()} MotoVaultPro. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const FeatureCard = ({ title, description, imageSrc, imageAlt }: FeatureC
|
|||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.5 }}
|
||||||
whileHover={{ y: -5 }}
|
whileHover={{ y: -5 }}
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-lg shadow-lg hover:shadow-xl transition-shadow duration-300">
|
<div className="overflow-hidden rounded-lg bg-white/5 border border-white/10 shadow-lg shadow-black/30 hover:border-white/20 hover:shadow-xl hover:shadow-black/40 transition-all duration-300">
|
||||||
<div className="relative h-56 overflow-hidden">
|
<div className="relative h-56 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={imageSrc}
|
src={imageSrc}
|
||||||
@@ -25,9 +25,9 @@ export const FeatureCard = ({ title, description, imageSrc, imageAlt }: FeatureC
|
|||||||
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
|
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-6">
|
<div className="p-6">
|
||||||
<h3 className="text-xl font-bold text-gray-900 mb-2">{title}</h3>
|
<h3 className="text-xl font-bold text-avus mb-2">{title}</h3>
|
||||||
<p className="text-gray-600 leading-relaxed">{description}</p>
|
<p className="text-titanio leading-relaxed">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -53,13 +53,13 @@ const features = [
|
|||||||
|
|
||||||
export const FeaturesGrid = () => {
|
export const FeaturesGrid = () => {
|
||||||
return (
|
return (
|
||||||
<section className="py-16 px-4 md:px-8 bg-gray-50">
|
<section className="py-16 px-4 md:px-8 bg-[#1D1A18] border-t border-white/5">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<p className="text-primary-500 text-sm font-semibold uppercase tracking-wide mb-2">
|
<p className="text-primary-500 text-sm font-semibold uppercase tracking-wide mb-2">
|
||||||
Our Features
|
Our Features
|
||||||
</p>
|
</p>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold text-gray-900">What We Offer</h2>
|
<h2 className="text-3xl md:text-4xl font-bold text-avus">What We Offer</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
@@ -69,7 +69,7 @@ export const FeaturesGrid = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-center mt-12">
|
<div className="text-center mt-12">
|
||||||
<p className="text-lg text-gray-600 mb-6">
|
<p className="text-lg text-titanio mb-6">
|
||||||
We are a cloud-based platform accessible anywhere, anytime.
|
We are a cloud-based platform accessible anywhere, anytime.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -71,17 +71,6 @@ export const HeroCarousel = () => {
|
|||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/40 to-black/60" />
|
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/40 to-black/60" />
|
||||||
<div className="absolute inset-0 flex flex-col items-center justify-center text-center px-4">
|
|
||||||
<p className="text-white text-sm md:text-base font-semibold uppercase tracking-widest mb-4">
|
|
||||||
Welcome to
|
|
||||||
</p>
|
|
||||||
<h1 className="text-white text-4xl md:text-6xl lg:text-7xl font-bold mb-6 leading-tight">
|
|
||||||
MOTOVAULTPRO
|
|
||||||
</h1>
|
|
||||||
<button className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300">
|
|
||||||
Learn More
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -121,12 +110,12 @@ export const HeroCarousel = () => {
|
|||||||
.hero-carousel .slick-prev:before,
|
.hero-carousel .slick-prev:before,
|
||||||
.hero-carousel .slick-next:before {
|
.hero-carousel .slick-next:before {
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
opacity: 0.75;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-carousel .slick-prev:hover:before,
|
.hero-carousel .slick-prev:hover:before,
|
||||||
.hero-carousel .slick-next:hover:before {
|
.hero-carousel .slick-next:hover:before {
|
||||||
opacity: 1;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useUnits } from '../core/units/UnitsContext';
|
import { useUnits } from '../core/units/UnitsContext';
|
||||||
import { useAdminAccess } from '../core/auth/useAdminAccess';
|
import { useAdminAccess } from '../core/auth/useAdminAccess';
|
||||||
import { useProfile, useUpdateProfile } from '../features/settings/hooks/useProfile';
|
import { useProfile, useUpdateProfile } from '../features/settings/hooks/useProfile';
|
||||||
|
import { useTheme } from '../shared-minimal/theme/ThemeContext';
|
||||||
import { DeleteAccountDialog } from '../features/settings/components/DeleteAccountDialog';
|
import { DeleteAccountDialog } from '../features/settings/components/DeleteAccountDialog';
|
||||||
import { PendingDeletionBanner } from '../features/settings/components/PendingDeletionBanner';
|
import { PendingDeletionBanner } from '../features/settings/components/PendingDeletionBanner';
|
||||||
import {
|
import {
|
||||||
@@ -44,9 +45,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { unitSystem, setUnitSystem } = useUnits();
|
const { unitSystem, setUnitSystem } = useUnits();
|
||||||
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
||||||
|
const { isDarkMode, setDarkMode } = useTheme();
|
||||||
const [notifications, setNotifications] = useState(true);
|
const [notifications, setNotifications] = useState(true);
|
||||||
const [emailUpdates, setEmailUpdates] = useState(false);
|
const [emailUpdates, setEmailUpdates] = useState(false);
|
||||||
const [darkMode, setDarkMode] = useState(false);
|
|
||||||
|
|
||||||
// Profile state
|
// Profile state
|
||||||
const { data: profile, isLoading: profileLoading } = useProfile();
|
const { data: profile, isLoading: profileLoading } = useProfile();
|
||||||
@@ -314,7 +315,7 @@ export const SettingsPage: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Switch
|
<Switch
|
||||||
checked={darkMode}
|
checked={isDarkMode}
|
||||||
onChange={(e) => setDarkMode(e.target.checked)}
|
onChange={(e) => setDarkMode(e.target.checked)}
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
|
|||||||
140
frontend/src/shared-minimal/theme/ThemeContext.tsx
Normal file
140
frontend/src/shared-minimal/theme/ThemeContext.tsx
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* @ai-summary Theme context for managing light/dark mode across the app
|
||||||
|
* Uses same localStorage key as useSettings for consistency
|
||||||
|
* Applies Tailwind dark class to document root
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createContext, useContext, useEffect, useMemo, useState, useCallback, ReactNode } from 'react';
|
||||||
|
import { ThemeProvider as MuiThemeProvider, Theme } from '@mui/material/styles';
|
||||||
|
import { CssBaseline } from '@mui/material';
|
||||||
|
import { md3LightTheme, md3DarkTheme } from './md3Theme';
|
||||||
|
|
||||||
|
// Same storage key as useSettingsPersistence for consistency
|
||||||
|
const SETTINGS_STORAGE_KEY = 'motovaultpro-mobile-settings';
|
||||||
|
|
||||||
|
interface ThemeContextValue {
|
||||||
|
isDarkMode: boolean;
|
||||||
|
toggleDarkMode: () => void;
|
||||||
|
setDarkMode: (value: boolean) => void;
|
||||||
|
theme: Theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
|
||||||
|
|
||||||
|
interface ThemeProviderProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read dark mode preference from localStorage (synced with useSettings)
|
||||||
|
const getStoredDarkMode = (): boolean => {
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem(SETTINGS_STORAGE_KEY);
|
||||||
|
if (stored) {
|
||||||
|
const settings = JSON.parse(stored);
|
||||||
|
return settings.darkMode ?? false;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore parse errors
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update dark mode in localStorage while preserving other settings
|
||||||
|
const setStoredDarkMode = (darkMode: boolean): void => {
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem(SETTINGS_STORAGE_KEY);
|
||||||
|
const settings = stored ? JSON.parse(stored) : {};
|
||||||
|
settings.darkMode = darkMode;
|
||||||
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
||||||
|
} catch {
|
||||||
|
// Ignore storage errors
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ThemeProvider = ({ children }: ThemeProviderProps) => {
|
||||||
|
const [isDarkMode, setIsDarkMode] = useState<boolean>(getStoredDarkMode);
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
|
|
||||||
|
// Initialize on mount
|
||||||
|
useEffect(() => {
|
||||||
|
setIsDarkMode(getStoredDarkMode());
|
||||||
|
setIsInitialized(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Apply dark class to document root for Tailwind
|
||||||
|
useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
if (isDarkMode) {
|
||||||
|
root.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
root.classList.remove('dark');
|
||||||
|
}
|
||||||
|
}, [isDarkMode]);
|
||||||
|
|
||||||
|
// Listen for storage changes from other tabs/components
|
||||||
|
useEffect(() => {
|
||||||
|
const handleStorageChange = (e: StorageEvent) => {
|
||||||
|
if (e.key === SETTINGS_STORAGE_KEY && e.newValue) {
|
||||||
|
try {
|
||||||
|
const settings = JSON.parse(e.newValue);
|
||||||
|
if (typeof settings.darkMode === 'boolean') {
|
||||||
|
setIsDarkMode(settings.darkMode);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore parse errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('storage', handleStorageChange);
|
||||||
|
return () => window.removeEventListener('storage', handleStorageChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setDarkMode = useCallback((value: boolean) => {
|
||||||
|
setIsDarkMode(value);
|
||||||
|
setStoredDarkMode(value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toggleDarkMode = useCallback(() => {
|
||||||
|
setDarkMode(!isDarkMode);
|
||||||
|
}, [isDarkMode, setDarkMode]);
|
||||||
|
|
||||||
|
const theme = useMemo(() => {
|
||||||
|
return isDarkMode ? md3DarkTheme : md3LightTheme;
|
||||||
|
}, [isDarkMode]);
|
||||||
|
|
||||||
|
const value = useMemo(
|
||||||
|
() => ({
|
||||||
|
isDarkMode,
|
||||||
|
toggleDarkMode,
|
||||||
|
setDarkMode,
|
||||||
|
theme,
|
||||||
|
}),
|
||||||
|
[isDarkMode, toggleDarkMode, setDarkMode, theme]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Prevent flash of wrong theme during SSR/initial load
|
||||||
|
if (!isInitialized) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={value}>
|
||||||
|
<MuiThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
{children}
|
||||||
|
</MuiThemeProvider>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTheme = (): ThemeContextValue => {
|
||||||
|
const context = useContext(ThemeContext);
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error('useTheme must be used within a ThemeProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Re-export for convenience
|
||||||
|
export { md3LightTheme, md3DarkTheme } from './md3Theme';
|
||||||
@@ -1,26 +1,20 @@
|
|||||||
/**
|
/**
|
||||||
* @ai-summary Material Design 3 theme configuration for MotoVaultPro
|
* @ai-summary Material Design 3 theme configuration for MotoVaultPro
|
||||||
|
* Supports both light and dark modes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createTheme, alpha } from '@mui/material/styles';
|
import { createTheme, alpha, ThemeOptions } from '@mui/material/styles';
|
||||||
|
|
||||||
// Brand color from mockup
|
// Brand colors
|
||||||
const primaryHex = '#7A212A';
|
const primaryHex = '#7A212A';
|
||||||
|
|
||||||
export const md3Theme = createTheme({
|
// Dark theme palette (Ferrari-inspired)
|
||||||
palette: {
|
const nero = '#231F1C'; // Nero Daytona - page base
|
||||||
mode: 'light',
|
const avus = '#F2F3F6'; // Bianco Avus - primary text
|
||||||
primary: {
|
const titanio = '#A8B8C0'; // Grigio Titanio - secondary text
|
||||||
main: primaryHex
|
|
||||||
},
|
// Shared theme options
|
||||||
secondary: {
|
const baseThemeOptions: ThemeOptions = {
|
||||||
main: alpha(primaryHex, 0.8)
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
default: '#F8F5F3',
|
|
||||||
paper: '#FFFFFF'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
shape: {
|
shape: {
|
||||||
borderRadius: 16
|
borderRadius: 16
|
||||||
},
|
},
|
||||||
@@ -37,8 +31,6 @@ export const md3Theme = createTheme({
|
|||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
boxShadow:
|
|
||||||
'0 1px 2px rgba(16,24,40,.04), 0 4px 16px rgba(16,24,40,.06)',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -71,15 +63,6 @@ export const md3Theme = createTheme({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
MuiBottomNavigation: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
borderTop: '1px solid rgba(16,24,40,.08)',
|
|
||||||
background: alpha('#FFFFFF', 0.8),
|
|
||||||
backdropFilter: 'blur(8px)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiBottomNavigationAction: {
|
MuiBottomNavigationAction: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
root: {
|
root: {
|
||||||
@@ -93,4 +76,85 @@ export const md3Theme = createTheme({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Light theme
|
||||||
|
export const md3LightTheme = createTheme({
|
||||||
|
...baseThemeOptions,
|
||||||
|
palette: {
|
||||||
|
mode: 'light',
|
||||||
|
primary: { main: primaryHex },
|
||||||
|
secondary: { main: alpha(primaryHex, 0.8) },
|
||||||
|
background: {
|
||||||
|
default: '#F8F5F3',
|
||||||
|
paper: '#FFFFFF'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: '#1a1a1a',
|
||||||
|
secondary: '#666666',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
...baseThemeOptions.components,
|
||||||
|
MuiCard: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: 20,
|
||||||
|
boxShadow: '0 1px 2px rgba(16,24,40,.04), 0 4px 16px rgba(16,24,40,.06)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiBottomNavigation: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderTop: '1px solid rgba(16,24,40,.08)',
|
||||||
|
background: alpha('#FFFFFF', 0.8),
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Dark theme
|
||||||
|
export const md3DarkTheme = createTheme({
|
||||||
|
...baseThemeOptions,
|
||||||
|
palette: {
|
||||||
|
mode: 'dark',
|
||||||
|
primary: { main: primaryHex },
|
||||||
|
secondary: { main: alpha(primaryHex, 0.8) },
|
||||||
|
background: {
|
||||||
|
default: nero,
|
||||||
|
paper: '#1D1A18'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: avus,
|
||||||
|
secondary: titanio,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
...baseThemeOptions.components,
|
||||||
|
MuiCard: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: 20,
|
||||||
|
boxShadow: '0 1px 2px rgba(0,0,0,.2), 0 4px 16px rgba(0,0,0,.3)',
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.05)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.1)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiBottomNavigation: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderTop: '1px solid rgba(255,255,255,.1)',
|
||||||
|
background: alpha(nero, 0.9),
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Default export for backward compatibility
|
||||||
|
export const md3Theme = md3LightTheme;
|
||||||
|
|||||||
@@ -4,23 +4,41 @@ export default {
|
|||||||
"./index.html",
|
"./index.html",
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
|
darkMode: 'class',
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
|
// Primary color scale (Rosso Mugello based)
|
||||||
primary: {
|
primary: {
|
||||||
50: '#eff6ff',
|
50: '#fdf2f3',
|
||||||
|
100: '#fce4e6',
|
||||||
|
200: '#f9cdd1',
|
||||||
|
300: '#f4a5ad',
|
||||||
|
400: '#ec717e',
|
||||||
500: '#7A212A',
|
500: '#7A212A',
|
||||||
600: '#7A212A',
|
600: '#6a1c24',
|
||||||
700: '#9c2a36',
|
700: '#5a171e',
|
||||||
|
800: '#4a1318',
|
||||||
|
900: '#3a0f12',
|
||||||
},
|
},
|
||||||
gray: {
|
gray: {
|
||||||
850: '#18202f',
|
850: '#18202f',
|
||||||
},
|
},
|
||||||
|
// Dark theme tokens (Ferrari-inspired palette)
|
||||||
|
nero: '#231F1C', // Nero Daytona - page base
|
||||||
|
avus: '#F2F3F6', // Bianco Avus - primary text on dark
|
||||||
|
titanio: '#A8B8C0', // Grigio Titanio - secondary text on dark
|
||||||
|
canna: '#7E8792', // Canna Di Fucile - placeholder text
|
||||||
|
scuro: '#4C4E4D', // Grigio Scuro - input backgrounds
|
||||||
|
silverstone: '#585C64', // Grigio Silverstone - input borders
|
||||||
|
abudhabi: '#2885B5', // Blu Abu Dhabi - focus rings
|
||||||
|
// Legacy aliases
|
||||||
'moto-red': '#7A212A',
|
'moto-red': '#7A212A',
|
||||||
'moto-red-light': '#9c2a36',
|
'moto-red-light': '#9c2a36',
|
||||||
},
|
},
|
||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
'gradient-moto': 'linear-gradient(90deg, #7A212A, #9c2a36)',
|
'gradient-moto': 'linear-gradient(90deg, #7A212A, #9c2a36)',
|
||||||
|
'gradient-cta': 'linear-gradient(90deg, #5a171e 0%, #7A212A 50%, #5a171e 100%)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
motovaultpro-vehicle-darkpatch.zip
Normal file
BIN
motovaultpro-vehicle-darkpatch.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user