# 05a — Template Map (installed template)

> **Stack note.** The installed "admin template" is the **Laravel React Starter
> Kit**: Inertia.js + React + TypeScript + **shadcn/ui** (`radix-nova` style,
> Tabler + Lucide icons) on **Tailwind v4**, built with Vite. This supersedes the
> Blade/Alpine assumption in the older docs (see CLAUDE.md "Stack reality").
> **All feature UI is built ONLY from the primitives inventoried here.** A missing
> primitive is added once under `resources/js/components/ui/` (registry-style) or
> `resources/js/components/` (composed), never hand-rolled per page.

Component source of truth: `resources/js/components/ui/*` (shadcn primitives) and
`resources/js/components/*` (app-composed). Design tokens: `resources/css/app.css`
(`@theme` + CSS custom properties). Brand tokens are defined in §Branding of
`app.css` and mapped onto the shadcn semantic tokens — never hardcode hex in a
page.

## 1. Buttons — `components/ui/button.tsx`

`<Button variant size asChild>`. Variants map to the brand as follows:

| Variant | Token used | Brand meaning / use |
|---|---|---|
| `default` | `bg-primary` (= Gold) | Primary action (one per view) |
| `secondary` | `bg-secondary` (Charcoal-2 surface) | Secondary action |
| `outline` | bordered, transparent | Tertiary / cancel |
| `ghost` | hover-only | Toolbar / row actions, icon buttons |
| `destructive` | `destructive` (red, tinted) | Delete / reverse / suspend |
| `link` | `text-primary` underline | Inline navigation |

Sizes: `xs · sm · default · lg` and icon-only `icon-xs · icon-sm · icon · icon-lg`.
Focus ring is `ring-ring/50` (mapped to Gold). **Never strip the focus ring.**
Loading state: pair with `<Spinner/>` + `disabled` + "Saving…" label.

## 2. Cards — `components/ui/card.tsx`

`Card` + `CardHeader` / `CardTitle` / `CardDescription` / `CardAction` /
`CardContent` / `CardFooter`. Surface = `bg-card` (Charcoal-2). Used for KPI
tiles, form section groups, tab panels, and empty-state containers.

## 3. Tables — **GAP → added as `components/ui/table.tsx`**

The kit ships no table primitive. Added once as a shadcn-style `Table / TableHeader
/ TableBody / TableRow / TableHead / TableCell / TableCaption` set, plus an
app-composed `<DataTable>` (`components/data-table.tsx`) providing the standard
list affordances from 05-UI-UX §5: sticky header, sortable column headers,
row-action kebab (`DropdownMenu`), pagination, and an integrated empty state.
All list pages use `<DataTable>` — never a bespoke `<table>`.

## 4. Form controls

| Control | Component | Notes |
|---|---|---|
| Text / email / number | `ui/input.tsx` | `aria-invalid` drives the error ring |
| Textarea | `ui/input.tsx` (multiline) | — |
| Select | `ui/select.tsx` (Radix) | replaces select2; searchable variant if needed |
| Checkbox | `ui/checkbox.tsx` | — |
| Toggle / switch | `ui/toggle.tsx`, `ui/toggle-group.tsx` | booleans, segmented control |
| Label | `ui/label.tsx` | always `htmlFor` bound (a11y) |
| OTP input | `ui/input-otp.tsx` | 2FA challenge / recovery codes |
| Password | `components/password-input.tsx` | show/hide toggle |
| Field error | `components/input-error.tsx` | inline, under field |
| Date picker | **GAP** — add when M03 needs it (native `<input type=date>` until then) |
| Rich text / file upload | **GAP** — deferred to M08 (documents) |

Form pattern: Inertia `useForm`; server errors map to fields via `errors`; old
input preserved by Inertia automatically; 4+ errors → top summary `Alert`.

## 5. Modals & sheets

- `ui/dialog.tsx` — confirms, quick-create, single-field quick edits.
  App-composed `components/confirm-dialog.tsx` wraps it for destructive confirms
  (with optional typed-confirmation "DELETE"). Never a full multi-tab form.
- `ui/sheet.tsx` — slide-over panel (filters, quick detail peeks).
- `ui/alert-dialog` — **GAP**; `confirm-dialog` built on `dialog` covers it.

## 6. Badges / pills — `components/ui/badge.tsx`

Variants `default (Gold) · secondary · destructive · outline · ghost · link`.
Status colors from 05-UI-UX §4 are provided as an app-composed
`components/status-badge.tsx` mapping semantic status → filled badge with text
(green/amber/red/blue/grey) so color is never the only signal.

## 7. Tabs — **GAP → added as `components/ui/tabs.tsx`**

Radix `Tabs / TabsList / TabsTrigger / TabsContent`, styled to brand. Used for
every entity detail page (Overview | … | Timeline | Comments). `toggle-group`
exists but is a segmented control, not page tabs — do not repurpose it.

## 8. Toasts — `components/ui/sonner.tsx` (Sonner)

Global `<Toaster/>` mounted in `app.tsx`. `toast.success/error(...)` for every
create/update/delete and recoverable error. Flash messages from the server are
bridged to Sonner via shared Inertia props (`flash.success` / `flash.error`).
**Never `window.alert()`.**

## 9. Charts — **GAP → deferred**

No chart library is installed (no Recharts/Chart.js). Phase-0 dashboards use
empty-state cards only. When M10/Phase-5 needs charts, add **Recharts** once and
theme its series to the brand palette (Gold, Gold Muted, Text Muted + semantic
status colors) — never the library's rainbow defaults (05-UI-UX §8).

## 10. Empty state — **GAP → added as `components/empty-state.tsx`**

The kit ships only `ui/placeholder-pattern.tsx` (decorative SVG). The mandated
empty-state pattern (icon + one sentence + optional primary action, 05-UI-UX §4)
is an app-composed `<EmptyState icon title description action />`, used inside
`DataTable`, dashboard cards, and any empty tab.

## 11. Supporting primitives (present, reused as-is)

`avatar` · `breadcrumb` (→ `components/breadcrumbs.tsx`) · `separator` ·
`skeleton` (table/loading states) · `spinner` · `tooltip` · `dropdown-menu`
(row/user menus) · `navigation-menu` · `sidebar` (`ui/sidebar.tsx` +
`components/app-sidebar.tsx`) · `collapsible` · `icon` (Tabler wrapper) ·
`user-info` / `nav-user` / `nav-main` / `nav-footer`.

## 12. Layouts (shells)

- `layouts/app-layout.tsx` → `app/app-sidebar-layout.tsx` — **staff shell**
  (`AppShell` + `AppSidebar` + `AppSidebarHeader` with breadcrumbs).
- `layouts/auth-layout.tsx` (`auth-simple` / `auth-card` / `auth-split`) — auth.
- Portal & print shells — **GAP**, added in their phases (M11 portal, PDF print).

## 13. Gaps summary (add-once list)

| Gap | Where | When |
|---|---|---|
| `table.tsx` + `DataTable` | `ui/` + `components/` | M01 (needed now) |
| `tabs.tsx` | `ui/` | M01 (detail pages) |
| `empty-state.tsx` | `components/` | M01 (needed now) |
| `status-badge.tsx` | `components/` | M01 |
| `confirm-dialog.tsx` | `components/` | M01 |
| Date picker | `ui/` | M03 |
| File upload / rich text | `ui/` | M08 |
| Charts (Recharts) | `ui/` | M10 / Phase 5 |
| Portal + print shells | `layouts/` | M11 / PDF phase |
