Genesis
This commit is contained in:
178
src/dev/ComponentDocs.jsx
Normal file
178
src/dev/ComponentDocs.jsx
Normal file
@@ -0,0 +1,178 @@
|
||||
import Box from '@mui/material/Box';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Table from '@mui/material/Table';
|
||||
import TableBody from '@mui/material/TableBody';
|
||||
import TableCell from '@mui/material/TableCell';
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { componentDocs } from 'virtual:component-docs';
|
||||
|
||||
/**
|
||||
* Look up a component's docs from the registry extracted by the Vite plugin.
|
||||
*/
|
||||
export function getComponentDoc(name) {
|
||||
return componentDocs[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Props documentation table.
|
||||
* `props`: [{ name, type, required?, default?, description }]
|
||||
*/
|
||||
export function PropsTable({ props }) {
|
||||
return (
|
||||
<TableContainer
|
||||
component={Paper}
|
||||
variant="outlined"
|
||||
sx={{ bgcolor: 'background.paper' }}
|
||||
>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{ width: '18%' }}>Prop</TableCell>
|
||||
<TableCell sx={{ width: '24%' }}>Type</TableCell>
|
||||
<TableCell sx={{ width: '12%' }}>Default</TableCell>
|
||||
<TableCell>Description</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{props.map((p) => (
|
||||
<TableRow
|
||||
key={p.name}
|
||||
sx={{ '&:last-child td, &:last-child th': { borderBottom: 0 } }}
|
||||
>
|
||||
<TableCell sx={{ py: 0.75 }}>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
alignItems="center"
|
||||
sx={{ flexWrap: 'wrap' }}
|
||||
>
|
||||
<Box
|
||||
component="code"
|
||||
sx={{ fontFamily: 'monospace', fontWeight: 600, fontSize: 13 }}
|
||||
>
|
||||
{p.name}
|
||||
</Box>
|
||||
{p.required ? (
|
||||
<Chip
|
||||
label="required"
|
||||
size="small"
|
||||
color="error"
|
||||
sx={{ height: 18, fontSize: 10 }}
|
||||
/>
|
||||
) : null}
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableCell sx={{ py: 0.75 }}>
|
||||
<Box
|
||||
component="code"
|
||||
sx={{
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 12,
|
||||
color: 'primary.main',
|
||||
}}
|
||||
>
|
||||
{p.type}
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell sx={{ py: 0.75 }}>
|
||||
{p.default != null ? (
|
||||
<Box component="code" sx={{ fontFamily: 'monospace', fontSize: 12 }}>
|
||||
{p.default}
|
||||
</Box>
|
||||
) : (
|
||||
'—'
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell sx={{ py: 0.75, color: 'text.secondary' }}>
|
||||
{p.description}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/** Behaviour notes rendered as a bulleted list. */
|
||||
export function BehaviourList({ items }) {
|
||||
return (
|
||||
<Box component="ul" sx={{ m: 0, pl: 2.5 }}>
|
||||
{items.map((item, i) => (
|
||||
<Box
|
||||
component="li"
|
||||
key={i}
|
||||
sx={{ typography: 'body2', color: 'text.secondary', mb: 0.5 }}
|
||||
>
|
||||
{item}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full documentation block for one component. Reads the component's docs from
|
||||
* the registry extracted by the Vite plugin (from JSDoc in the source files).
|
||||
*
|
||||
* name — component name as tagged with `@component` in the source JSDoc
|
||||
*
|
||||
* Optionally accepts overrides for any field (e.g. `props`/`behaviour`) when a
|
||||
* mock page wants to add context on top of the source docs.
|
||||
*/
|
||||
export function ComponentDocs({ name, ...overrides }) {
|
||||
const doc = { ...getComponentDoc(name), ...overrides };
|
||||
const { importPath, defaultExport, description, props = [], behaviour = [] } = doc;
|
||||
|
||||
const importLine = importPath
|
||||
? defaultExport
|
||||
? `import ${name} from '${importPath}'`
|
||||
: `import { ${name} } from '${importPath}'`
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Paper variant="outlined" sx={{ mt: 3, p: 2.5 }}>
|
||||
<Typography variant="h6" sx={{ mb: 0.5 }}>
|
||||
{name}
|
||||
</Typography>
|
||||
{importLine ? (
|
||||
<Typography
|
||||
variant="caption"
|
||||
component="code"
|
||||
color="text.secondary"
|
||||
sx={{ display: 'block', fontFamily: 'monospace', mb: 1 }}
|
||||
>
|
||||
{importLine}
|
||||
</Typography>
|
||||
) : null}
|
||||
{description ? (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||
{description}
|
||||
</Typography>
|
||||
) : null}
|
||||
{props.length > 0 ? (
|
||||
<>
|
||||
<Typography variant="subtitle2" sx={{ mb: 1 }}>
|
||||
Props
|
||||
</Typography>
|
||||
<PropsTable props={props} />
|
||||
</>
|
||||
) : null}
|
||||
{behaviour.length > 0 ? (
|
||||
<>
|
||||
<Typography variant="subtitle2" sx={{ mt: 2.5, mb: 1 }}>
|
||||
Behaviour
|
||||
</Typography>
|
||||
<BehaviourList items={behaviour} />
|
||||
</>
|
||||
) : null}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
export default ComponentDocs;
|
||||
55
src/dev/DevApp.jsx
Normal file
55
src/dev/DevApp.jsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
import Tab from '@mui/material/Tab';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import PanelsMockPage from './mock-pages/PanelsMockPage';
|
||||
import TilesMockPage from './mock-pages/TilesMockPage';
|
||||
import PillsMockPage from './mock-pages/PillsMockPage';
|
||||
import TextFieldsMockPage from './mock-pages/TextFieldsMockPage';
|
||||
import ListsMockPage from './mock-pages/ListsMockPage';
|
||||
|
||||
const PAGES = [
|
||||
{ id: 'panels', label: 'Panels', node: <PanelsMockPage /> },
|
||||
{ id: 'lists', label: 'Listen', node: <ListsMockPage /> },
|
||||
{ id: 'tiles', label: 'Tiles', node: <TilesMockPage /> },
|
||||
{ id: 'pills', label: 'Pills', node: <PillsMockPage /> },
|
||||
{ id: 'textfields', label: 'Text fields', node: <TextFieldsMockPage /> },
|
||||
];
|
||||
|
||||
/**
|
||||
* Dev harness shell. Each tab renders a "mock page" exercising the library's
|
||||
* components with fake data — no backend, no redux. Future test cases will be
|
||||
* written against the same mock pages.
|
||||
*/
|
||||
class DevApp extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { tab: 'panels' };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tab } = this.state;
|
||||
const page = PAGES.find((p) => p.id === tab);
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 3, maxWidth: 1100, mx: 'auto' }}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
dashgui — component gallery
|
||||
</Typography>
|
||||
<Tabs
|
||||
value={tab}
|
||||
onChange={(_e, next) => this.setState({ tab: next })}
|
||||
sx={{ mb: 3 }}
|
||||
>
|
||||
{PAGES.map((p) => (
|
||||
<Tab key={p.id} value={p.id} label={p.label} />
|
||||
))}
|
||||
</Tabs>
|
||||
{page?.node}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { DevApp };
|
||||
17
src/dev/main.jsx
Normal file
17
src/dev/main.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { DevApp } from './DevApp';
|
||||
|
||||
// Standalone harness — mocks the consuming app's theme/bootstrap so the GUI
|
||||
// primitives can be inspected without a backend.
|
||||
const theme = createTheme({
|
||||
shape: { borderRadius: 4 },
|
||||
});
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<DevApp />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
154
src/dev/mock-pages/ListsMockPage.jsx
Normal file
154
src/dev/mock-pages/ListsMockPage.jsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Button from '@mui/material/Button';
|
||||
import RecordList from '../../lists/RecordList';
|
||||
import { ComponentDocs } from '../ComponentDocs';
|
||||
|
||||
const MOCK_ROWS = [
|
||||
{
|
||||
id: 1,
|
||||
number: 'L-1001',
|
||||
date: '2026-08-01',
|
||||
party: 'Müller GmbH',
|
||||
status: 'fertig',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
number: 'L-1002',
|
||||
date: '2026-08-03',
|
||||
party: 'Schmidt & Co',
|
||||
status: 'offen',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
number: 'L-1003',
|
||||
date: '2026-08-05',
|
||||
party: 'Weber OHG',
|
||||
status: 'offen',
|
||||
},
|
||||
];
|
||||
|
||||
const COLUMNS = [
|
||||
{ key: 'number', label: 'Nummer' },
|
||||
{ key: 'date', label: 'Lieferdatum' },
|
||||
{ key: 'party', label: 'Lieferant' },
|
||||
{
|
||||
key: 'status',
|
||||
label: 'Status',
|
||||
render: (row) => (
|
||||
<Chip
|
||||
size="small"
|
||||
label={row.status}
|
||||
color={row.status === 'fertig' ? 'success' : 'default'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Mock page exercising RecordList with fake in-memory rows — no storage
|
||||
* manager, no router, no toaster. Mirrors the shape the four dashfront list
|
||||
* pages share (Lieferungen / Angebote / Aufträge / Kunden).
|
||||
*/
|
||||
class ListsMockPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
status: 'ready',
|
||||
rows: MOCK_ROWS,
|
||||
log: [],
|
||||
};
|
||||
}
|
||||
|
||||
simulateLoading = () => {
|
||||
this.setState({ status: 'loading' });
|
||||
setTimeout(() => this.setState({ status: 'ready' }), 800);
|
||||
};
|
||||
|
||||
simulateFailure = () => {
|
||||
this.setState({ status: 'failed' });
|
||||
};
|
||||
|
||||
handleCreate = () => {
|
||||
this.log('create');
|
||||
};
|
||||
|
||||
handleEdit = (row) => {
|
||||
this.log(`edit ${row.number}`);
|
||||
};
|
||||
|
||||
handleDelete = (row) => {
|
||||
this.log(`delete ${row.number}`);
|
||||
this.setState((s) => ({ rows: s.rows.filter((r) => r.id !== row.id) }));
|
||||
};
|
||||
|
||||
log(msg) {
|
||||
this.setState((s) => ({ log: [msg, ...s.log].slice(0, 6) }));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status, rows, log } = this.state;
|
||||
const failedNode = status === 'failed' ? (
|
||||
<Typography variant="body2" color="error">
|
||||
Mock-Fehlerzustand (hier würde BackendError stehen).
|
||||
</Typography>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
||||
<Button size="small" variant="outlined" onClick={this.simulateLoading}>
|
||||
Laden
|
||||
</Button>
|
||||
<Button size="small" variant="outlined" color="error" onClick={this.simulateFailure}>
|
||||
Fehler
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
onClick={() =>
|
||||
this.setState({ status: 'ready', rows: MOCK_ROWS, log: [] })
|
||||
}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<RecordList
|
||||
status={status}
|
||||
error={failedNode}
|
||||
rows={rows}
|
||||
columns={COLUMNS}
|
||||
createLabel="Neue Lieferung"
|
||||
onCreate={this.handleCreate}
|
||||
onEdit={this.handleEdit}
|
||||
onDelete={this.handleDelete}
|
||||
deleteDisabled={false}
|
||||
emptyMessage="Noch keine Lieferungen."
|
||||
color="#fed7aa"
|
||||
getEditLabel={(r) => `„${r.number}“ bearbeiten`}
|
||||
getDeleteLabel={(r) => `„${r.number}“ löschen`}
|
||||
/>
|
||||
|
||||
{log.length > 0 ? (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Aktionen:
|
||||
</Typography>
|
||||
{log.map((entry, i) => (
|
||||
<Typography key={i} variant="caption" display="block">
|
||||
• {entry}
|
||||
</Typography>
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
<ComponentDocs name="RecordList" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ListsMockPage;
|
||||
128
src/dev/mock-pages/PanelsMockPage.jsx
Normal file
128
src/dev/mock-pages/PanelsMockPage.jsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { EditablePanelTile, PanelTile, PanelTileGrid } from '../../panels';
|
||||
import SingleLineTextEdit from '../../SingleLineTextEdit';
|
||||
import { ComponentDocs } from '../ComponentDocs';
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock page exercising PanelTile / EditablePanelTile with fake in-memory data.
|
||||
* `onError` is passed to simulate the consuming app's error snackbar.
|
||||
*/
|
||||
class PanelsMockPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
companyName: 'ACME GmbH',
|
||||
productName: 'Erdnussbutter 350g',
|
||||
lastSaved: null,
|
||||
errors: [],
|
||||
};
|
||||
}
|
||||
|
||||
handleSave = async (next) => {
|
||||
// Simulated latency so the save spinner is visible.
|
||||
await sleep(600);
|
||||
this.setState({ companyName: next, lastSaved: next });
|
||||
};
|
||||
|
||||
handleProductSave = async (next) => {
|
||||
await sleep(600);
|
||||
this.setState({ productName: next, lastSaved: next });
|
||||
};
|
||||
|
||||
// Mirrors the consuming app's notifyError: returns a normalized { message }.
|
||||
handleError = (err) => {
|
||||
const message = String(err?.message ?? err ?? 'Unbekannter Fehler');
|
||||
this.setState((prev) => ({ errors: [message, ...prev.errors].slice(0, 5) }));
|
||||
return { message };
|
||||
};
|
||||
|
||||
render() {
|
||||
const { companyName, productName, lastSaved, errors } = this.state;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<PanelTileGrid>
|
||||
<EditablePanelTile
|
||||
wide={2}
|
||||
title="Firma"
|
||||
value={companyName}
|
||||
onSave={this.handleSave}
|
||||
onError={this.handleError}
|
||||
display={
|
||||
<Typography variant="body1">{companyName || '—'}</Typography>
|
||||
}
|
||||
edit={({ draft, onChange, inputRef }) => (
|
||||
<SingleLineTextEdit
|
||||
label="Name"
|
||||
value={draft}
|
||||
onChange={onChange}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<EditablePanelTile
|
||||
wide={1}
|
||||
title="Produkt"
|
||||
color="#e2e8f0"
|
||||
value={productName}
|
||||
onSave={this.handleProductSave}
|
||||
onError={this.handleError}
|
||||
display={
|
||||
<Typography variant="body1">{productName || '—'}</Typography>
|
||||
}
|
||||
edit={({ draft, onChange, inputRef }) => (
|
||||
<SingleLineTextEdit
|
||||
label="Name"
|
||||
value={draft}
|
||||
onChange={onChange}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<PanelTile wide={1} title="Nur anzeigen" color="#fef3c7">
|
||||
<Typography variant="body2">
|
||||
PanelTile ohne action — read-only.
|
||||
</Typography>
|
||||
</PanelTile>
|
||||
</PanelTileGrid>
|
||||
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{lastSaved != null
|
||||
? `Zuletzt gespeichert: ${lastSaved}`
|
||||
: 'Noch nichts gespeichert.'}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{errors.length > 0 ? (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="caption" color="error">
|
||||
Mock-Fehler (würde als Snackbar erscheinen):
|
||||
</Typography>
|
||||
{errors.map((e, i) => (
|
||||
<Typography key={i} variant="caption" display="block" color="error">
|
||||
• {e}
|
||||
</Typography>
|
||||
))}
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
<ComponentDocs name="PanelTile" />
|
||||
|
||||
<ComponentDocs name="PanelTileGrid" />
|
||||
|
||||
<ComponentDocs name="EditablePanelTile" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PanelsMockPage;
|
||||
55
src/dev/mock-pages/PillsMockPage.jsx
Normal file
55
src/dev/mock-pages/PillsMockPage.jsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import ToggleOnIcon from '@mui/icons-material/ToggleOn';
|
||||
import {
|
||||
ActionElevatedPill,
|
||||
ToggleElevatedPill,
|
||||
} from '../../ElevatedPill';
|
||||
import ElevatedPill from '../../ElevatedPill';
|
||||
import { ComponentDocs } from '../ComponentDocs';
|
||||
|
||||
class PillsMockPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { enabled: true, active: true };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { enabled, active } = this.state;
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||
<Typography variant="body2" sx={{ mr: 1 }}>
|
||||
Toggle:
|
||||
</Typography>
|
||||
<ToggleElevatedPill
|
||||
label="Sichtbar"
|
||||
checked={enabled}
|
||||
onToggle={(next) => this.setState({ enabled: next })}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
||||
<Typography variant="body2" sx={{ mr: 1 }}>
|
||||
Action:
|
||||
</Typography>
|
||||
<ActionElevatedPill
|
||||
label="Aktiv"
|
||||
active={active}
|
||||
onClick={() => this.setState((s) => ({ active: !s.active }))}
|
||||
icon={<ToggleOnIcon sx={{ fontSize: 18 }} />}
|
||||
/>
|
||||
<ElevatedPill label="Statisch" />
|
||||
</Box>
|
||||
|
||||
<ComponentDocs name="ElevatedPill" />
|
||||
|
||||
<ComponentDocs name="ToggleElevatedPill" />
|
||||
|
||||
<ComponentDocs name="ActionElevatedPill" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PillsMockPage;
|
||||
48
src/dev/mock-pages/TextFieldsMockPage.jsx
Normal file
48
src/dev/mock-pages/TextFieldsMockPage.jsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import SingleLineTextEdit from '../../SingleLineTextEdit';
|
||||
import { ComponentDocs } from '../ComponentDocs';
|
||||
|
||||
class TextFieldsMockPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { name: '', note: 'Schreibgeschützt' };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { name, note } = this.state;
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
maxWidth: 480,
|
||||
}}
|
||||
>
|
||||
<SingleLineTextEdit
|
||||
label="Name"
|
||||
value={name}
|
||||
onChange={(next) => this.setState({ name: next })}
|
||||
helperText="Gemeinsames Einzeilen-Feld"
|
||||
/>
|
||||
<SingleLineTextEdit
|
||||
label="Nur lesen"
|
||||
value={note}
|
||||
readOnly
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Aktueller Wert: {JSON.stringify(name)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<ComponentDocs name="SingleLineTextEdit" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TextFieldsMockPage;
|
||||
76
src/dev/mock-pages/TilesMockPage.jsx
Normal file
76
src/dev/mock-pages/TilesMockPage.jsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Tile, tileBaseSx, TILE_SIZE } from '../../tiles';
|
||||
import FolderIcon from '@mui/icons-material/FolderOutlined';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import { ComponentDocs } from '../ComponentDocs';
|
||||
|
||||
class MockFolderTile extends Tile {
|
||||
renderIcon() {
|
||||
return <FolderIcon color="action" sx={{ fontSize: 40 }} />;
|
||||
}
|
||||
}
|
||||
|
||||
class MockAddTile extends Tile {
|
||||
renderIcon() {
|
||||
return <AddIcon color="primary" sx={{ fontSize: 40 }} />;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock page exercising the base Tile primitive with subclasses, mirroring how
|
||||
* dashfront's ActionTile/CategoryTile/etc. extend it.
|
||||
*/
|
||||
class TilesMockPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { clicks: 0 };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { clicks } = this.state;
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="body2" sx={{ mb: 2 }}>
|
||||
Klicks: {clicks}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: `repeat(auto-fill, minmax(${TILE_SIZE}px, 1fr))`,
|
||||
gap: 2,
|
||||
maxWidth: 640,
|
||||
}}
|
||||
>
|
||||
<MockFolderTile
|
||||
label="Ordner"
|
||||
secondary="3 Artikel"
|
||||
onClick={() => this.setState((s) => ({ clicks: s.clicks + 1 }))}
|
||||
/>
|
||||
<MockAddTile
|
||||
label="Neu"
|
||||
secondary="anlegen"
|
||||
onClick={() => this.setState((s) => ({ clicks: s.clicks + 1 }))}
|
||||
/>
|
||||
<MockFolderTile
|
||||
label="Deaktiviert"
|
||||
secondary="nicht klickbar"
|
||||
disabled
|
||||
/>
|
||||
<Box sx={{ ...tileBaseSx, bgcolor: 'primary.main', color: 'white' }}>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
tileBaseSx direkt
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<ComponentDocs name="Tile" />
|
||||
|
||||
<ComponentDocs name="tileBaseSx" />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TilesMockPage;
|
||||
Reference in New Issue
Block a user