Shared Design System
Architecture, components, and theme tokens of the @veriworkly/ui package.
Shared Design System (@veriworkly/ui)
@veriworkly/ui is the centralised UI library for the monorepo. It is consumed by all five Next.js
applications:
- Marketing site (
apps/site, port 3000) - Studio (
apps/studio, port 3001) - Documentation (
apps/docs-platform, port 3002) - Blog (
apps/blog-platform, port 3003) - Portfolio builder (
apps/portfolio, port 3004)
The package is consumed directly from source — its package.json points main and types at
./src/index.ts with no build step — so edits hot-reload in every consuming application
immediately.
No tailwind.config.ts
Tailwind CSS 4 defines its theme in CSS via the @theme at-rule, so this package has no
JavaScript Tailwind config. All tokens live in src/styles/themes.css.
Theme and tokens
packages/ui/src/styles/themes.css defines two parallel layers of CSS custom properties:
- Application tokens (
--background,--foreground,--card, …) declared on:rootfor light mode and.darkfor dark mode. These are what application CSS and hand-written styles use. - Fumadocs tokens (
--color-fd-*) declared inside@theme, mapping the same palette onto the variable names Fumadocs' components expect, so the docs and blog inherit the brand palette without a separate theme.
Core application tokens
| CSS variable | Purpose | Light | Dark |
|---|---|---|---|
--background | Page canvas | #f5f4ef (cream) | #0d1117 (deep navy-black) |
--foreground | Primary text and icons | #171717 (charcoal) | #f3f4f6 (light grey) |
--card | Container and panel surfaces | #ffffff | #121924 (slate navy) |
--muted | Secondary text | #5f5c54 | #94a3b8 |
--border | Dividers and outlines | rgba(23,23,23,0.12) | rgba(148,163,184,0.25) |
--accent | Interactive and action states | #2563eb (royal blue) | #60a5fa (light blue) |
--accent-foreground | Text on accent surfaces | #f8fbff | #0f172a |
--destructive | Errors and destructive actions | #dc2626 | #ef4444 |
--destructive-foreground | Text on destructive surfaces | #ffffff | #ffffff |
Corresponding Fumadocs tokens
| Fumadocs token | Maps to |
|---|---|
--color-fd-background | --background |
--color-fd-foreground | --foreground |
--color-fd-card | --card |
--color-fd-border | --border |
--color-fd-primary | --accent |
--color-fd-muted | A translucent surface tint |
--color-fd-muted-foreground | --muted |
--color-fd-ring | Focus ring — matches --accent |
Using tokens in custom CSS
.custom-panel {
background-color: var(--card);
border: 1px solid var(--border);
color: var(--foreground);
transition: border-color 0.2s ease;
}
.custom-panel:hover {
border-color: var(--accent);
}Global styles
src/styles/globals.css sets the shared baseline: a default border-color on every element, smooth
scroll behaviour, the subtle dual radial-gradient page background, an accent-tinted ::selection,
and utility classes such as .surface-grid (a token-derived grid overlay) and .hide-scrollbar.
Component library
UI primitives (src/components/ui)
Twelve primitives, all built with Tailwind utilities and no third-party headless UI dependency:
| Component | Purpose |
|---|---|
| Accordion | Collapsible panels for FAQs and dense detail. |
| Badge | Pill badges for tags and status indicators. |
| Button | Action triggers with loading states, icons, and style variants. |
| Card | Bordered content containers. |
| Checkbox | Accessible check selectors. |
| Input | Text fields with validation and error messaging. |
| Menu | Contextual dropdown and action menus. |
| Modal | Overlay dialogs with transitions. |
| Select | Form dropdowns. |
| Switch | Toggle controls. |
| TextArea | Multi-line text fields. |
| Tooltip | Hover descriptions. |
Layout components (src/components/layout)
| Component | Purpose |
|---|---|
| Container | Page margins and max-width constraints. |
| AppShell | Left-rail navigation shell for authenticated workspaces. |
| MarketingNavbar | The marketing header. Composed from MarketingNavLogo, MarketingDesktopNav, MarketingMobileNav, and MarketingNavActions, all exported from layout/navbar. |
| MarketingFooter | Multi-column link index with copyright and social links. |
| ThemeToggle | Light / dark theme switcher, toggling the .dark class on the document root. |
| SocialIcons | Brand vector icons for the project's social links. |
Everything is re-exported from src/index.ts, so consumers import from the package root:
import { Button, Card, Badge, MarketingFooter } from "@veriworkly/ui";Typography
Geist and Geist Mono are configured through next/font/google in src/lib/fonts.ts and
exported as a single globalFontVariables string.
import { globalFontVariables } from "@veriworkly/ui";
import "@veriworkly/ui/styles/globals.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={globalFontVariables}>
<body className="bg-background text-foreground antialiased">{children}</body>
</html>
);
}This exposes --font-geist-sans and --font-geist-mono as CSS variables for the whole document.
Adding a component
Implement it
Create the file under packages/ui/src/components/ui/ or packages/ui/src/components/layout/.
Style with Tailwind utilities and the shared cn helper — never hardcode hex colours; use theme
tokens so both themes work automatically.
// packages/ui/src/components/ui/CardHeader.tsx
import React from "react";
import { cn } from "../../utils";
export interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}
export const CardHeader = ({ className, ...props }: CardHeaderProps) => (
<div className={cn("border-border mb-4 border-b pb-4", className)} {...props} />
);Verify in both themes
Because the package is consumed from source, every running application picks the change up via hot module replacement. Check the component against both light and dark themes, and against the contrast and keyboard-focus expectations in the Coding Standards.
Public style guide
The marketing site publishes a live showcase of this design system — colours, typography, components, brand assets, motion, and layout rules — at veriworkly.com/style-guide.