Frontend
Komponenty
shadcn/ui knihovna, Field pattern, TanStack Form a @turtor/ui
UI komponenty jsou centralizované v balíčku @turtor/ui postaveném na shadcn/ui s Tailwind CSS v4.
Import
import { Button, Card, Input, Dialog, Badge } from '@turtor/ui';Kategorie komponent
| Kategorie | Adresář | Klíčové komponenty |
|---|---|---|
| Základní (shadcn) | components/*.tsx | Button, Input, Card, Dialog, Select, Badge, Tabs |
| Kalendář | components/calendar/ | WeeklyCalendar, MiniMonthCalendar |
| Datová tabulka | components/data-table/ | DataTable, DataTableColumnHeader, DataTableFilters |
| Zobrazení | components/display/ | PriceDisplay, CompactPriceDisplay |
| Zpětná vazba | components/feedback/ | StatusBadge, EmptyState, LoadingSpinner, PageSkeleton |
| Formuláře (TanStack) | components/form/ | Form, FormInput, FormSelect, FormDatePicker |
| Layout | components/layout/ | PageHeader, StatsCard, SplitView, KanbanBoard |
| Field (raw layout) | components/field.tsx | Field, FieldGroup, FieldLabel, FieldError |
Field pattern
Standardní vzor pro formulářová pole v admin aplikaci:
import { Field, FieldGroup, FieldLabel, FieldError, Input } from '@turtor/ui';
// Základní vertikální pole
<Field>
<FieldLabel htmlFor="email">E-mail</FieldLabel>
<Input id="email" type="email" />
</Field>
// Horizontální pole (label + input vedle sebe)
<Field orientation="horizontal">
<FieldLabel htmlFor="name">Jméno</FieldLabel>
<Input id="name" />
</Field>
// Responzivní (vertikální na mobilu, horizontální na desktopu)
<Field orientation="responsive">
<FieldLabel htmlFor="phone">Telefon</FieldLabel>
<Input id="phone" />
</Field>
// Pole s chybou
<Field>
<FieldLabel htmlFor="name">Jméno *</FieldLabel>
<Input id="name" />
<FieldError>Jméno je povinné</FieldError>
</Field>
// Skupina polí
<FieldGroup>
<Field>
<FieldLabel htmlFor="firstName">Křestní jméno</FieldLabel>
<Input id="firstName" />
</Field>
<Field>
<FieldLabel htmlFor="lastName">Příjmení</FieldLabel>
<Input id="lastName" />
</Field>
</FieldGroup>TanStack Form komponenty
Wrapper komponenty pro TanStack Form s automatickou validací:
import { Form, useForm, FormInput, FormSelect } from '@turtor/ui';
function MujFormular() {
const form = useForm({
defaultValues: { email: '', role: '' },
onSubmit: async ({ value }) => {
await ulozitData(value);
},
});
return (
<Form form={form}>
<form.Field name="email">
{(field) => <FormInput field={field} label="E-mail" required />}
</form.Field>
<form.Field name="role">
{(field) => (
<FormSelect
field={field}
label="Role"
options={[
{ value: 'admin', label: 'Administrátor' },
{ value: 'user', label: 'Uživatel' },
]}
/>
)}
</form.Field>
<Button type="submit">Uložit</Button>
</Form>
);
}Dostupné form komponenty
| Komponenta | Typ hodnoty | Extra props |
|---|---|---|
FormInput | string | Všechny InputProps (type, placeholder, ...) |
FormTextarea | string | Všechny TextareaProps |
FormSelect | string | options: { value, label }[], placeholder? |
FormCheckbox | boolean | disabled? |
FormDatePicker | Date | undefined | fromDate?, toDate?, placeholder? |
FormTimePicker | string | minTime?, maxTime?, step? (výchozí 30 min) |
DataTable
TanStack Table wrapper s řazením, filtrováním a paginací:
import { DataTable, DataTableColumnHeader } from '@turtor/ui';
// Server-side paginace (řízená)
<DataTable
columns={columns}
data={data}
loading={isLoading}
pagination={{ pageIndex, pageSize }}
onPaginationChange={setPagination}
pageCount={totalPages}
manualPagination
sorting={sorting}
onSortingChange={setSorting}
manualSorting
onRowClick={(row) => navigate({ to: `/courses/${row.id}` })}
emptyState={<EmptyState title="Žádné kurzy" />}
/>StatusBadge
Generický badge řízený konfiguračními objekty z @turtor/shared:
import { StatusBadge } from '@turtor/ui';
import { INSTRUCTOR_STATUS_CONFIG } from '@turtor/shared';
<StatusBadge status={instructor.status} config={INSTRUCTOR_STATUS_CONFIG} />PageSkeleton
Předpřipravené skeleton layouty pro běžné typy stránek:
import { PageSkeleton } from '@turtor/ui';
<PageSkeleton variant="dashboard" /> // Mřížka statistik + obsah
<PageSkeleton variant="list" /> // Filtry + seznam + paginace
<PageSkeleton variant="detail" /> // Breadcrumb + hlavička + 2-sloupcový layout
<PageSkeleton variant="kanban" /> // Kanban sloupce s kartami
<PageSkeleton variant="form" /> // Formulářová pole v kartěStatsCard
Metriková karta pro dashboard:
import { StatsCard } from '@turtor/ui';
<StatsCard
title="Celkem kurzů"
value={42}
description="oproti minulému měsíci"
icon={<BookOpen className="h-4 w-4" />}
trend={{ value: 12, isPositive: true, label: 'od minulého měsíce' }}
/>PriceDisplay
České formátování cen:
import { PriceDisplay, CompactPriceDisplay } from '@turtor/ui';
<PriceDisplay amount={1500} /> // "1 500 Kč"
<PriceDisplay amount={1500} suffix="za osobu" /> // "1 500 Kč za osobu"
<PriceDisplay amount={null} fallback="Neurčeno" /> // "Neurčeno"
<CompactPriceDisplay amount={1500} /> // Kompaktní pro tabulkyToast notifikace
import { toast } from 'sonner';
toast.success('Úspěšně uloženo');
toast.error('Něco se pokazilo');
toast.promise(asyncFn, {
loading: 'Ukládám...',
success: 'Uloženo!',
error: 'Chyba při ukládání',
});Utility (cn)
Sloučení Tailwind tříd:
import { cn } from '@turtor/ui';
<div className={cn(
'base-classes',
isActive && 'active-classes',
variant === 'primary' && 'primary-classes',
)} />Přidání nové komponenty
cd packages/ui
npx shadcn@latest add component-namePoté exportovat z packages/ui/src/index.ts a sestavit balíček:
pnpm build --filter=@turtor/ui