fix(RecordList): align action buttons and tint row dividers to color prop

This commit is contained in:
seb
2026-08-09 00:04:30 +02:00
parent f0b622a535
commit 4f0d73e0ea

View File

@@ -48,12 +48,35 @@ import { PanelTile, PanelTileGrid } from '../panels';
* @behaviour Clicking a row calls `onEdit(row)` (only when `onEdit` is provided); the action buttons stop propagation so they do not double-trigger the row click. * @behaviour Clicking a row calls `onEdit(row)` (only when `onEdit` is provided); the action buttons stop propagation so they do not double-trigger the row click.
* @behaviour The actions column appears only if `onEdit` or `onDelete` is provided. * @behaviour The actions column appears only if `onEdit` or `onDelete` is provided.
* @behaviour No data layer: this component never touches storage, routing, toasters, or backend error formatting. * @behaviour No data layer: this component never touches storage, routing, toasters, or backend error formatting.
* @behaviour When `color` is a hex value, the row dividers are tinted to a darker shade of it so the horizontal lines fit the tile background.
*/ */
class RecordList extends Component { class RecordList extends Component {
handleRowClick(row) { handleRowClick(row) {
this.props.onEdit?.(row); this.props.onEdit?.(row);
} }
/** Darken a #rrggbb / #rgb hex color by `amount` (0–1); falls back to the divider grey for non-hex colors. */
dividerColor(color, amount = 0.15) {
if (typeof color !== 'string') return 'divider';
const m = color.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
if (!m) return 'divider';
let hex = m[1];
if (hex.length === 3) {
hex = hex
.split('')
.map((c) => c + c)
.join('');
}
const num = parseInt(hex, 16);
const channels = [16, 8, 0].map((shift) => {
const c = (num >> shift) & 0xff;
return Math.max(0, Math.round(c * (1 - amount)));
});
const toHex = (v) => v.toString(16).padStart(2, '0');
return `#${channels.map(toHex).join('')}`;
}
renderLoading() { renderLoading() {
return ( return (
<Box sx={{ display: 'flex', justifyContent: 'center', py: 6 }}> <Box sx={{ display: 'flex', justifyContent: 'center', py: 6 }}>
@@ -99,13 +122,22 @@ class RecordList extends Component {
deleteDisabled, deleteDisabled,
getEditLabel, getEditLabel,
getDeleteLabel, getDeleteLabel,
color,
} = this.props; } = this.props;
const hasActions = Boolean(onEdit || onDelete); const hasActions = Boolean(onEdit || onDelete);
const borderColor = this.dividerColor(color);
return ( return (
<TableContainer> <TableContainer>
<Table size="small"> <Table
size="small"
sx={{
'& .MuiTableCell-root': {
borderColor,
},
}}
>
<TableHead> <TableHead>
<TableRow> <TableRow>
{columns.map((col) => ( {columns.map((col) => (
@@ -140,29 +172,31 @@ class RecordList extends Component {
padding="checkbox" padding="checkbox"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{onEdit ? ( <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<IconButton {onEdit ? (
size="small" <IconButton
aria-label={ size="small"
getEditLabel?.(row) ?? `„${id}“ bearbeiten` aria-label={
} getEditLabel?.(row) ?? `„${id}“ bearbeiten`
onClick={() => onEdit(row)} }
> onClick={() => onEdit(row)}
<EditOutlinedIcon fontSize="small" /> >
</IconButton> <EditOutlinedIcon fontSize="small" />
) : null} </IconButton>
{onDelete ? ( ) : null}
<IconButton {onDelete ? (
size="small" <IconButton
aria-label={ size="small"
getDeleteLabel?.(row) ?? `„${id}“ löschen` aria-label={
} getDeleteLabel?.(row) ?? `„${id}“ löschen`
disabled={deleteDisabled} }
onClick={() => onDelete(row)} disabled={deleteDisabled}
> onClick={() => onDelete(row)}
<DeleteOutlinedIcon fontSize="small" /> >
</IconButton> <DeleteOutlinedIcon fontSize="small" />
) : null} </IconButton>
) : null}
</Box>
</TableCell> </TableCell>
) : null} ) : null}
</TableRow> </TableRow>