--- paths: - "src/components/**" - "src/app/**/page.tsx" - "src/app/**/layout.tsx" - "src/hooks/**" --- # Frontend Rules ## shadcn/ui first (mandatory) Pre-installed: `button`, `card`, `input`, `label`, `form`, `sonner`. Before building any UI element, check `ls src/components/ui/`. If shadcn has the component and it is not installed yet, install it — do not hand-write it: ```bash npx shadcn@latest add dialog table tabs --yes ``` Never write a custom Button, Input, Select, Checkbox, Switch, Dialog, Alert, Table, Tabs, Card, Badge, Dropdown, Popover, Tooltip, Sidebar or Breadcrumb. Custom components are only compositions of these primitives plus business logic. ## Tailwind v4 - **There is no `tailwind.config.ts`.** Theme tokens live in `src/app/globals.css` under `@theme inline`. Add a design token there, not in a config file. - Use semantic tokens (`bg-background`, `text-muted-foreground`, `border-border`), not raw palette values like `bg-slate-900` — otherwise dark mode breaks. - Tailwind classes only. No inline `style`, no CSS modules. ## Component Standards - TypeScript interfaces for all props - Responsive at 375px / 768px / 1440px - Every data-driven component handles three states: loading, error, empty - Semantic HTML and ARIA labels; keyboard reachable - Server Components by default — add `'use client'` only when you need state, effects or browser APIs ## Feedback and Theming - Toasts via `sonner`: `import { toast } from 'sonner'`. The `Toaster` is already mounted in `layout.tsx` — do not mount a second one. - Dark mode is class-based via next-themes; never read the theme during render in a way that differs between server and client (hydration mismatch) ## Forms `react-hook-form` + `zod` through `@hookform/resolvers/zod`, using the shadcn `form` component. The Zod schema is the single source of truth — the same schema validates again on the server.