Components Guide
The template ships 70+ components. They fall into a few groups under
src/components/. The ui/ folder holds the shadcn/ui primitives; everything
else is built on top of them.
Folder map
src/components/
├── ui/ shadcn/ui primitives (button, card, dialog, table, …)
├── layout/ AppShell, Sidebar, Topbar, command palette, logo, user menu
├── common/ StatCard, PageHeader, EmptyState, StatusBadge, ActivityFeed
├── charts/ Line / Area / Bar / Donut / Mixed wrappers + primitives
├── tables/ DataTable (TanStack Table)
├── forms/ PasswordInput, social buttons
├── ai/ ModelSelector, TokenCounter, UsageMeter, AgentStatusIndicator…
└── <page area>/ analytics, prompts, playground, users, billing, settings, …
Common components
StatCard
src/components/common/stat-card.tsx — an animated metric card with optional
trend, icon and sparkline.
import { Activity } from "lucide-react";
import { StatCard } from "@/components/common/stat-card";
<StatCard
label="Total API Calls"
value={2_418_902}
change={14.2} // % vs last period
icon={Activity}
sparkline={[12, 18, 14, 22, 30]}
// invertTrend // set when "down" is good (e.g. cost)
/>;
PageHeader
src/components/common/page-header.tsx — title, breadcrumbs and an actions
slot. Used at the top of every page.
<PageHeader
title="Users"
description="Manage everyone in your workspace."
breadcrumbs={[{ label: "Dashboard", href: "/dashboard" }, { label: "Users" }]}
actions={<Button>Invite user</Button>}
/>
StatusBadge
src/components/common/status-badge.tsx — maps a status string (active, paused,
paid, pro, admin, …) to a consistent color tone automatically.
<StatusBadge status="active" /> {/* green dot + label */}
<StatusBadge status="pro" dot={false} />
EmptyState / ActivityFeed
EmptyState (icon + message + CTA) for empty lists; ActivityFeed renders a
vertical timeline of events.
Charts
All wrappers live in src/components/charts/ and use Recharts with shared
theming. They accept a data array and a series config.
import { LineChart } from "@/components/charts/line-chart";
<LineChart
data={apiUsageData} // [{ date, calls }, …]
series={[{ key: "calls", label: "API calls" }]}
valueFormatter={(v) => v.toLocaleString()}
/>;
Available: LineChart, AreaChart (stacked), StackedBarChart,
CategoryBarChart, DonutChart (+ ChartLegend), MixedChart (bars + line).
Colors come from the --chart-1…6 tokens; see
Customization.
Charts render after mount (via the
useMountedhook) to avoid Recharts' 0×0-size warning during server rendering — keep that pattern if you add new chart wrappers.
DataTable
src/components/tables/data-table.tsx — a TanStack Table v8 wrapper with
sorting, pagination, column visibility, optional row selection and a bulk-action
bar.
import { DataTable } from "@/components/tables/data-table";
<DataTable
columns={columns} // TanStack ColumnDef[]
data={rows}
pageSize={10}
enableRowSelection
onRowClick={(row) => router.push(`/users/${row.id}`)}
renderBulkActions={(selected, clear) => (
<Button onClick={() => { /* … */ clear(); }}>Delete {selected.length}</Button>
)}
toolbar={<Input placeholder="Search…" />}
/>;
See src/components/users/users-view.tsx and
src/components/prompts/prompts-view.tsx for full column examples.
AI components
In src/components/ai/:
- ModelSelector — dropdown of models with provider dot + per-1K cost.
- TokenCounter — horizontal usage bar with limit and percentage.
- UsageMeter — circular quota progress meter.
- AgentStatusIndicator — colored status pill (active/paused/training/error).
- CostMetric — currency value with trend.
- ModelCard — model spec card with set-primary action.
Forms
Forms use React Hook Form + Zod. Pattern (from the auth pages):
const schema = z.object({ email: z.string().email() });
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
src/components/forms/password-input.tsx provides a show/hide password field.
Adding a component
Put shared UI in the closest matching folder (common/, ai/, charts/…), or
a new <page-area>/ folder for page-specific views. Reuse the cn() helper
from @/lib/utils for class merging, and keep client-only logic behind
"use client".
Next: Mock Data →