diff --git a/index.html b/index.html index 93d32c5..f27d0e4 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + Dashfront diff --git a/package-lock.json b/package-lock.json index 4838b4e..331ee24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "@mui/material": "^9.1.2", "notistack": "^3.0.2", "react": "^19.2.7", - "react-dom": "^19.2.7" + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.0" }, "devDependencies": { "@vitejs/plugin-react": "^6.0.2", @@ -1036,6 +1037,19 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -1772,6 +1786,44 @@ "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", "license": "MIT" }, + "node_modules/react-router": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz", + "integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz", + "integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==", + "license": "MIT", + "dependencies": { + "react-router": "7.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -1858,6 +1910,12 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", diff --git a/package.json b/package.json index c1e722a..251e10e 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "@mui/material": "^9.1.2", "notistack": "^3.0.2", "react": "^19.2.7", - "react-dom": "^19.2.7" + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.0" }, "devDependencies": { "@vitejs/plugin-react": "^6.0.2", diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..d713658 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,12 @@ + + + D + diff --git a/src/App.jsx b/src/App.jsx index 56da491..cd85405 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,10 +1,12 @@ import Box from '@mui/material/Box'; import CircularProgress from '@mui/material/CircularProgress'; +import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; import { useAuth } from './auth/useAuth'; import LoginPage from './components/LoginPage'; import AppShell from './components/AppShell'; +import SectionPage from './pages/SectionPage'; +import { NAV_ITEMS } from './nav'; -// Top-level router by auth status. Kept tiny so it rarely re-renders. export default function App() { const { status } = useAuth(); @@ -23,5 +25,28 @@ export default function App() { ); } - return status === 'authed' ? : ; + if (status !== 'authed') { + return ; + } + + return ( + + + }> + {NAV_ITEMS.map(({ path, label }) => + path === '/' ? ( + } /> + ) : ( + } + /> + ), + )} + } /> + + + + ); } diff --git a/src/components/AppShell.jsx b/src/components/AppShell.jsx index 9376bb1..85635b7 100644 --- a/src/components/AppShell.jsx +++ b/src/components/AppShell.jsx @@ -1,21 +1,15 @@ -import { useState } from 'react'; import Box from '@mui/material/Box'; import List from '@mui/material/List'; import ListItemButton from '@mui/material/ListItemButton'; import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemText from '@mui/material/ListItemText'; +import { NavLink, Outlet } from 'react-router-dom'; import UserMenu from './UserMenu'; import { NAV_ITEMS } from '../nav'; const SIDEBAR_WIDTH = 240; -// App layout. State lives in the children (UserMenu, page content) so the -// shell itself does not re-render when their state changes. export default function AppShell() { - const [activeId, setActiveId] = useState(NAV_ITEMS[0].id); - const activeItem = NAV_ITEMS.find((item) => item.id === activeId) ?? NAV_ITEMS[0]; - const ActivePage = activeItem.Page; - return ( - {NAV_ITEMS.map(({ id, label, icon: Icon }) => ( + {NAV_ITEMS.map(({ path, label, icon: Icon }) => ( setActiveId(id)} - sx={{ borderRadius: 0, px: 2 }} + key={path} + component={NavLink} + to={path} + end={path === '/'} + sx={{ + borderRadius: 0, + px: 2, + '&.active': { bgcolor: 'action.selected' }, + }} > @@ -49,7 +47,7 @@ export default function AppShell() { - + ); diff --git a/src/components/PageLayout.jsx b/src/components/PageLayout.jsx new file mode 100644 index 0000000..2fd8f70 --- /dev/null +++ b/src/components/PageLayout.jsx @@ -0,0 +1,13 @@ +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; + +export default function PageLayout({ title, children }) { + return ( + + + {title} + + {children} + + ); +} diff --git a/src/nav.js b/src/nav.js index 158494b..b5d8495 100644 --- a/src/nav.js +++ b/src/nav.js @@ -1,11 +1,15 @@ -import DashboardIcon from '@mui/icons-material/Dashboard'; -import DashboardPage from './pages/DashboardPage'; +import HomeIcon from '@mui/icons-material/Home'; +import Inventory2Icon from '@mui/icons-material/Inventory2'; +import LocalShippingIcon from '@mui/icons-material/LocalShipping'; +import AssignmentIcon from '@mui/icons-material/Assignment'; +import PeopleIcon from '@mui/icons-material/People'; +import InfoIcon from '@mui/icons-material/Info'; export const NAV_ITEMS = [ - { - id: 'dashboard', - label: 'Dashboard', - icon: DashboardIcon, - Page: DashboardPage, - }, + { path: '/', label: 'Home', icon: HomeIcon }, + { path: '/artikel', label: 'Artikel', icon: Inventory2Icon }, + { path: '/lieferung', label: 'Lieferung', icon: LocalShippingIcon }, + { path: '/auftrag', label: 'Auftrag', icon: AssignmentIcon }, + { path: '/kunde', label: 'Kunde', icon: PeopleIcon }, + { path: '/infos', label: 'Infos', icon: InfoIcon }, ]; diff --git a/src/pages/DashboardPage.jsx b/src/pages/DashboardPage.jsx deleted file mode 100644 index 09dc9a3..0000000 --- a/src/pages/DashboardPage.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import Typography from '@mui/material/Typography'; - -export default function DashboardPage() { - return ( - - Dashboard - - ); -} diff --git a/src/pages/SectionPage.jsx b/src/pages/SectionPage.jsx new file mode 100644 index 0000000..448f217 --- /dev/null +++ b/src/pages/SectionPage.jsx @@ -0,0 +1,10 @@ +import Typography from '@mui/material/Typography'; +import PageLayout from '../components/PageLayout'; + +export default function SectionPage({ title }) { + return ( + + Inhalt folgt. + + ); +}