This commit is contained in:
seb
2026-08-02 22:53:35 +02:00
parent 2dd14bac91
commit 52e4d3d9c9
6 changed files with 304 additions and 43 deletions

View File

@@ -1,8 +1,161 @@
import FolderIcon from '@mui/icons-material/Folder';
import { Tile } from './Tile';
import { Component } from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import DragHandleIcon from '@mui/icons-material/DragHandle';
import AccountTreeIcon from '@mui/icons-material/AccountTree';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
import { Tile, tileBaseSx } from './Tile';
/**
* Top edit band (upper third) with a move handle on the left and a tree
* (drop-into-subcategory) handle on the right.
*/
function TopBand() {
return (
<Box
sx={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: '16.66%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 0.5,
}}
>
<IconButton
className="sortable-handle"
size="small"
aria-label="Verschieben"
sx={{ cursor: 'grab', '&:active': { cursor: 'grabbing' } }}
>
<DragHandleIcon sx={{ fontSize: 18 }} />
</IconButton>
<IconButton
className="sortable-tree"
size="small"
aria-label="In Unterkategorie ablegen"
sx={{ cursor: 'grab', '&:active': { cursor: 'grabbing' } }}
>
<AccountTreeIcon sx={{ fontSize: 18 }} />
</IconButton>
</Box>
);
}
/**
* Shared grey name band spanning the middle third.
*/
function NameBand({ label, nameInput }) {
if (label == null) return null;
return (
<Box
sx={{
position: 'absolute',
top: '33.33%',
bottom: '33.33%',
left: 0,
right: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'grey.300',
px: 1,
}}
>
{nameInput ?? (
<Typography
variant="body2"
fontWeight={600}
noWrap
sx={{ lineHeight: 1.2, color: 'text.primary' }}
>
{label}
</Typography>
)}
</Box>
);
}
/**
* Bottom edit band with left/right chevron reorder buttons and a center delete.
*/
function EditBand({ onMoveLeft, onMoveRight, onDelete, canLeft, canRight }) {
return (
<Box
sx={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: '16.66%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 0.5,
bgcolor: 'grey.400',
}}
>
<IconButton className="sortable-handle-btn" size="small" aria-label="Nach links verschieben" disabled={!canLeft} onClick={onMoveLeft}>
<ChevronLeftIcon sx={{ fontSize: 18 }} />
</IconButton>
<IconButton className="sortable-handle-btn" size="small" aria-label="Löschen" onClick={onDelete}>
<DeleteOutlinedIcon sx={{ fontSize: 18 }} />
</IconButton>
<IconButton className="sortable-handle-btn" size="small" aria-label="Nach rechts verschieben" disabled={!canRight} onClick={onMoveRight}>
<ChevronRightIcon sx={{ fontSize: 18 }} />
</IconButton>
</Box>
);
}
/**
* Category tile (normal mode): no icon, click navigates to the category.
*/
export class CategoryTile extends Tile {
renderIcon() {
return <FolderIcon color="primary" sx={{ fontSize: 40 }} />;
return null;
}
renderLabel() {
const { label, nameInput } = this.props;
return <NameBand label={label} nameInput={nameInput} />;
}
}
/**
* Category tile for edit mode: no ButtonBase (no ripple, no click navigation),
* always shows the bottom edit band with chevron reorder/delete actions.
*/
export class CategoryEditTile extends Component {
render() {
const { label, nameInput, editBand, sx, ...rest } = this.props;
return (
<Box
{...rest}
sx={{
...tileBaseSx,
cursor: 'default',
position: 'relative',
'&:hover': { bgcolor: 'background.paper', boxShadow: 0 },
...sx,
}}
>
<TopBand />
<NameBand label={label} nameInput={nameInput} />
<EditBand
onMoveLeft={editBand.onMoveLeft}
onMoveRight={editBand.onMoveRight}
onDelete={editBand.onDelete}
canLeft={editBand.canLeft}
canRight={editBand.canRight}
/>
</Box>
);
}
}