Design System
Token reference, component primitives, and contribution rules for the DocuGardener UI. All values here are locked — do not hardcode colours, shadows, or radius values in components. Use only the tokens and primitives listed below.
Live preview: /ux-preview/design-system.html
Repo-level quick reference: docs/design-system.md
Colour Tokens
Defined in web/app/globals.css as CSS custom properties on :root and .dark. Never use raw hex values in components.
--backgroundPage / shell background--foregroundPrimary text--cardCard surface--borderCard/input borders--inputInput field borders--primaryBrand accent — buttons, links--mutedSubdued surface (headers, sidebars)--muted-foregroundSecondary / helper text--status-freshStatusChip: fresh (green / healthy)--status-witheredStatusChip: withered (amber / degraded)--status-brokenStatusChip: broken (red / critical)Spacing & Radius Tokens
| Token / class | Value | Use |
|---|---|---|
| .rounded-card | 0.75rem | All Card components |
| --radius | 0.5rem | Base shadcn radius |
| .app-container | max-w-7xl + px-6/8 | Page content wrapper |
| .shadow-card | subtle ring + drop-shadow | Default card shadow |
| .shadow-card-hover | elevated on hover | Interactive cards |
StatusChip
File: web/components/ui/status-chip.tsx. Use StatusChip for all inline status indicators in card headers. Never replicate the chip with raw Tailwind classes — always use this primitive.
Usage
import { StatusChip } from "@/components/ui/status-chip"
// In a CardHeader:
<StatusChip variant="primary" label="REPOSITORIES" className="mb-2" />DataTable
File: web/components/ui/data-table.tsx. Use for all data tables in dashboard pages. Provides dense padding, hover rows, and overflow scrolling. Never use raw <table> elements in dashboard code.
Usage
import {
DataTable, DataTableHeader, DataTableBody,
DataTableRow, DataTableHead, DataTableCell,
} from "@/components/ui/data-table"
<DataTable>
<DataTableHeader>
<DataTableRow>
<DataTableHead>Name</DataTableHead>
<DataTableHead>Status</DataTableHead>
</DataTableRow>
</DataTableHeader>
<DataTableBody>
{rows.map((row) => (
<DataTableRow key={row.id}>
<DataTableCell>{row.name}</DataTableCell>
<DataTableCell>{row.status}</DataTableCell>
</DataTableRow>
))}
</DataTableBody>
</DataTable>Override note
DataTable uses dense defaults (px-3 py-2 heads, px-3 py-2.5 cells). Pass an explicit className to override via tailwind-merge — e.g. className="px-6 py-3".
PageHeader
File: web/components/layout/PageHeader.tsx. Every dashboard page must open with PageHeader. Do not build custom page headers. Use the subtitle slot for the accent line above the title, and the children slot for stat cards.
Typography Classes
.type-section-headerSection HeaderCard titles, section labels.type-bodyBody text for descriptions and prose.Card descriptions, paragraphs.type-metadataMETADATALabels, overline text.animate-entranceEntrance animationApply to cards; stagger with animationDelayRules (Non-Negotiable)
- ·Use CSS custom property tokens — never raw hex or rgb values.
- ·Use .rounded-card for all Card components — never override with arbitrary values.
- ·Use StatusChip for all inline status labels in card headers.
- ·Use DataTable for all data tables in dashboard pages — no raw <table>.
- ·Use PageHeader for every dashboard page — no custom page headers.
- ·Do not add border-l-8 for status colour coding — use StatusChip instead.
- ·Shadows come from .shadow-card / .shadow-card-hover — no inline shadow utilities.