Skip to main content

UI components & utilities

The app's design system is a set of shadcn/ui-style primitives built on Radix UI and Tailwind CSS. Application chrome (the header) is composed from these primitives.

Design system primitives

Exported from src/components/ui/index.ts:

GroupExports
ButtonButton, buttonVariants, ButtonProps
CardCard, CardHeader, CardFooter, CardTitle, CardDescription, CardContent
BadgeBadge, badgeVariants, BadgeProps
TableTable, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption
FormInput, Label, Checkbox
ScrollScrollArea, ScrollBar
AvatarAvatar, AvatarImage, AvatarFallback
LayoutSeparator, Tabs, TabsList, TabsTrigger, TabsContent
TooltipTooltip, TooltipTrigger, TooltipContent, TooltipProvider
DropdownDropdownMenu + Trigger, Content, Item, Label, Separator, Group, Portal, Sub, RadioGroup
DialogDialog + Trigger, Portal, Close, Overlay, Content, Header, Footer, Title, Description
FeedbackProgress, StatusDot (StatusDotProps)
Utilitycn

Import from the barrel:

import {Button, Card, CardHeader, cn} from '@/components/ui';

cn(...classes)

The className helper combines clsx with tailwind-merge, so conflicting Tailwind utilities resolve to the last one:

<div className={cn('px-2 py-1', isActive && 'bg-primary', className)} />

Header components

The application header lives in src/components/header/:

ComponentRole
AppHeaderTop bar: brand, mode controls, view-tabs slot, save indicator, profile menu.
ViewTabsThe horizontal strip of view tabs with add/rename/duplicate/delete.
UserMenuProfile dropdown: workspace switcher, settings, connection switcher, sign-out.

AppHeader is presentational — it takes the current user, mode, and saveStatus plus callbacks (onGoLive, onEdit, onSave, onNewWorkspace, onWorkspaceSettings, onSignOut) and a tabsSlot.

Shared utilities

src/lib/utils.ts holds the tiny cross-cutting helpers:

genId(prefix = 'id'): string; // unique id (crypto.randomUUID with fallback)
nowIso(): string; // current ISO-8601 timestamp

These back the workspace/view/widget factories that need fresh ids and timestamps.

note

cn is exported from @/components/ui (the design system), while genId and nowIso come from @/lib/utils. They live in different places on purpose: one is a styling concern, the others are domain helpers.

Styling