11 KiB
xBid Design System & Style Guide
A reference for the visual language, component patterns, and design principles used in xBid so that future apps can maintain the same look and feel.
1. Core Principles
- Dark-first: The app is permanently dark mode (
className="dark"on<html>). There is no light/dark toggle. - Minimal chrome: Surfaces are dark zinc grays with amber as the single accent colour. No gradients, no heavy decoration.
- Dense but readable: Data-heavy UI uses compact sizing (
text-xs,text-sm) with generous whitespace in page-level padding. - Amber accent, zinc foundation: Brand colour is amber (
#f59e0b/amber-500). All structural surfaces use the zinc palette.
2. Typography
Font Family
- Primary (body & UI): Inter — loaded via
next/font/google, subsetlatin. - Mono: Geist Mono (via
--font-geist-monoCSS variable from shadcn). - Applied globally:
font-sanson<html>.
Scale (Tailwind defaults, used in practice)
| Usage | Class(es) | Notes |
|---|---|---|
| Page title | text-3xl font-bold text-white |
e.g. Dashboard h1 |
| Section title | text-xl font-semibold text-white |
e.g. "Recent Jobs" h2 |
| Detail page title | text-xl font-bold text-white |
Truncated with truncate |
| Card title | text-base font-medium (via CardTitle) |
|
| Body / default | text-sm |
|
| Captions / meta | text-sm text-zinc-400 or text-zinc-500 |
|
| Table headers | text-xs uppercase tracking-wider text-zinc-500 |
|
| Table cells | text-xs or text-sm |
|
| Error messages | text-xs text-red-400 |
Form validation |
| Stat value | text-3xl font-bold text-white |
Dashboard stat cards |
3. Colour Palette
The app uses Tailwind CSS v4 with OKLCH CSS variables. All semantic tokens map to zinc grays in dark mode.
Brand / Accent
| Token | Tailwind class | Hex approx | Usage |
|---|---|---|---|
| Brand amber | amber-500 |
#f59e0b |
Logo bg, icon colour |
| Active nav highlight | amber-500/10 bg + amber-400 text |
— | Active nav item |
| Amber text | text-amber-400 |
#fbbf24 |
Active nav, stat icons |
| Amber text bold | text-amber-500 |
#f59e0b |
Logo "Bid" wordmark |
Surface / Layout
| Purpose | Tailwind class | Notes |
|---|---|---|
| Page background | bg-zinc-950 |
Top bar, outermost bg |
| Sidebar & card bg | bg-zinc-900 |
Primary surface |
| Hover / secondary surface | bg-zinc-800 |
Hover states, secondary card |
| Input fields | bg-zinc-900 border-zinc-700 |
Form inputs override |
| Borders | border-zinc-800 |
Dividers, card outlines |
| Input borders | border-zinc-700 |
Slightly lighter than surface borders |
Text
| Purpose | Tailwind class | Hex approx |
|---|---|---|
| Primary / headings | text-white |
#ffffff |
| Secondary / labels | text-zinc-400 |
#a1a1aa |
| Tertiary / placeholders | text-zinc-500 |
#71717a |
| Disabled / subtle | text-zinc-600 |
#52525b |
| Bright secondary | text-zinc-300 |
#d4d4d8 |
Semantic / Status Badges
These appear on Job and Invoice status badges. Pattern: coloured bg at low opacity + matching light text.
| Status | Classes |
|---|---|
| DRAFT | bg-zinc-700 text-zinc-300 |
| SENT | bg-blue-900/60 text-blue-300 |
| APPROVED / PAID | bg-green-900/60 text-green-300 |
| REJECTED / OVERDUE | bg-red-900/60 text-red-300 |
| ARCHIVED | bg-yellow-900/60 text-yellow-300 |
| VIEWED | bg-purple-900/60 text-purple-300 |
| PARTIALLY_PAID | bg-orange-900/60 text-orange-300 |
| CANCELLED | bg-zinc-800 text-zinc-500 |
Icon Colours (Dashboard Stats)
| Metric | Icon colour |
|---|---|
| Jobs / Total | text-amber-400 |
| Clients | text-blue-400 |
| Drafts | text-zinc-400 |
| Sent / Pending | text-yellow-400 |
| Approved | text-green-400 |
4. Spacing & Layout
App Shell
┌─────────────────────────────────────────┐
│ Sidebar (w-60 / w-16 collapsed) │ Main content (flex-1 overflow-y-auto)
│ bg-zinc-900 │ p-8 on page content
│ border-r border-zinc-800 │
└─────────────────────────────────────────┘
- Root:
flex h-full overflow-hidden - Sidebar:
flex flex-col bg-zinc-900 border-r border-zinc-800 transition-all duration-200 - Main:
flex-1 overflow-y-auto - Page padding:
p-8
Page Header pattern
<div className="mb-8">
<h1 className="text-3xl font-bold text-white">Page Title</h1>
<p className="text-zinc-400 mt-1">Subtitle / description.</p>
</div>
Detail Page Top Bar
<div className="border-b border-zinc-800 px-8 py-4 flex items-center gap-4 bg-zinc-950">
{/* back arrow + title + meta + actions */}
</div>
Grid layouts
| Pattern | Class |
|---|---|
| Stat cards | grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5 |
| Form fields | grid grid-cols-1 sm:grid-cols-2 gap-5 |
| Form field spacing | space-y-1.5 (label + input) |
| Form section spacing | space-y-6 |
5. Border Radius
Defined by CSS variable --radius: 0.625rem (10px).
| Token | Size | Tailwind class |
|---|---|---|
| sm | ~6px | rounded-sm / rounded |
| md | ~8px | rounded-md |
| lg | 10px (base) | rounded-lg |
| xl | ~14px | rounded-xl |
| 4xl (badges) | ~26px | rounded-4xl |
In practice: rounded-lg is the default for buttons, inputs, cards, nav items. Cards use rounded-xl. Badges use rounded-4xl (pill shape).
6. Component Patterns
Sidebar Navigation
- Container:
bg-zinc-900 border-r border-zinc-800 - Logo area:
px-4 py-5 border-b border-zinc-800- Icon:
w-8 h-8 rounded-lg bg-amber-500 flex items-center justify-centerwith black icon inside - Wordmark:
font-bold text-lg tracking-tight text-white— "x" white, "Bid" amber
- Icon:
- Nav item inactive:
text-zinc-400 hover:text-white hover:bg-zinc-800 px-3 py-2.5 rounded-lg text-sm font-medium - Nav item active:
bg-amber-500/10 text-amber-400 - Icon size:
h-4 w-4
Cards
<Card className="bg-zinc-900 border-zinc-800">
<CardHeader>
<CardTitle>…</CardTitle>
<CardDescription>…</CardDescription>
</CardHeader>
<CardContent>…</CardContent>
</Card>
- Card has
ring-1 ring-foreground/10androunded-xlby default via shadcn base-nova. - Override bg/border on dark surfaces:
bg-zinc-900 border-zinc-800.
Buttons
Variants from shadcn buttonVariants:
| Variant | Appearance |
|---|---|
default |
Dark bg (primary), light text — effectively bg-zinc-900 text-white in dark mode |
outline |
Border, transparent bg, hover muted |
secondary |
Muted bg |
ghost |
No border, hover muted |
destructive |
Red tinted bg, red text |
link |
Underline on hover |
Sizes: xs, sm, default (h-8), lg, icon, icon-xs, icon-sm, icon-lg.
Badges / Status Pills
<Badge className="bg-green-900/60 text-green-300">Approved</Badge>
- Custom status colours applied via
classNameoverride (see §3 Semantic/Status Badges). - Default shape: pill (
rounded-4xl),h-5,text-xs.
Form Fields
<div className="space-y-1.5">
<Label>Field Label *</Label>
<Input className="bg-zinc-900 border-zinc-700" placeholder="…" />
{error && <p className="text-red-400 text-xs">{error.message}</p>}
</div>
- Input base:
h-8 rounded-lg border border-input bg-transparent— always override withbg-zinc-900 border-zinc-700for dark surface visibility. - Textarea, Select follow the same pattern.
Tables
Line-item tables are custom <table> elements styled with:
text-xs w-full- Header row:
border-b border-zinc-800 text-zinc-500 uppercase tracking-wider - Cells:
px-4 py-2 text-left - Alternating/hover rows: use
hover:bg-zinc-800/50
shadcn <Table> component uses text-sm and standard border-b between rows.
Tabs
<Tabs defaultValue="…">
<TabsList>
<TabsTrigger value="…">Label</TabsTrigger>
</TabsList>
<TabsContent value="…">…</TabsContent>
</Tabs>
TabsListbg:bg-muted(zinc-800 in dark),rounded-lg.TabsTriggeractive: white text, slight bg lift.
Dialogs / Sheets
Standard shadcn Dialog / Sheet. Content uses bg-zinc-900 / card surface. Destructive actions use red confirm buttons.
Toasts / Notifications
- Library: Sonner (
<Toaster richColors position="top-right" />) toast.success(…)— greentoast.error(…)— red- Always called after async actions complete.
Dropdown Menus
Standard shadcn DropdownMenu. Destructive actions get text-destructive styling on the DropdownMenuItem.
Collapsible / Expandable Rows
Shot and asset cards use a chevron toggle (ChevronDown / ChevronRight) to expand inline line-item tables. Pattern:
<button onClick={() => setExpanded(!expanded)}>
{expanded ? <ChevronDown /> : <ChevronRight />}
</button>
7. Icons
Library: Lucide React (lucide-react)
Standard icon size: h-4 w-4 (16px). Larger decorative: h-5 w-5.
Common icons used:
| Purpose | Icon |
|---|---|
| Dashboard | LayoutDashboard |
| Clients | Users |
| Jobs / Quotes | Briefcase |
| Invoices | FileText |
| Rate Cards | CreditCard |
| Settings | Settings |
| Back | ArrowLeft |
| Download PDF | Download |
| Duplicate | Copy |
| Delete | Trash2 |
| Edit | Pencil |
| Add | Plus |
| More options | MoreHorizontal |
| Search | Search |
| Loading | Loader2 (with animate-spin) |
| Drag handle | GripVertical |
| App logo | Film |
| Send | Send |
| Approve / Mark paid | Check / CheckCircle |
8. Motion & Transitions
- Sidebar collapse:
transition-all duration-200 - Nav item colour:
transition-colors - Buttons:
transition-all - Drag-and-drop (DnD Kit): opacity
0.5while dragging. - Animation library:
tw-animate-css(imported in globals.css).
9. Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router, React Server Components) |
| Styling | Tailwind CSS v4 |
| Component system | shadcn/ui (base-nova style) + @base-ui/react primitives |
| Icon library | Lucide React |
| Font | Inter (Google Fonts via next/font) |
| Notifications | Sonner |
| Forms | React Hook Form + Zod |
| Drag & Drop | @dnd-kit/core + @dnd-kit/sortable |
| ORM | Prisma |
| DB | PostgreSQL |
| Color space | OKLCH (CSS variables) |
10. Quick Reference — Recurring Class Combinations
# Page wrapper
p-8
# Page title
text-3xl font-bold text-white
# Page subtitle
text-zinc-400 mt-1
# Section heading
text-xl font-semibold text-white mb-4
# Top bar (detail pages)
border-b border-zinc-800 px-8 py-4 flex items-center gap-4 bg-zinc-950
# Card (dark surface)
bg-zinc-900 border-zinc-800
# Card text hierarchy
text-white (value) | text-zinc-400 (label) | text-zinc-500 (meta)
# Form input (dark)
bg-zinc-900 border-zinc-700
# Form error
text-red-400 text-xs
# Table header
border-b border-zinc-800 text-zinc-500 uppercase tracking-wider text-xs
# Empty state text
text-center text-sm text-zinc-500
# Active nav
bg-amber-500/10 text-amber-400
# Inactive nav
text-zinc-400 hover:text-white hover:bg-zinc-800