agent-ecosystem/.claude/commands/ccc/design-system.md

12 KiB

name description
ccc:design-system Design system and visual language — theming, CSS variables, Tailwind config, component styling patterns, icon usage, animations, and z-index layers. Use when creating or modifying UI components, working with the dark/light theme, or debugging visual issues.

Design System & Visual Language

How the theming, color palette, component patterns, and styling conventions work.

Theme Architecture

Two themes (dark/light) driven by CSS custom properties in src/renderer/index.css. Toggled via useTheme() hook which adds/removes light class on document.documentElement.

Flash prevention: a script in index.html applies the cached theme before React loads.

Theme Hook

// src/renderer/hooks/useTheme.ts
const { theme, resolvedTheme, isDark, isLight } = useTheme();
// theme: 'dark' | 'light' | 'system'
// resolvedTheme: 'dark' | 'light' (after system resolution)

Styling Convention

Colors: Always via CSS variables (theme-aware). Use inline style or Tailwind classes mapped to variables. Layout/spacing: Tailwind utility classes. Icons: lucide-react with size-* Tailwind classes.

// Preferred: inline style for theme-aware colors, Tailwind for layout
<div className="flex items-center gap-2 rounded-md px-3 py-2"
     style={{ backgroundColor: 'var(--color-surface-raised)', color: 'var(--color-text)' }}>
  <Bot className="size-4 shrink-0" style={{ color: COLOR_TEXT_SECONDARY }} />
</div>

// Also valid: Tailwind classes that reference CSS variables
<div className="bg-surface text-text border-border">
<div className="bg-surface-raised text-text-secondary">

TypeScript Constants

src/renderer/constants/cssVariables.ts centralizes CSS variable strings:

import { COLOR_TEXT_MUTED, CARD_BG, CARD_BORDER_STYLE } from '@renderer/constants/cssVariables';

<span style={{ color: COLOR_TEXT_MUTED }}>Muted text</span>
<div style={{ backgroundColor: CARD_BG, border: CARD_BORDER_STYLE }}>Card</div>

Constants cover: text colors, surfaces, borders, code blocks, diff, cards, tags, prose.

CSS Variable Reference

All defined in src/renderer/index.css under :root (dark) and :root.light.

Surfaces

Variable Dark Light Usage
--color-surface #141416 #f9f9f7 Main background
--color-surface-raised #27272a #f0efed Elevated surfaces
--color-surface-overlay #27272a #e8e7e4 Overlays/modals
--color-surface-sidebar #0f0f11 #f1f0ee Sidebar background

Text

Variable Dark Light Usage
--color-text #fafafa #1c1b19 Primary text
--color-text-secondary #a1a1aa #4d4b46 Secondary text
--color-text-muted #71717a #6d6b65 Muted text

Borders

Variable Dark Light
--color-border rgba(255,255,255,0.05) #d5d3cf
--color-border-subtle rgba(255,255,255,0.05) #e3e1dd
--color-border-emphasis rgba(255,255,255,0.1) #a8a5a0

Chat Bubbles

User bubble (right-aligned):

Variable Dark Light
--chat-user-bg #27272a #eae9e6
--chat-user-text #a1a1aa #5a5955
--chat-user-border rgba(255,255,255,0.08) #d5d3cf
--chat-user-shadow 0 1px 0 0 rgba(255,255,255,0.03) 0 1px 2px 0 rgba(0,0,0,0.04)
--chat-user-tag-bg rgba(255,255,255,0.08) rgba(0,0,0,0.05)
--chat-user-tag-text #e4e4e7 #3a3935
--chat-user-tag-border rgba(255,255,255,0.12) rgba(0,0,0,0.08)

AI message:

Variable Dark Light
--chat-ai-border rgba(255,255,255,0.05) #d5d3cf
--chat-ai-icon #71717a #6d6b65

System bubble:

Variable Dark Light
--chat-system-bg rgba(39,39,42,0.5) #eae9e6
--chat-system-text #d4d4d8 #3a3935

Code & Syntax

Variable Dark Light
--code-bg #1c1c1e #f0efed
--code-header-bg #1c1c1e #eae9e6
--code-border rgba(255,255,255,0.1) #d5d3cf
--code-line-number #52525b #a8a5a0
--code-filename #60a5fa #2563eb
--inline-code-bg rgba(255,255,255,0.08) rgba(0,0,0,0.05)
--inline-code-text #e4e4e7 #3a3935

Syntax highlighting: --syntax-string, --syntax-comment, --syntax-number, --syntax-keyword, --syntax-type, --syntax-operator, --syntax-function. Dark uses vibrant colors; light uses GitHub-inspired palette.

Semantic Blocks

Thinking: Purple tones (--thinking-bg, --thinking-border, --thinking-text) Tool call: Amber tones (--tool-call-bg, --tool-call-border, --tool-call-text) Tool result success: Green tones (--tool-result-success-bg/border/text) Tool result error: Red tones (--tool-result-error-bg/border/text) Output: Gray tones (--output-bg, --output-border, --output-text) Interruption: Red (--interruption-bg/border/text) Warning: Amber (--warning-bg/border/text) Plan exit: Green (--plan-exit-bg/header-bg/border/text)

Diff Viewer

Variable Dark Light
--diff-added-bg rgba(34,197,94,0.15) rgba(34,197,94,0.1)
--diff-added-text #4ade80 #166534
--diff-removed-bg rgba(239,68,68,0.15) rgba(239,68,68,0.1)
--diff-removed-text #f87171 #991b1b

Cards (Subagents)

Variable Dark Light
--card-bg #121212 #f9f9f7
--card-border #27272a #d5d3cf
--card-header-bg #18181b #f0efed
--card-header-hover #1f1f23 #eae9e6
--card-icon-muted #52525b #a8a5a0
--card-separator #3f3f46 #d5d3cf

Badges

Status badges: --badge-error-bg/text, --badge-warning-bg/text, --badge-success-bg/text, --badge-info-bg/text, --badge-neutral-bg/text. Tags: --tag-bg, --tag-text, --tag-border.

Search Highlights

Variable Dark Light
--highlight-bg rgba(202,138,4,0.7) #facc15
--highlight-bg-inactive rgba(113,63,18,0.5) #fef08a
--highlight-ring #facc15 #ca8a04

Scrollbar

Custom scrollbar styling via --scrollbar-thumb, --scrollbar-thumb-hover, --scrollbar-thumb-active.

Tailwind Config

tailwind.config.js maps CSS variables to Tailwind classes:

colors: {
  surface: {
    DEFAULT: 'var(--color-surface)',
    raised: 'var(--color-surface-raised)',
    overlay: 'var(--color-surface-overlay)',
    sidebar: 'var(--color-surface-sidebar)',
    code: 'var(--code-bg)',
  },
  border: {
    DEFAULT: 'var(--color-border)',
    subtle: 'var(--color-border-subtle)',
    emphasis: 'var(--color-border-emphasis)',
  },
  text: {
    DEFAULT: 'var(--color-text)',
    secondary: 'var(--color-text-secondary)',
    muted: 'var(--color-text-muted)',
  },
  semantic: {
    success: '#22c55e',
    error: '#ef4444',
    warning: '#f59e0b',
    info: '#3b82f6',
  },
  // Backward-compatible alias
  'claude-dark': { bg: 'var(--color-surface)', surface: 'var(--color-surface-raised)', ... },
}

Plugin: @tailwindcss/typography for markdown prose.

Icon Library

lucide-react across 55+ components.

Sizes: size-3 (tiny), size-3.5 (small), size-4 (standard), size-5 (medium), size-10 (empty states)

Pattern: className for size, style for color:

<Bot className="size-4 shrink-0" style={{ color: COLOR_TEXT_SECONDARY }} />
<Loader2 className="size-3.5 shrink-0 animate-spin" style={{ color: '#3b82f6' }} />

Common icons: Bot (AI), User (user), ChevronRight/ChevronDown (expansion), Check/Copy (clipboard), Info (tooltips), Loader2 (loading), Clock (duration), Terminal (traces), CheckCircle2 (completed).

Team Colors

src/renderer/constants/teamColors.ts defines 8 color sets for teammate visualization:

import { getTeamColorSet, TeamColorSet } from '@renderer/constants/teamColors';

const colors = getTeamColorSet('blue');
// colors.border: '#3b82f6'  — border accent
// colors.badge: 'rgba(59, 130, 246, 0.15)'  — badge background
// colors.text: '#60a5fa'  — text color

Available colors: blue, green, red, yellow, purple, cyan, orange, pink.

Component Patterns

User Chat Bubble

Right-aligned with rounded corners, subtle shadow, copy overlay on hover:

<div className="flex justify-end">
  <div className="max-w-[85%]">
    <div className="rounded-2xl rounded-br-sm px-4 py-3"
         style={{
           backgroundColor: 'var(--chat-user-bg)',
           border: '1px solid var(--chat-user-border)',
           boxShadow: 'var(--chat-user-shadow)',
         }}>
      <ReactMarkdown>{text}</ReactMarkdown>
    </div>
  </div>
</div>

AI Group Header

Collapsible with model badge, summary, metrics:

<div onClick={toggle} className="flex cursor-pointer items-center gap-2">
  <Bot className="size-4" style={{ color: COLOR_TEXT_SECONDARY }} />
  <span>Claude</span>
  <span className={getModelColorClass(model.family)}>{model.name}</span>
  <span style={{ color: COLOR_TEXT_MUTED }}>{itemsSummary}</span>
  <ChevronDown className={`size-3.5 transition-transform ${isExpanded ? 'rotate-180' : ''}`} />
</div>

Subagent Card

Linear-style card with nested expansion:

<div style={{ backgroundColor: CARD_BG, border: CARD_BORDER_STYLE }}>
  <div className="flex cursor-pointer items-center gap-2 px-3 py-2"
       style={{ backgroundColor: isExpanded ? CARD_HEADER_BG : 'transparent' }}>
    <ChevronRight className={`size-3.5 transition-transform ${isExpanded ? 'rotate-90' : ''}`} />
    {/* colored dot + badge + description + metrics */}
  </div>
  {isExpanded && <div className="space-y-3 p-3">{/* content */}</div>}
</div>

Copy Button (Overlay)

Gradient-fade overlay that appears on group hover:

<div className="absolute right-0 top-0 opacity-0 group-hover:opacity-100 transition-opacity">
  <div style={{ background: `linear-gradient(to right, transparent, ${bgColor})` }} />
  <button><Copy className="size-3.5" /></button>
</div>

Popover via Portal

Token usage and context badges use portaled popovers to escape stacking context:

{showPopover && createPortal(
  <div style={{
    backgroundColor: 'var(--color-surface-raised)',
    border: '1px solid var(--color-border)',
    boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.3)',
    zIndex: 99999,
  }}>
    {/* content */}
  </div>,
  document.body
)}

Animations

CSS Keyframes (in index.css)

  • shimmer — skeleton loading shimmer effect
  • skeleton-fade-in — staggered fade-in for skeleton cards
  • splash-slide — splash screen loading bar

Tailwind Utilities

Class Usage
animate-spin Loading spinners (Loader2)
animate-ping Pulsing dots (ongoing state)
transition-transform Chevron rotation
transition-colors Hover color changes
transition-opacity Copy button fade-in
transition-all duration-300 Card highlight transitions
duration-[3000ms] Highlight ring fade-out

Z-Index Layers

Z-Index Usage
z-10 Copy button overlays, dropdown backdrops
z-20 Dropdown menus, search bar
z-30 Pane split drop zones
z-40 Pane view overlays
z-50 Context menus, command palette, settings selects
99999 Portaled popovers (token usage, context badge, metrics pill)

Light Theme Notes

The light theme uses warm neutrals (not pure white/gray):

  • Backgrounds: #f9f9f7, #f0efed, #eae9e6 (warm off-white)
  • Borders: #d5d3cf, #e3e1dd (warm gray)
  • Text: #1c1b19, #4d4b46, #6d6b65 (warm dark)
  • Syntax highlighting: GitHub-inspired palette

Body transition: background-color 0.2s ease, color 0.2s ease for smooth theme switching.