Getting Started
Introduction
The Smejkal Design System is a unified set of tokens, components, and conventions that keeps the admin dashboard and this documentation site visually consistent. It is built on Tailwind CSS v4, Radix UI primitives, class-variance-authority, and a token vocabulary that lives in @repo/ui.
Stack
Every layer of the system has a specific job. Tailwind v4 handles utility classes and the @theme inline bridge that turns CSS custom properties into utilities. Radix UI provides the accessible primitive behavior for interactive components. CVA manages variant logic so component APIs stay clean. Lucide React supplies all icons through a single consistent set.
| Layer | Technology | Purpose |
|---|---|---|
| Styling engine | Tailwind CSS v4 | Utility classes, token bridge via @theme inline |
| Primitives | Radix UI | Accessible keyboard behavior, focus management, ARIA |
| Variant API | class-variance-authority (CVA) | Type-safe component variant definitions |
| Class merging | tailwind-merge + clsx via cn() | Conflict-free class composition at runtime |
| Icons | lucide-react | Named icon imports, consistent stroke weight |
| Shared tokens | @repo/ui/theme.css | Single source of truth for all CSS custom properties |
| Shared components | @repo/ui/src/components/ | Atom-level components consumed by all apps |
Key principles
Token-driven
Every color, radius, and shadow is a CSS custom property. Apps import the shared @repo/ui/theme.css token file and expose each token as a Tailwind utility via @theme inline in their own globals.css. Changing a design decision in one place propagates to every app automatically.
Dark-first
Both the admin app and this docs site apply class="dark" to the HTML element. The token system defines light mode values in :root and dark overrides under the .dark selector. Dark is the default; light mode support is available whenever it is needed.
Accessible by default
All interactive components are built on Radix UI primitives, which provide keyboard navigation, focus trap management, and correct ARIA attributes out of the box. Focus rings use the brand green at 40% opacity so they are visible without being distracting.
Composable
Atom components live in @repo/ui/src/components/ and are imported through the workspace path alias @repo/ui/components/[name]. Page-level patterns — data tables, confirmation dialogs, action bars — are composed from atoms inside each app rather than being baked into the shared package.
Package structure
The monorepo is a Turborepo + pnpm workspace. Design system concerns are spread across three packages:
| Package | Contents |
|---|---|
@repo/ui | Shared components, theme.css token file, cn() utility, CVA helpers |
@repo/types | Shared TypeScript interfaces (Supabase row types, component prop types) |
@repo/config | Shared ESLint, TypeScript, and Tailwind configuration presets |
Each app — apps/web, apps/admin, and apps/docs — installs the workspace packages and adds its ownglobals.css with app-specific @theme inlineoverrides where needed.
How to use this documentation
The sections in the left sidebar follow the order you would encounter each layer when building a new feature: start with accessibility constraints, then choose colors from the token vocabulary, follow writing conventions for copy, use icons consistently, understand the Tailwind utility mapping, grasp the theming architecture, and finally apply the typography system for long-form content.
This design system is intentionally opinionated. When in doubt, prefer the token over a hard-coded value, prefer an existing component over a one-off, and prefer the established naming convention over a new one.