Genesis
This commit is contained in:
128
src/tiles/Tile.jsx
Normal file
128
src/tiles/Tile.jsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Component } from 'react';
|
||||
import ButtonBase from '@mui/material/ButtonBase';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
/**
|
||||
* Square side length (px) used as the basis for the tile grid in consuming
|
||||
* apps.
|
||||
*
|
||||
* @component TILE_SIZE
|
||||
* @import dashgui/tiles
|
||||
*
|
||||
* @behaviour Constant (140) exported for building grids: `repeat(auto-fill, minmax(TILE_SIZEpx, 1fr))`.
|
||||
*/
|
||||
export const TILE_SIZE = 140;
|
||||
|
||||
/** Matches panel tile rounding (theme.shape.borderRadius × 4 → typically 16px). */
|
||||
export const TILE_BORDER_RADIUS = 4;
|
||||
|
||||
/**
|
||||
* Shared tile styling, exported for reuse — lets consumers render a tile-like
|
||||
* box without extending the Tile class (see the blue box in the gallery).
|
||||
*
|
||||
* @component tileBaseSx
|
||||
* @import dashgui/tiles
|
||||
*
|
||||
* @behaviour Sets a square aspect ratio, centered flex column layout, rounded corners, background.paper fill, shadow 3, and hover states (background hover + shadow 6).
|
||||
* @behaviour Not tied to a click handler — add your own onClick when used directly. Spread additional styles after it to override (e.g. bgcolor, color).
|
||||
*/
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Base square tile (ButtonBase) meant to be subclassed — subclasses override
|
||||
* the render hooks (e.g. `renderIcon`) and pass label/secondary text via props.
|
||||
* Renders the shared `tileBaseSx` styling.
|
||||
*
|
||||
* @component Tile
|
||||
* @import dashgui/tiles
|
||||
*
|
||||
* @prop {ReactNode} [label] - Primary text shown under the icon.
|
||||
* @prop {ReactNode} [secondary] - Small secondary caption shown under the label.
|
||||
* @prop {() => void} [onClick] - Called when the tile is clicked (disabled tiles are inert).
|
||||
* @prop {boolean} [disabled=false] - Fades the tile to 50% opacity and disables pointer events.
|
||||
* @prop {object} [sx] - Extra styles merged on top of `tileBaseSx` (win over it).
|
||||
*
|
||||
* @behaviour Renders inside a `ButtonBase` with `type="button"` and the shared `tileBaseSx` square look (aspect-ratio 1:1, rounded, shadow, hover feedback).
|
||||
* @behaviour Subclasses override `renderIcon()`, `renderLabel()`, `renderSecondary()`, or `renderExtra()` to compose the tile body.
|
||||
* @behaviour `TILE_SIZE` (140) is the basis for sizing the containing grid in the consuming app.
|
||||
*/
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
1
src/tiles/index.js
Normal file
1
src/tiles/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { TILE_SIZE, Tile, tileBaseSx } from './Tile';
|
||||
Reference in New Issue
Block a user