Refactor section title toggles into reusable ElevatedPill components

This commit is contained in:
seb
2026-08-04 00:01:51 +02:00
parent 8f371749c6
commit aa543f8631
2 changed files with 91 additions and 14 deletions

View File

@@ -0,0 +1,80 @@
import { Component } from 'react';
import Box from '@mui/material/Box';
import Switch from '@mui/material/Switch';
import Typography from '@mui/material/Typography';
import { alpha } from '@mui/material/styles';
/** Base pill with elevation, shared styling, and an overridable trailing element. */
class ElevatedPill extends Component {
renderTrailing() {
return null;
}
render() {
const { label, active = false } = this.props;
return (
<Box
component="label"
sx={(theme) => ({
display: 'inline-flex',
alignItems: 'center',
gap: 0.5,
px: 1.5,
py: 0.25,
borderRadius: 999,
background: active
? `linear-gradient(180deg, ${alpha(theme.palette.primary.main, 0.28)}, ${alpha(
theme.palette.primary.main,
0.22,
)})`
: `linear-gradient(180deg, ${alpha(theme.palette.primary.main, 0.16)}, ${alpha(
theme.palette.primary.main,
0.10,
)})`,
color: 'text.primary',
cursor: 'pointer',
userSelect: 'none',
boxShadow: theme.shadows[1],
transition: 'background 150ms ease, box-shadow 150ms ease',
})}
>
<Typography variant="body2" sx={{ lineHeight: 1 }}>
{label}
</Typography>
{this.renderTrailing()}
</Box>
);
}
}
export class ToggleElevatedPill extends ElevatedPill {
renderTrailing() {
const { checked, onToggle } = this.props;
return (
<Switch
size="small"
checked={checked}
onChange={(event) => onToggle(event.target.checked)}
sx={(theme) => ({
'& .MuiSwitch-switchBase': {
color: checked ? 'success.main' : 'grey.300',
},
'& .Mui-checked': {
color: 'success.main',
},
'& .Mui-checked + .MuiSwitch-track': {
backgroundColor: alpha(theme.palette.success.main, 0.35),
},
})}
/>
);
}
}
export class ActionElevatedPill extends ElevatedPill {
renderTrailing() {
return this.props.icon;
}
}
export default ElevatedPill;

View File

@@ -1,11 +1,12 @@
import { Outlet, useLocation } from 'react-router-dom'; import { Outlet, useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import FormControlLabel from '@mui/material/FormControlLabel'; import Box from '@mui/material/Box';
import Switch from '@mui/material/Switch'; import SettingsIcon from '@mui/icons-material/Settings';
import PageLayout from './PageLayout'; import PageLayout from './PageLayout';
import { NAV_ITEMS, SUB_NAV } from '../nav'; import { NAV_ITEMS, SUB_NAV } from '../nav';
import { isKategorienPath } from '../pages/artikel/categoryRoute'; import { isKategorienPath } from '../pages/artikel/categoryRoute';
import { selectRenameMode, setRenameMode } from '../store/categorySlice'; import { selectRenameMode, setRenameMode } from '../store/categorySlice';
import { ActionElevatedPill, ToggleElevatedPill } from './ElevatedPill';
export default function SectionLayout({ sectionPath }) { export default function SectionLayout({ sectionPath }) {
const { pathname } = useLocation(); const { pathname } = useLocation();
@@ -36,18 +37,14 @@ export default function SectionLayout({ sectionPath }) {
const showsRenameSwitch = activeSub?.segment === 'kategorien'; const showsRenameSwitch = activeSub?.segment === 'kategorien';
const titleAction = showsRenameSwitch ? ( const titleAction = showsRenameSwitch ? (
<FormControlLabel <Box sx={{ display: 'inline-flex', gap: 1 }}>
control={ <ToggleElevatedPill
<Switch label="Editieren"
size="small" checked={renameMode}
checked={renameMode} onToggle={(checked) => dispatch(setRenameMode(checked))}
onChange={(event) => dispatch(setRenameMode(event.target.checked))} />
/> <ActionElevatedPill label="Extras" icon={<SettingsIcon sx={{ fontSize: 18 }} />} />
} </Box>
label="Editieren"
labelPlacement="end"
sx={{ ml: 0 }}
/>
) : null; ) : null;
return ( return (