Dark/Light Mode Implementierung mit MUI Theme
This commit is contained in:
2936
01-frontend/package-lock.json
generated
2936
01-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^7.0.2",
|
||||
"@mui/material": "^7.0.2",
|
||||
"@mui/icons-material": "^7.1.0",
|
||||
"@mui/material": "^7.1.0",
|
||||
"i18next": "^25.2.0",
|
||||
"i18next-browser-languagedetector": "^8.1.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
@@ -22,7 +22,8 @@
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-router-dom": "^7.5.3"
|
||||
"react-router-dom": "^7.5.3",
|
||||
"webshop": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
#root {
|
||||
width: 100%;
|
||||
/* App.css - CSS-Variablen-basierte Version */
|
||||
:root {
|
||||
--background-color: #fafafa;
|
||||
--text-color: #000000;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: var(--background-color) !important;
|
||||
color: var(--text-color) !important;
|
||||
transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: var(--background-color) !important;
|
||||
color: var(--text-color) !important;
|
||||
transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Rest Ihrer Styles ohne feste Farben */
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
@@ -32,12 +53,13 @@
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.navbar-offset {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||
import { StyledEngineProvider } from '@mui/material/styles';
|
||||
import './App.css';
|
||||
import NavBar from './helper/navbar/NavBar';
|
||||
import Home from './pages/Home';
|
||||
@@ -9,39 +10,32 @@ import Payment from './pages/Payment';
|
||||
import Contact from './pages/Contact';
|
||||
import Category from './pages/Category';
|
||||
import { BasketProvider } from './helper/BasketProvider';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import { green } from '@mui/material/colors';
|
||||
import { CustomThemeProvider } from './theme/ThemeContext';
|
||||
import Orders from './pages/Orders';
|
||||
import Account from './pages/Account';
|
||||
|
||||
export default function App() {
|
||||
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: green[500],
|
||||
},
|
||||
},});
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<BasketProvider>
|
||||
<BrowserRouter>
|
||||
<NavBar />
|
||||
<div className='navbar-offset' />
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="*" element={<NoPage />} />
|
||||
<Route path="/product/:id" element={<Product />} />
|
||||
<Route path="/checkout" element={<Payment />} />
|
||||
<Route path="/categories" element={<Category />} />
|
||||
<Route path="/contact" element={<Contact />} />
|
||||
<Route path='/account' element={<Account />} />
|
||||
<Route path='/orders' element={<Orders />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</BasketProvider>
|
||||
</ThemeProvider>
|
||||
<StyledEngineProvider injectFirst>
|
||||
<CustomThemeProvider>
|
||||
<BasketProvider>
|
||||
<BrowserRouter>
|
||||
<NavBar />
|
||||
<div className='navbar-offset' />
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="*" element={<NoPage />} />
|
||||
<Route path="/product/:id" element={<Product />} />
|
||||
<Route path="/checkout" element={<Payment />} />
|
||||
<Route path="/categories" element={<Category />} />
|
||||
<Route path="/contact" element={<Contact />} />
|
||||
<Route path='/account' element={<Account />} />
|
||||
<Route path='/orders' element={<Orders />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</BasketProvider>
|
||||
</CustomThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,25 +15,26 @@ import AdbIcon from '@mui/icons-material/Adb';
|
||||
import { alpha, InputBase, styled } from '@mui/material';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import './NavBar.css';
|
||||
import ThemeToggle from '../../theme/ThemeToggle';
|
||||
|
||||
const Search = styled('div')(({ theme }) => ({
|
||||
position: 'relative',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.15),
|
||||
'&:hover': {
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||
},
|
||||
marginLeft: 0,
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
marginLeft: theme.spacing(1),
|
||||
width: 'auto',
|
||||
marginLeft: theme.spacing(1),
|
||||
width: 'auto',
|
||||
},
|
||||
}));
|
||||
}));
|
||||
|
||||
const SearchIconWrapper = styled('div')(({ theme }) => ({
|
||||
const SearchIconWrapper = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
@@ -41,27 +42,25 @@ const Search = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}));
|
||||
}));
|
||||
|
||||
const StyledInputBase = styled(InputBase)(({ theme }) => ({
|
||||
const StyledInputBase = styled(InputBase)(({ theme }) => ({
|
||||
color: 'white',
|
||||
width: '100%',
|
||||
'& .MuiInputBase-input': {
|
||||
padding: theme.spacing(1, 1, 1, 0),
|
||||
// vertical padding + font size from searchIcon
|
||||
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
||||
transition: theme.transitions.create('width'),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '12ch',
|
||||
'&:focus': {
|
||||
width: '20ch',
|
||||
padding: theme.spacing(1, 1, 1, 0),
|
||||
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
||||
transition: theme.transitions.create('width'),
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '12ch',
|
||||
'&:focus': {
|
||||
width: '20ch',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
}));
|
||||
|
||||
export default function NavBar() {
|
||||
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(null);
|
||||
@@ -76,6 +75,7 @@ export default function NavBar() {
|
||||
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElNav(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElUser(event.currentTarget);
|
||||
};
|
||||
@@ -157,6 +157,7 @@ export default function NavBar() {
|
||||
))}
|
||||
</Menu>
|
||||
</Box>
|
||||
|
||||
<AdbIcon sx={{ display: { xs: 'flex', md: 'none' }, mr: 1 }} />
|
||||
<Typography
|
||||
variant="h5"
|
||||
@@ -176,6 +177,7 @@ export default function NavBar() {
|
||||
>
|
||||
DPS
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
|
||||
{pages.map((page) => (
|
||||
<Button
|
||||
@@ -187,7 +189,9 @@ export default function NavBar() {
|
||||
</Button>
|
||||
))}
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 0 }}>
|
||||
|
||||
<Box sx={{ flexGrow: 0, display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<ThemeToggle />
|
||||
<Tooltip title="Open settings">
|
||||
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
|
||||
<Avatar alt="Florian Speicher" src="/static/images/avatar/2.jpg" />
|
||||
@@ -195,7 +199,7 @@ export default function NavBar() {
|
||||
</Tooltip>
|
||||
<Menu
|
||||
sx={{ mt: '45px' }}
|
||||
id="menu-appbar"
|
||||
id="menu-appbar-user"
|
||||
anchorEl={anchorElUser}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
padding: 20px;
|
||||
text-align: left;
|
||||
background: linear-gradient(135deg, #ece9e6, #ffffff);
|
||||
color: #333;
|
||||
color: primary;
|
||||
min-height: 100vh;
|
||||
margin: 0; /* Entferne zentrierende Margins */
|
||||
width: 100%; /* Container nimmt die gesamte Breite ein */
|
||||
@@ -133,6 +133,7 @@
|
||||
min-height: 600px;
|
||||
padding: 20px 0; /* Abstand oben und unten */
|
||||
box-sizing: border-box;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
|
||||
183
01-frontend/src/theme/ThemeContext.tsx
Normal file
183
01-frontend/src/theme/ThemeContext.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
'use client';
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import { CssBaseline, GlobalStyles } from '@mui/material';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
|
||||
type ThemeMode = 'light' | 'dark';
|
||||
|
||||
interface ThemeContextType {
|
||||
mode: ThemeMode;
|
||||
toggleMode: () => void;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextType>({
|
||||
mode: 'light',
|
||||
toggleMode: () => {},
|
||||
});
|
||||
|
||||
export const useThemeMode = () => useContext(ThemeContext);
|
||||
|
||||
interface CustomThemeProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const CustomThemeProvider: React.FC<CustomThemeProviderProps> = ({ children }) => {
|
||||
// ✅ SSR-sichere System-Präferenz-Erkennung
|
||||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)', { noSsr: true });
|
||||
|
||||
// ✅ SSR-sichere Initialisierung
|
||||
const [mode, setMode] = useState<ThemeMode>('light');
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
// ✅ Nach dem ersten Render ausführen (SSR-sicher)
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
const savedMode = localStorage.getItem('themeMode') as ThemeMode;
|
||||
if (savedMode === 'light' || savedMode === 'dark') {
|
||||
setMode(savedMode);
|
||||
} else {
|
||||
setMode(prefersDarkMode ? 'dark' : 'light');
|
||||
}
|
||||
}
|
||||
}, [prefersDarkMode]);
|
||||
|
||||
// Mode in localStorage speichern
|
||||
useEffect(() => {
|
||||
if (mounted && typeof window !== 'undefined') {
|
||||
localStorage.setItem('themeMode', mode);
|
||||
}
|
||||
}, [mode, mounted]);
|
||||
|
||||
// ✅ Browser-only DOM-Manipulation
|
||||
useEffect(() => {
|
||||
if (mounted && typeof window !== 'undefined') {
|
||||
const backgroundColor = mode === 'dark' ? '#121212' : '#fafafa';
|
||||
|
||||
// Warten bis DOM geladen ist
|
||||
const updateBackground = () => {
|
||||
document.documentElement.style.setProperty('--background-color', backgroundColor);
|
||||
document.documentElement.style.backgroundColor = backgroundColor;
|
||||
document.body.style.backgroundColor = backgroundColor;
|
||||
|
||||
const root = document.getElementById('root');
|
||||
if (root) {
|
||||
root.style.backgroundColor = backgroundColor;
|
||||
}
|
||||
};
|
||||
|
||||
// Sofort ausführen
|
||||
updateBackground();
|
||||
|
||||
// Nach einem kurzen Delay nochmal (für hartnäckige Cases)
|
||||
const timeoutId = setTimeout(updateBackground, 100);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
}
|
||||
}, [mode, mounted]);
|
||||
|
||||
const toggleMode = () => {
|
||||
setMode(prevMode => prevMode === 'light' ? 'dark' : 'light');
|
||||
};
|
||||
|
||||
// Theme basierend auf Mode erstellen
|
||||
const theme = React.useMemo(() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode,
|
||||
primary: {
|
||||
main: '#0fd13f', // Ihre grüne NavBar
|
||||
light: mode === 'dark' ? '#4caf50' : '#42a5f5',
|
||||
dark: mode === 'dark' ? '#388e3c' : '#1565c0',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
secondary: {
|
||||
main: mode === 'dark' ? '#bb86fc' : '#9c27b0',
|
||||
light: mode === 'dark' ? '#d7aefb' : '#ba68c8',
|
||||
dark: mode === 'dark' ? '#985eff' : '#7b1fa2',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
background: {
|
||||
default: mode === 'dark' ? '#121212' : '#fafafa',
|
||||
paper: mode === 'dark' ? '#1e1e1e' : '#ffffff',
|
||||
},
|
||||
text: {
|
||||
primary: mode === 'dark' ? '#ffffff' : '#000000',
|
||||
secondary: mode === 'dark' ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.6)',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
html: {
|
||||
backgroundColor: `${mode === 'dark' ? '#121212' : '#fafafa'} !important`,
|
||||
transition: 'background-color 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
},
|
||||
body: {
|
||||
backgroundColor: `${mode === 'dark' ? '#121212' : '#fafafa'} !important`,
|
||||
transition: 'background-color 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAppBar: {
|
||||
styleOverrides: {
|
||||
colorPrimary: {
|
||||
backgroundColor: '#0fd13f !important',
|
||||
color: '#ffffff',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[mode]
|
||||
);
|
||||
|
||||
// ✅ Aggressive GlobalStyles mit CSS-Variablen
|
||||
const globalStyles = mounted ? (
|
||||
<GlobalStyles
|
||||
styles={{
|
||||
':root': {
|
||||
'--background-color': mode === 'dark' ? '#121212' : '#fafafa',
|
||||
'--text-color': mode === 'dark' ? '#ffffff' : '#000000',
|
||||
},
|
||||
'*': {
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
'html, body, #root': {
|
||||
backgroundColor: `var(--background-color) !important`,
|
||||
color: `var(--text-color) !important`,
|
||||
transition: 'background-color 300ms cubic-bezier(0.4, 0, 0.2, 1), color 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
minHeight: '100vh',
|
||||
},
|
||||
'div, section, main, article': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
// ✅ SSR-Fallback während mounted = false
|
||||
if (!mounted) {
|
||||
return (
|
||||
<ThemeProvider theme={createTheme({ palette: { mode: 'light' } })}>
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ mode, toggleMode }}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline enableColorScheme />
|
||||
{globalStyles}
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
28
01-frontend/src/theme/ThemeToggle.tsx
Normal file
28
01-frontend/src/theme/ThemeToggle.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
// theme/ThemeToggle.tsx
|
||||
import React from 'react';
|
||||
import { IconButton, Tooltip } from '@mui/material';
|
||||
import { Brightness4, Brightness7 } from '@mui/icons-material';
|
||||
import { useThemeMode } from './ThemeContext';
|
||||
|
||||
const ThemeToggle: React.FC = () => {
|
||||
const { mode, toggleMode } = useThemeMode();
|
||||
|
||||
return (
|
||||
<Tooltip title={mode === 'dark' ? 'Zu hellem Modus wechseln' : 'Zu dunklem Modus wechseln'}>
|
||||
<IconButton
|
||||
onClick={toggleMode}
|
||||
color="inherit"
|
||||
sx={{
|
||||
transition: 'transform 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'scale(1.1)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{mode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeToggle;
|
||||
11
01-frontend/src/theme/theme-augmentation.d.ts
vendored
Normal file
11
01-frontend/src/theme/theme-augmentation.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import '@mui/material/styles';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Palette {
|
||||
tertiary: Palette['primary'];
|
||||
}
|
||||
|
||||
interface PaletteOptions {
|
||||
tertiary?: PaletteOptions['primary'];
|
||||
}
|
||||
}
|
||||
207
01-frontend/src/theme/theme.ts
Normal file
207
01-frontend/src/theme/theme.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
import './theme-augmentation.d.ts'; // Falls vorhanden
|
||||
|
||||
export const darkmode = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#0fd13f', // Ihre grüne Farbe
|
||||
light: '#42a5f5',
|
||||
dark: '#15650',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
secondary: {
|
||||
main: '#9c27b0',
|
||||
light: '#ba68c8',
|
||||
dark: '#7b1fa2',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
// ✅ 'tertiary' entfernt - ist kein Standard MUI-Property
|
||||
error: {
|
||||
main: '#f44336',
|
||||
light: '#e57373',
|
||||
dark: '#d32f2f',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
warning: {
|
||||
main: '#ed6c02',
|
||||
light: '#ff9800',
|
||||
dark: '#e65100',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
info: {
|
||||
main: '#0288d1',
|
||||
light: '#03a9f4',
|
||||
dark: '#01579b',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
success: {
|
||||
main: '#2e7d32',
|
||||
light: '#4caf50',
|
||||
dark: '#1b5e20',
|
||||
contrastText: '#fff',
|
||||
},
|
||||
background: {
|
||||
default: '#fafafa',
|
||||
paper: '#ffffff',
|
||||
},
|
||||
text: {
|
||||
primary: '#000000',
|
||||
secondary: 'rgba(0, 0, 0, 0.6)',
|
||||
},
|
||||
},
|
||||
// ✅ Sanfte Übergänge hinzugefügt
|
||||
transitions: {
|
||||
duration: {
|
||||
shortest: 150,
|
||||
shorter: 200,
|
||||
short: 250,
|
||||
standard: 300,
|
||||
complex: 375,
|
||||
enteringScreen: 225,
|
||||
leavingScreen: 195,
|
||||
},
|
||||
easing: {
|
||||
easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
easeOut: 'cubic-bezier(0.0, 0, 0.2, 1)',
|
||||
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||
sharp: 'cubic-bezier(0.4, 0, 0.6, 1)',
|
||||
},
|
||||
},
|
||||
// ✅ Verbesserte Komponenten-Overrides
|
||||
components: {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
body: {
|
||||
backgroundColor: '#fafafa',
|
||||
transition: 'background-color 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
},
|
||||
html: {
|
||||
backgroundColor: '#fafafa',
|
||||
transition: 'background-color 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAppBar: {
|
||||
styleOverrides: {
|
||||
colorPrimary: {
|
||||
backgroundColor: '#0fd13f', // Ihre grüne NavBar
|
||||
color: '#ffffff',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
textTransform: 'none', // Entfernt automatische Großschreibung
|
||||
fontWeight: 600,
|
||||
},
|
||||
contained: {
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||
'&:hover': {
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCard: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 12,
|
||||
boxShadow: '0 2px 12px rgba(0,0,0,0.08)',
|
||||
transition: 'box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
'&:hover': {
|
||||
boxShadow: '0 4px 20px rgba(0,0,0,0.12)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTextField: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 16,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
elevation1: {
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
|
||||
},
|
||||
elevation2: {
|
||||
boxShadow: '0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// ✅ Benutzerdefinierte Typografie
|
||||
typography: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||
h1: {
|
||||
fontWeight: 700,
|
||||
fontSize: '2.5rem',
|
||||
lineHeight: 1.2,
|
||||
},
|
||||
h2: {
|
||||
fontWeight: 600,
|
||||
fontSize: '2rem',
|
||||
lineHeight: 1.3,
|
||||
},
|
||||
h3: {
|
||||
fontWeight: 600,
|
||||
fontSize: '1.75rem',
|
||||
lineHeight: 1.3,
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 600,
|
||||
fontSize: '1.5rem',
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
h5: {
|
||||
fontWeight: 600,
|
||||
fontSize: '1.25rem',
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
h6: {
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
body1: {
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.5,
|
||||
},
|
||||
body2: {
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
button: {
|
||||
fontWeight: 600,
|
||||
textTransform: 'none',
|
||||
},
|
||||
},
|
||||
// ✅ Benutzerdefinierte Breakpoints
|
||||
breakpoints: {
|
||||
values: {
|
||||
xs: 0,
|
||||
sm: 600,
|
||||
md: 960,
|
||||
lg: 1280,
|
||||
xl: 1920,
|
||||
},
|
||||
},
|
||||
// ✅ Angepasste Spacing-Funktion
|
||||
spacing: 8, // 8px als Basis-Einheit
|
||||
});
|
||||
@@ -22,5 +22,8 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user