fix(RecordList): align action buttons and tint row dividers to color prop
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user