Turtor Docs
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

KategorieAdresářKlíčové komponenty
Základní (shadcn)components/*.tsxButton, Input, Card, Dialog, Select, Badge, Tabs
Kalendářcomponents/calendar/WeeklyCalendar, MiniMonthCalendar
Datová tabulkacomponents/data-table/DataTable, DataTableColumnHeader, DataTableFilters
Zobrazenícomponents/display/PriceDisplay, CompactPriceDisplay
Zpětná vazbacomponents/feedback/StatusBadge, EmptyState, LoadingSpinner, PageSkeleton
Formuláře (TanStack)components/form/Form, FormInput, FormSelect, FormDatePicker
Layoutcomponents/layout/PageHeader, StatsCard, SplitView, KanbanBoard
Field (raw layout)components/field.tsxField, 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

KomponentaTyp hodnotyExtra props
FormInputstringVšechny InputProps (type, placeholder, ...)
FormTextareastringVšechny TextareaProps
FormSelectstringoptions: { value, label }[], placeholder?
FormCheckboxbooleandisabled?
FormDatePickerDate | undefinedfromDate?, toDate?, placeholder?
FormTimePickerstringminTime?, 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 tabulky

Toast 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-name

Poté exportovat z packages/ui/src/index.ts a sestavit balíček:

pnpm build --filter=@turtor/ui