367 lines
11 KiB
TypeScript
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>
|
|
);
|
|
}
|