Files
reactShop/src/components/ThemeCustomizerDialog.js
2025-07-02 12:49:06 +02:00

258 lines
7.4 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Typography,
Box,
Accordion,
AccordionSummary,
AccordionDetails,
TextField,
Chip,
Grid,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import PaletteIcon from '@mui/icons-material/Palette';
const ThemeCustomizerDialog = ({ open, onClose, theme, onThemeChange }) => {
const [localTheme, setLocalTheme] = useState(theme);
// @note Theme customizer for development - allows real-time theme changes
useEffect(() => {
setLocalTheme(theme);
}, [theme]);
const handleColorChange = (path, value) => {
const pathArray = path.split('.');
const newTheme = { ...localTheme };
let current = newTheme;
for (let i = 0; i < pathArray.length - 1; i++) {
current = current[pathArray[i]];
}
current[pathArray[pathArray.length - 1]] = value;
setLocalTheme(newTheme);
onThemeChange(newTheme);
};
const resetTheme = () => {
const defaultTheme = {
palette: {
mode: 'light',
primary: {
main: '#2E7D32',
light: '#4CAF50',
dark: '#1B5E20',
},
secondary: {
main: '#81C784',
light: '#A5D6A7',
dark: '#66BB6A',
},
background: {
default: '#C8E6C9',
paper: '#ffffff',
},
text: {
primary: '#33691E',
secondary: '#558B2F',
},
success: {
main: '#43A047',
},
error: {
main: '#D32F2F',
},
},
typography: {
fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
h4: {
fontWeight: 600,
color: '#33691E',
},
},
};
setLocalTheme(defaultTheme);
onThemeChange(defaultTheme);
};
const ColorPicker = ({ label, path, value }) => (
<Box sx={{ mb: 1.5 }}>
<Typography variant="caption" sx={{ mb: 0.5, display: 'block' }}>{label}</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<TextField
type="color"
value={value}
onChange={(e) => handleColorChange(path, e.target.value)}
sx={{ width: 50, height: 35 }}
/>
<TextField
value={value}
onChange={(e) => handleColorChange(path, e.target.value)}
size="small"
sx={{ flex: 1, fontSize: '0.75rem' }}
/>
</Box>
</Box>
);
return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
<DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<PaletteIcon />
Theme Customizer (Development Mode)
</DialogTitle>
<DialogContent>
<Box sx={{ mb: 2 }}>
<Chip
label="DEV ONLY"
color="warning"
size="small"
sx={{ mb: 2 }}
/>
<Typography variant="body2" color="text.secondary">
This tool is only available in development mode for theme customization.
</Typography>
</Box>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">Primary Colors</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={1}>
<Grid item xs={4}>
<ColorPicker
label="Main"
path="palette.primary.main"
value={localTheme.palette.primary.main}
/>
</Grid>
<Grid item xs={4}>
<ColorPicker
label="Light"
path="palette.primary.light"
value={localTheme.palette.primary.light}
/>
</Grid>
<Grid item xs={4}>
<ColorPicker
label="Dark"
path="palette.primary.dark"
value={localTheme.palette.primary.dark}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">Secondary Colors</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={1}>
<Grid item xs={4}>
<ColorPicker
label="Main"
path="palette.secondary.main"
value={localTheme.palette.secondary.main}
/>
</Grid>
<Grid item xs={4}>
<ColorPicker
label="Light"
path="palette.secondary.light"
value={localTheme.palette.secondary.light}
/>
</Grid>
<Grid item xs={4}>
<ColorPicker
label="Dark"
path="palette.secondary.dark"
value={localTheme.palette.secondary.dark}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">Background & Text</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={1}>
<Grid item xs={6}>
<ColorPicker
label="Background"
path="palette.background.default"
value={localTheme.palette.background.default}
/>
<ColorPicker
label="Paper"
path="palette.background.paper"
value={localTheme.palette.background.paper}
/>
</Grid>
<Grid item xs={6}>
<ColorPicker
label="Text Primary"
path="palette.text.primary"
value={localTheme.palette.text.primary}
/>
<ColorPicker
label="Text Secondary"
path="palette.text.secondary"
value={localTheme.palette.text.secondary}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">Status Colors</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={1}>
<Grid item xs={6}>
<ColorPicker
label="Success"
path="palette.success.main"
value={localTheme.palette.success.main}
/>
</Grid>
<Grid item xs={6}>
<ColorPicker
label="Error"
path="palette.error.main"
value={localTheme.palette.error.main}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</DialogContent>
<DialogActions>
<Button onClick={resetTheme} color="warning">
Reset to Default
</Button>
<Button onClick={onClose}>
Close
</Button>
</DialogActions>
</Dialog>
);
};
export default ThemeCustomizerDialog;