You are viewing archived documentation for v0.13. Go to latest →

Design System

Consistent CSS classes for buttons and badges across the web UI.

Buttons

All buttons use the .btn base class plus a variant and optional size modifier.

<button className="btn btn-primary">Save</button>
<button className="btn btn-secondary btn-sm">Cancel</button>
<button className="btn btn-danger btn-sm">Delete</button>
<button className="btn btn-primary btn-lg">Submit Form</button>

Base (.btn)

Shared properties applied to all buttons:

Property Value
Padding 0.4rem 0.75rem
Border radius var(--radius) (8px)
Font size 0.8rem
Font family var(--font)
Font weight 500
Display inline-flex (centered)
Transition opacity 0.15s, background 0.15s, border-color 0.15s

Variants

Class Use for Background Color Border
.btn-primary Main actions (save, submit, confirm) var(--accent) green #000 none
.btn-secondary Secondary actions (cancel, back, filter) var(--bg-card) var(--text-muted) var(--border)
.btn-danger Destructive actions (delete, clear) #7f1d1d #fca5a5 #ef4444
.btn-ghost Tertiary/minimal (menu items, dismiss) transparent var(--text-muted) var(--border)

Sizes

Class Padding Font size Width
.btn-sm 0.25rem 0.5rem 0.7rem auto
(default) 0.4rem 0.75rem 0.8rem auto
.btn-lg 0.625rem 1rem 0.85rem 100%

States

All handled by CSS — no JS needed:

State Effect
:hover Variant-specific (opacity, background change)
:disabled opacity: 0.45, cursor: not-allowed
:active transform: scale(0.98)

Usage Guidelines

  • Forms: Use btn btn-primary btn-lg for submit buttons (full width)
  • Tables: Use btn btn-secondary btn-sm for action buttons, btn btn-danger btn-sm for delete
  • Modals: Cancel = btn btn-secondary btn-sm, Confirm = btn btn-primary, Destructive = btn btn-danger btn-sm
  • Navigation: Use btn btn-secondary for prev/next, btn btn-ghost for menu items
  • Tabs: Active = btn btn-primary, Inactive = btn btn-secondary
  • For dynamic color buttons (e.g., vote buttons), use btn btn-lg and set background, color, border via style prop

Badges

All badges use the .badge base class plus a variant.

<span className="badge badge-online">active</span>
<span className="badge badge-muted">viewer</span>
<span className="badge badge-accent">Platform Admin</span>
<span className="badge badge-rare">RARE x3</span>

Base (.badge)

Property Value
Padding 0.1rem 0.4rem
Border radius 9999px (pill)
Font size 0.65rem
Font weight 500
Display inline-block

Variants

Class Use for Background Color Border
.badge-online Active, online, confirmed var(--accent-dim) var(--accent) green
.badge-offline Blocked, offline, error #7f1d1d var(--danger) red
.badge-degraded Warning, degraded #78350f var(--warning) yellow
.badge-muted Role labels, neutral info var(--bg) var(--text-muted) var(--border)
.badge-accent Platform admin, special var(--accent-dim) var(--accent) var(--accent)
.badge-rare Rare species #1e1b4b #8b5cf6 purple
.badge-danger Rejected, errors #7f1d1d #ef4444

Usage Guidelines

  • Status: badge-online (active), badge-offline (blocked), badge-degraded (warning)
  • Roles: badge-muted for tenant roles (viewer, member, admin), badge-accent for platform admin
  • Species: badge-rare for rare detections, badge-online for confirmed, badge-danger for rejected
  • Webhooks/workers: badge-online for active, badge-muted for disabled

Page Layout

Every page follows a consistent fixed-header / scrollable-content pattern:

┌──────────────────────────────────────────────┐
│ .page-header  — Title + subtitle + actions   │  fixed
├──────────────────────────────────────────────┤
│ .page-toolbar — Filters, sort, toggles, ⋮   │  fixed
├──────────────────────────────────────────────┤
│ .page-scroll  — Content (cards, tables...)   │  scrolls
├──────────────────────────────────────────────┤
│ .page-footer  — Pagination controls          │  fixed
└──────────────────────────────────────────────┘

Classes

Class Purpose Behavior
.page-header Page title, subtitle, primary actions Fixed at top, flex-shrink: 0
.page-toolbar Filters, sort, toggles, overflow menu Fixed below header. On mobile (< 768px), scrolls with content
.page-scroll Main content area flex: 1, overflow-y: auto
.page-footer Pagination (prev/next) Fixed at bottom, border-top separator

Principles

  • page-header is always present. Title + optional subtitle + optional action buttons (e.g. "Register satellite")
  • page-toolbar is optional — only rendered if the page has filters or controls. Uses flexbox wrap for responsive layout. Styled inputs/selects are automatic via child selectors.
  • page-scroll wraps all scrollable content. Only this area scrolls.
  • page-footer is optional — only for pages with pagination (Detections, Timeline, Audit Log)
  • Pages use React fragments (<>...</>) as their root element so the layout classes sit directly inside .main-content's flex column

Overflow Menu

For pages with many secondary actions (e.g. export formats), use the OverflowMenu component:

import { OverflowMenu } from "../components/OverflowMenu.js";

<OverflowMenu items={[
  { label: "Export CSV", href: "/api/export?format=csv", download: true },
  { label: "Export JSON", href: "/api/export?format=json", download: true },
]} />

Uses CSS classes .overflow-menu, .overflow-menu-trigger (⋮ button), .overflow-menu-dropdown (positioned dropdown).

Mobile Behavior

On screens < 768px:

  • .page-toolbar loses its fixed position and scrolls with content (via flex-shrink: unset)
  • .page-footer stays fixed — pagination is always accessible
  • Toolbar inputs expand to full width

Scrollbars

Global scrollbar styling — thin (6px), transparent track, faint thumb:

  • Chromium: ::-webkit-scrollbar rules
  • Firefox: scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.1) transparent

Color Palette

Variable Value Use
--bg #0f1117 Page background
--bg-card #1a1d27 Card/panel background
--bg-hover #252833 Hover states
--border #2a2d3a Borders, dividers
--text #e4e4e7 Primary text
--text-muted #9ca3af Secondary text, labels
--accent #22c55e Green primary accent
--accent-dim #166534 Green dim background
--warning #f59e0b Yellow warning
--danger #ef4444 Red danger
--info #3b82f6 Blue info
--radius 8px Border radius
--font -apple-system, Inter, system-ui, sans-serif Primary font
--mono JetBrains Mono, Fira Code, monospace Code font