Outsource custom GUI class components to dashgui library

Move reusable GUI primitives (PanelTile, EditablePanelTile, base Tile,
ElevatedPill, SingleLineTextEdit) into the shared dashgui package and
consume them via a file: dependency. EditablePanelTile now accepts an
onError prop so error notification stays app-side.
This commit is contained in:
seb
2026-08-08 16:17:16 +02:00
parent 2cbe5dabb2
commit 57fff72f12
38 changed files with 80 additions and 759 deletions

View File

@@ -1,6 +1,6 @@
import AddIcon from '@mui/icons-material/Add';
import Typography from '@mui/material/Typography';
import { Tile } from './Tile';
import { Tile } from 'dashgui/tiles';
export class ActionTile extends Tile {
renderIcon() {

View File

@@ -2,7 +2,7 @@ import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
import Box from '@mui/material/Box';
import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography';
import { Tile, tileBaseSx } from './Tile';
import { Tile, tileBaseSx } from 'dashgui/tiles';
import { formatPrice } from '../../utils/price';
import { articleSku } from '../../pages/artikel/articleRoute';
import ArticlePhoto from '../article/ArticlePhoto';

View File

@@ -1,7 +1,7 @@
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { Tile, tileBaseSx } from './Tile';
import { Tile, tileBaseSx } from 'dashgui/tiles';
/**
* BackTile renders as a <div> (Box) instead of <button> (ButtonBase)

View File

@@ -13,7 +13,7 @@ import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
import ThumbHashImage from '../article/ThumbHashImage';
import { thumb } from '../../api';
import { tileBaseSx } from './Tile';
import { tileBaseSx } from 'dashgui/tiles';
/**
* Top row (1/3): sort handle | settings toggle | move handle.

View File

@@ -1,91 +0,0 @@
import { Component } from 'react';
import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography';
export const TILE_SIZE = 140;
/** Matches panel tile rounding (theme.shape.borderRadius × 4 → typically 16px). */
export const TILE_BORDER_RADIUS = 4;
export const tileBaseSx = {
aspectRatio: '1 / 1',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 1,
p: 1.5,
cursor: 'pointer',
userSelect: 'none',
textAlign: 'center',
border: 'none',
borderRadius: TILE_BORDER_RADIUS,
overflow: 'hidden',
bgcolor: 'background.paper',
boxShadow: 3,
transition: 'box-shadow 0.15s, background-color 0.15s',
'&:hover': {
bgcolor: 'action.hover',
boxShadow: 6,
},
};
export class Tile extends Component {
handleClick = () => {
this.props.onClick?.();
};
renderIcon() {
return null;
}
renderLabel() {
const { label } = this.props;
if (!label) return null;
return (
<Typography variant="body2" fontWeight={600} sx={{ lineHeight: 1.2 }}>
{label}
</Typography>
);
}
renderSecondary() {
const { secondary } = this.props;
if (!secondary) return null;
return (
<Typography variant="caption" color="text.secondary" sx={{ lineHeight: 1.2 }}>
{secondary}
</Typography>
);
}
renderExtra() {
return null;
}
render() {
const { sx, disabled } = this.props;
return (
<ButtonBase
component="button"
type="button"
disabled={disabled}
onClick={this.handleClick}
sx={{
...tileBaseSx,
position: 'relative',
...(disabled
? { opacity: 0.5, pointerEvents: 'none' }
: {}),
...sx,
}}
>
{this.renderIcon()}
{this.renderLabel()}
{this.renderSecondary()}
{this.renderExtra()}
</ButtonBase>
);
}
}

View File

@@ -1,4 +1,4 @@
export { TILE_SIZE, Tile, tileBaseSx } from './Tile';
export { TILE_SIZE, Tile, tileBaseSx } from 'dashgui/tiles';
export { BackTile } from './BackTile';
export { CategoryTile, CategoryEditTile } from './CategoryTile';
export { ArticleTile } from './ArticleTile';