// App.tsx — Material Design 3 styled prototype for MotoVaultPro (MUI v5) // Install deps (npm): // npm install @mui/material @emotion/react @emotion/styled @mui/icons-material // This file is TypeScript-friendly (tsx) but also works in plain React projects if the tooling supports TS. import * as React from "react"; import { useEffect, useMemo, useState } from "react"; import { ThemeProvider, createTheme, alpha } from "@mui/material/styles"; import CssBaseline from "@mui/material/CssBaseline"; // <-- FIX: import from @mui/material, not styles import { Box, Container, Typography, Card, CardContent, CardActionArea, Button, Grid, Divider, BottomNavigation, BottomNavigationAction, Select, MenuItem, FormControl, InputLabel, TextField, ToggleButtonGroup, ToggleButton, } from "@mui/material"; import HomeRoundedIcon from "@mui/icons-material/HomeRounded"; import DirectionsCarRoundedIcon from "@mui/icons-material/DirectionsCarRounded"; import LocalGasStationRoundedIcon from "@mui/icons-material/LocalGasStationRounded"; import SettingsRoundedIcon from "@mui/icons-material/SettingsRounded"; // ---- Theme (Material Design 3-inspired) ---- const primaryHex = "#7A212A"; // brand color const theme = createTheme({ palette: { mode: "light", primary: { main: primaryHex }, secondary: { main: alpha(primaryHex, 0.8) }, background: { default: "#F8F5F3", paper: "#FFFFFF" }, }, shape: { borderRadius: 16 }, typography: { fontFamily: "Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif", h3: { fontWeight: 700, letterSpacing: -0.5 }, }, components: { MuiCard: { styleOverrides: { root: { borderRadius: 20, boxShadow: "0 1px 2px rgba(16,24,40,.04), 0 4px 16px rgba(16,24,40,.06)", }, }, }, MuiButton: { variants: [ // Custom MD3-like "tonal" button { // TS note: We define a custom variant name, which runtime supports via props match, // but TypeScript doesn't know it by default. We handle that at usage with `as any`. props: { variant: "tonal" as any }, style: ({ theme }) => ({ backgroundColor: alpha(theme.palette.primary.main, 0.12), color: theme.palette.primary.main, borderRadius: 999, textTransform: "none", fontWeight: 600, paddingInline: 18, "&:hover": { backgroundColor: alpha(theme.palette.primary.main, 0.18) }, }), }, { props: { variant: "contained" }, style: ({ theme }) => ({ borderRadius: 999, textTransform: "none", fontWeight: 700, paddingInline: 20, boxShadow: "0 8px 24px " + alpha(theme.palette.primary.main, 0.25), }), }, ], }, MuiBottomNavigation: { styleOverrides: { root: { borderTop: "1px solid rgba(16,24,40,.08)", background: alpha("#FFFFFF", 0.8), backdropFilter: "blur(8px)", }, }, }, MuiBottomNavigationAction: { styleOverrides: { root: { minWidth: 0, paddingTop: 8, paddingBottom: 8, "&.Mui-selected": { color: primaryHex }, }, }, }, }, }); // ---- Types ---- export type Vehicle = { id: number; year: number; make: string; model: string; image?: string; }; const vehiclesSeed: Vehicle[] = [ { id: 1, year: 2021, make: "Chevrolet", model: "Malibu" }, { id: 2, year: 2019, make: "Toyota", model: "Camry" }, { id: 3, year: 2018, make: "Ford", model: "F-150" }, { id: 4, year: 2022, make: "Honda", model: "CR‑V" }, ]; // ---- Reusable bits ---- const Spark = ({ points = [3, 5, 4, 6, 5, 7, 6] as number[], color = primaryHex, }) => { const width = 120; const height = 36; const max = Math.max(...points); const min = Math.min(...points); const path = points .map((v, i) => { const x = (i / (points.length - 1)) * width; const y = height - ((v - min) / (max - min || 1)) * height; return `${i === 0 ? "M" : "L"}${x},${y}`; }) .join(" "); return ( ); }; const VehicleCard = ({ v, onClick, }: { v: Vehicle; onClick?: (v: Vehicle) => void; }) => ( onClick?.(v)}> {v.make} {v.model} {v.year} ); // ---- Screens ---- const Dashboard = ({ recent }: { recent: Vehicle[] }) => ( Dashboard Recent Vehicles {recent.map((v) => ( ))} Fuel Spent This Month $134.22 Average Price $3.69/gal ); const Vehicles = ({ vehicles, onOpen, }: { vehicles: Vehicle[]; onOpen: (v: Vehicle) => void; }) => ( Vehicles {vehicles.map((v) => ( ))} ); const VehicleDetail = ({ v, onBack }: { v: Vehicle; onBack: () => void }) => ( {v.make} {v.model} Fuel Logs Apr 24 15,126 mi Mar 13 14,300 mi Jan 10 14,055 mi ); const LogFuel = ({ vehicles }: { vehicles: Vehicle[] }) => { const [vehicleId, setVehicleId] = useState(vehicles[0]?.id || 1); const [date, setDate] = useState(new Date().toISOString().slice(0, 10)); const [odo, setOdo] = useState(15126); const [qty, setQty] = useState(12.5); const [price, setPrice] = useState(3.79); const handleSave = () => { alert(`Saved fuel log for vehicle ${vehicleId}`); }; return ( Log Fuel Vehicle setDate(e.target.value)} InputLabelProps={{ shrink: true }} /> setOdo(Number(e.target.value))} /> setQty(Number(e.target.value))} /> setPrice(Number(e.target.value))} /> ); }; const Settings = () => { const [distance, setDistance] = useState("mi"); const [fuel, setFuel] = useState("gal"); return ( Settings Distance v && setDistance(v)} sx={{ mb: 3 }} > Miles Kilometers Fuel v && setFuel(v)} > U.S. Gallons Liters ); }; // ---- (Dev) Runtime smoke tests ---- const DevTests = () => { useEffect(() => { console.assert(!!ThemeProvider, "ThemeProvider should be available"); console.assert(typeof createTheme === "function", "createTheme should be a function"); console.assert(!!CssBaseline, "CssBaseline should be importable from @mui/material"); console.log("[DevTests] Basic runtime checks passed."); }, []); return null; }; // ---- Root App with bottom nav ---- export default function App() { const [tab, setTab] = useState(0); // 0: Dashboard, 1: Vehicles, 2: Log Fuel, 3: Settings const [open, setOpen] = useState(null); const recent = useMemo(() => vehiclesSeed.slice(0, 2), []); return ( {tab === 0 && } {tab === 1 && (open ? ( setOpen(null)} /> ) : ( ))} {tab === 2 && } {tab === 3 && } setTab(v)} sx={{ position: "sticky", bottom: 0, mt: 2 }} > } /> } /> } /> } /> ); }