Files
app/src/admin/pages/UiKit.tsx

367 lines
11 KiB
TypeScript

import { useState } from "react";
import { Link as RouterLink } from "react-router-dom";
import ScopedCssBaseline from "@mui/material/ScopedCssBaseline";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import {
Button,
Card,
TextField,
Select,
StatusChip,
Tabs,
TabPanel,
Pagination,
CheckboxField,
Alert,
DataTable,
DateField,
type DataColumn,
PageHeader,
EmptyState,
LoadingState,
FilterBar,
StatCard,
} from "../ui";
import { useTheme } from "../../context/ThemeContext";
const BoxIcon = (
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
</svg>
);
const InboxIcon = (
<svg
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
>
<polyline points="22 12 16 12 14 15 10 15 8 12 2 12" />
<path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
</svg>
);
interface DemoRow {
id: number;
name: string;
qty: number;
}
const DEMO_ROWS: DemoRow[] = [
{ id: 1, name: "Beta", qty: 30 },
{ id: 2, name: "Alfa", qty: 10 },
{ id: 3, name: "Gama", qty: 20 },
];
function SectionLabel({ children }: { children: React.ReactNode }) {
return (
<Typography
variant="overline"
color="text.secondary"
display="block"
mt={2}
>
{children}
</Typography>
);
}
export default function UiKit() {
const { theme, toggleTheme } = useTheme();
const [selectVal, setSelectVal] = useState("a");
const [tab, setTab] = useState("one");
const [page, setPage] = useState(2);
const [checked, setChecked] = useState(true);
const [date, setDate] = useState("2026-06-06");
const [sortBy, setSortBy] = useState("name");
const [sortDir, setSortDir] = useState<"asc" | "desc">("asc");
const [lastClicked, setLastClicked] = useState<string | null>(null);
const onSort = (key: string) => {
if (sortBy === key) setSortDir((d) => (d === "asc" ? "desc" : "asc"));
else {
setSortBy(key);
setSortDir("asc");
}
};
const sortedRows = [...DEMO_ROWS].sort((a, b) => {
const cmp = String(a[sortBy as keyof DemoRow]).localeCompare(
String(b[sortBy as keyof DemoRow]),
"cs",
{ numeric: true },
);
return sortDir === "asc" ? cmp : -cmp;
});
const columns: DataColumn<DemoRow>[] = [
{ key: "name", header: "Název", sortKey: "name", render: (r) => r.name },
{
key: "qty",
header: "Množství",
align: "right",
mono: true,
sortKey: "qty",
render: (r) => r.qty,
},
];
return (
<ScopedCssBaseline>
<Box sx={{ p: 4, minHeight: "100vh", bgcolor: "background.default" }}>
<Stack direction="row" alignItems="center" spacing={2} mb={3}>
<Typography variant="h4">UI Kit</Typography>
<Button color="inherit" variant="outlined" onClick={toggleTheme}>
Theme: {theme}
</Button>
</Stack>
<Stack spacing={3} sx={{ maxWidth: 640 }}>
<Card>
<Typography variant="h6" gutterBottom>
Faktury
</Typography>
<Typography color="text.secondary" gutterBottom>
12 vystavených tento měsíc
</Typography>
<Stack direction="row" spacing={1} mb={2}>
<StatusChip label="Zaplaceno" color="success" />
<StatusChip label="Po splatnosti" color="error" />
</Stack>
<TextField
label="Hledat fakturu"
placeholder="Číslo nebo klient…"
/>
<Box mt={2}>
<Button>Nová faktura</Button>
</Box>
</Card>
<Card>
<Typography variant="h6">Kit Phase 3</Typography>
<SectionLabel>Select</SectionLabel>
<Select
value={selectVal}
onChange={setSelectVal}
options={[
{ value: "a", label: "Možnost A" },
{ value: "b", label: "Možnost B" },
{ value: "c", label: "Možnost C" },
]}
/>
<SectionLabel>StatusChip</SectionLabel>
<Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
<StatusChip label="default" />
<StatusChip label="success" color="success" />
<StatusChip label="error" color="error" />
<StatusChip label="warning" color="warning" />
<StatusChip label="info" color="info" />
<StatusChip
label="clickable"
color="success"
onClick={() => {}}
/>
</Stack>
<SectionLabel>Tabs</SectionLabel>
<Tabs
value={tab}
onChange={setTab}
tabs={[
{ value: "one", label: "První" },
{ value: "two", label: "Druhá" },
]}
/>
<TabPanel value="one" current={tab}>
<Typography>Obsah první záložky.</Typography>
</TabPanel>
<TabPanel value="two" current={tab}>
<Typography>Obsah druhé záložky.</Typography>
</TabPanel>
<SectionLabel>Sortable DataTable + Pagination</SectionLabel>
<DataTable<DemoRow>
columns={columns}
rows={sortedRows}
rowKey={(r) => r.id}
sortBy={sortBy}
sortDir={sortDir}
onSort={onSort}
/>
<Pagination page={page} pageCount={5} onChange={setPage} />
<SectionLabel>DateField + Checkbox</SectionLabel>
<DateField value={date} onChange={setDate} label="Datum" />
<Box>
<CheckboxField
label="Souhlasím"
checked={checked}
onChange={setChecked}
/>
</Box>
<SectionLabel>Alert</SectionLabel>
<Stack spacing={1}>
<Alert severity="success">Úspěšně uloženo.</Alert>
<Alert severity="error">Něco se pokazilo.</Alert>
<Alert severity="warning">Pozor na toto.</Alert>
<Alert severity="info">Informace.</Alert>
</Stack>
</Card>
{/* ── Phase 6 primitives ── */}
<Card>
<Typography variant="h6">Kit Phase 6 Primitives</Typography>
<SectionLabel>PageHeader title only</SectionLabel>
<PageHeader title="Přehled projektů" />
<SectionLabel>PageHeader with subtitle + actions</SectionLabel>
<PageHeader
title="Sklady"
subtitle="Správa skladových zásob"
actions={
<>
<Button variant="outlined" color="inherit" size="small">
Export
</Button>
<Button size="small">Nová položka</Button>
</>
}
/>
<SectionLabel>EmptyState icon + action</SectionLabel>
<EmptyState
icon={InboxIcon}
title="Žádné záznamy"
description="Zatím nebyly přidány žádné položky."
action={<Button size="small">Přidat první položku</Button>}
/>
<SectionLabel>EmptyState title only</SectionLabel>
<EmptyState title="Žádné výsledky" />
<SectionLabel>LoadingState</SectionLabel>
<LoadingState label="Načítám data…" />
<SectionLabel>FilterBar</SectionLabel>
<FilterBar>
<Box sx={{ width: 200 }}>
<TextField placeholder="Hledat…" />
</Box>
<Box sx={{ width: 160 }}>
<Select
value={selectVal}
onChange={setSelectVal}
options={[
{ value: "a", label: "Všechny stavy" },
{ value: "b", label: "Aktivní" },
{ value: "c", label: "Uzavřené" },
]}
/>
</Box>
<Button size="small" variant="outlined" color="inherit">
Resetovat
</Button>
</FilterBar>
<SectionLabel>StatCard grid all colors</SectionLabel>
<Box
sx={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
gap: 1.5,
}}
>
<StatCard label="Celkem" value="1 240" icon={BoxIcon} />
<StatCard
label="Aktivní"
value="38"
icon={BoxIcon}
color="primary"
/>
<StatCard
label="Dokončené"
value="112"
icon={BoxIcon}
color="success"
footer="↑ 12 oproti minulému měsíci"
/>
<StatCard
label="Varování"
value="5"
icon={BoxIcon}
color="warning"
/>
<StatCard label="Chyby" value="2" icon={BoxIcon} color="error" />
<StatCard
label="Informace"
value="99"
icon={BoxIcon}
color="info"
/>
</Box>
<SectionLabel>
DataTable onRowClick + rowDanger (row 2 = danger)
</SectionLabel>
{lastClicked && (
<Typography
variant="caption"
color="text.secondary"
mb={1}
display="block"
>
Naposledy kliknuto: {lastClicked}
</Typography>
)}
<DataTable<DemoRow>
columns={columns}
rows={DEMO_ROWS}
rowKey={(r) => r.id}
onRowClick={(r) => setLastClicked(r.name)}
rowDanger={(r) => r.id === 2}
rowInactive={(r) => r.id === 3}
/>
<SectionLabel>Button as RouterLink</SectionLabel>
<Stack direction="row" spacing={1}>
<Button
component={RouterLink}
to="/ui-kit"
variant="outlined"
color="inherit"
size="small"
>
RouterLink button (current page)
</Button>
<Button
component="a"
href="https://mui.com"
target="_blank"
rel="noopener"
size="small"
variant="outlined"
color="inherit"
>
Anchor button
</Button>
</Stack>
</Card>
</Stack>
</Box>
</ScopedCssBaseline>
);
}