Setup Guide
One-time setup for using MERIDIAN // NEXT components. Add these to your project, then copy any component from the theme.
The cn() utility combines clsx and tailwind-merge for conditional class names. Install both packages.
npm install clsx tailwind-mergeCreate lib/utils.ts with the cn() helper. Every component imports this for class name merging.
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs))
}Add the MERIDIAN // NEXT design tokens to your globals.css. These define colors, fonts, and animation tokens used by every component in the theme.
@theme {
--color-mdn-bg: #0b0e14;
--color-mdn-surface: #111520;
--color-mdn-surface-2: #161c2d;
--color-mdn-surface-3: #1c2238;
--color-mdn-border: #1e2640;
--color-mdn-border-2: #252d4a;
--color-mdn-text-dim: #3d4a6a;
--color-mdn-text-muted: #5a6585;
--color-mdn-text-body: #8892a8;
--color-mdn-text-label: #b0bbce;
--color-mdn-text-primary: #c8d0e0;
--color-mdn-text-bright: #e8edf5;
--color-mdn-ice: #4fc3f7;
--color-mdn-ice-dim: rgba(79, 195, 247, 0.12);
--color-mdn-ice-glow: rgba(79, 195, 247, 0.25);
--color-mdn-green: #00e5a0;
--color-mdn-green-dim: rgba(0, 229, 160, 0.1);
--color-mdn-amber: #fbbf24;
--color-mdn-amber-dim: rgba(251, 191, 36, 0.1);
--color-mdn-red: #f43f5e;
--color-mdn-red-dim: rgba(244, 63, 94, 0.1);
--color-mdn-violet: #a78bfa;
--color-mdn-violet-dim: rgba(167, 139, 250, 0.1);
--font-mono: var(--font-ibm-plex-mono);
--font-body: var(--font-dm-sans);
--sidebar-w: 220px;
--topbar-h: 48px;
--radius-sm: 3px;
--radius-md: 4px;
--radius-lg: 6px;
}Each component may need its own CSS classes in your globals.css. Copy the styles for the components you use.
.mdn-btn {
font-family: var(--font-ibm-plex-mono), monospace;
font-size: 11px;
padding: 5px 12px;
border-radius: 3px;
cursor: pointer;
transition: all 0.15s;
border: 1px solid var(--color-mdn-ice);
color: var(--color-mdn-ice);
background: transparent;
display: inline-flex;
align-items: center;
gap: 6px;
}
.mdn-btn:hover {
background: var(--color-mdn-ice-dim);
}
.mdn-btn-solid {
background: var(--color-mdn-ice);
color: var(--color-mdn-bg);
border-color: var(--color-mdn-ice);
}
.mdn-btn-solid:hover {
background: #7dd6fb;
border-color: #7dd6fb;
}
.mdn-btn-sm {
font-size: 10px;
padding: 3px 8px;
}
.mdn-btn-ghost {
border-color: var(--color-mdn-border-2);
color: var(--color-mdn-text-muted);
background: transparent;
}
.mdn-btn-ghost:hover {
border-color: var(--color-mdn-border-2);
color: var(--color-mdn-text-label);
}
.mdn-btn-lg {
font-size: 12px;
padding: 8px 18px;
}.mdn-nav-badge.green {
background: var(--color-mdn-green-dim);
color: var(--color-mdn-green);
}.mdn-text-body { font-size: 13px; color: var(--color-mdn-text-body); }
.mdn-text-caption { font-size: 11px; color: var(--color-mdn-text-muted); }
.mdn-text-label { font-size: 11px; color: var(--color-mdn-text-label); letter-spacing: 0.05em; }
.mdn-text-code { font-family: var(--font-ibm-plex-mono), monospace; font-size: 11.5px; color: var(--color-mdn-ice); background: var(--color-mdn-surface-2); padding: 1px 4px; border-radius: 2px; }
.mdn-text-mono { font-family: var(--font-ibm-plex-mono), monospace; font-size: 11.5px; color: var(--color-mdn-text-primary); }.mdn-card {
background: var(--color-mdn-surface);
border: 1px solid var(--color-mdn-border);
border-radius: 4px;
}
.mdn-card-header {
padding: 14px 16px;
border-bottom: 1px solid var(--color-mdn-border);
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.mdn-card-title {
font-size: 12px;
font-weight: 500;
color: var(--color-mdn-text-label);
}
.mdn-card-body {
padding: 16px;
}.mdn-health-dot.warn {
background: var(--color-mdn-amber);
box-shadow: 0 0 0 2px var(--color-mdn-amber-dim);
}
.mdn-kpi-badge.warn {
background: var(--color-mdn-amber-dim);
color: var(--color-mdn-amber);
}
.mdn-status-pill.ok {
background: var(--color-mdn-green-dim);
color: var(--color-mdn-green);
}
.mdn-status-pill.warn {
background: var(--color-mdn-amber-dim);
color: var(--color-mdn-amber);
}
.mdn-status-pill.err {
background: var(--color-mdn-red-dim);
color: var(--color-mdn-red);
}
.mdn-status-pill.idle {
background: var(--color-mdn-surface-3);
color: var(--color-mdn-text-muted);
}
.mdn-status-pill.info {
background: var(--color-mdn-ice-dim);
color: var(--color-mdn-ice);
}
.mdn-activity-icon.ok {
background: var(--color-mdn-green-dim);
color: var(--color-mdn-green);
}
.mdn-activity-icon.warn {
background: var(--color-mdn-amber-dim);
color: var(--color-mdn-amber);
}
.mdn-activity-icon.err {
background: var(--color-mdn-red-dim);
color: var(--color-mdn-red);
}
.mdn-activity-icon.info {
background: var(--color-mdn-ice-dim);
color: var(--color-mdn-ice);
}
.mdn-service-status.ok {
background: var(--color-mdn-green);
box-shadow: 0 0 0 2px var(--color-mdn-green-dim);
}
.mdn-service-status.warn {
background: var(--color-mdn-amber);
}
.mdn-service-uptime.ok {
color: var(--color-mdn-green);
}
.mdn-service-uptime.warn {
color: var(--color-mdn-amber);
}
.mdn-log-line.warn {
border-left-color: var(--color-mdn-amber);
}
.mdn-log-level.warn {
color: var(--color-mdn-amber);
background: var(--color-mdn-amber-dim);
}
.mdn-log-level.info {
color: var(--color-mdn-green);
background: var(--color-mdn-green-dim);
}Button
Dashboard button with primary (solid), secondary (outline), and ghost variants in three sizes. Renders as a Next.js Link when an href is provided.
Badge
Status badge with six color variants: ice, green, amber, red, violet, and surface. Designed for dashboard labels, status indicators, and category tags.
Text
Polymorphic text primitive with body, caption, label, code, and mono variants. Renders as any block or inline HTML tag via the `as` prop.
Card
Composable card with Card, CardHeader, and CardBody sub-components. Uses `mdn-card` CSS classes for consistent dashboard panel styling.
StatusPill
Compact status indicator with five semantic states: ok, warn, err, idle, and info. Each state maps to a default label (Healthy, Degraded, Down, Idle, Info) that can be overridden via the label prop.