AgentSkillsCN

theme-system

在 OpenChamber 中创建或修改 UI 组件、样式或视觉元素时使用。所有 UI 颜色必须采用主题令牌——切勿使用硬编码值或 Tailwind 颜色类。

SKILL.md
--- frontmatter
name: theme-system
description: Use when creating or modifying UI components, styling, or visual elements in OpenChamber. All UI colors must use theme tokens - never hardcoded values or Tailwind color classes.
license: MIT
compatibility: opencode

Overview

OpenChamber uses a JSON-based theme system. Themes are defined in packages/ui/src/lib/theme/themes/. Users can also add custom themes via ~/.config/openchamber/themes/.

Core principle: UI colors must use theme tokens - never hardcoded hex colors or Tailwind color classes.

When to Use

  • Creating or modifying UI components
  • Working with colors, backgrounds, borders, or text

Quick Decision Tree

  1. Code display?syntax.*
  2. Feedback/status?status.*
  3. Primary CTA?primary.*
  4. Interactive/clickable?interactive.*
  5. Background layer?surface.*
  6. Text?surface.foreground or surface.mutedForeground

Critical Rules

  • surface.elevated = inputs, cards, panels
  • interactive.hover = ONLY on clickable elements
  • interactive.selection = active/selected states (not primary!)
  • Status colors = ONLY for actual feedback (errors, warnings, success)
  • Input footers = bg-transparent on elevated background

Never Use

  • Hardcoded hex colors (#FF0000)
  • Tailwind colors (bg-white, text-blue-500, bg-gray-*)
  • Deprecated: bg-secondary, bg-muted

Usage

Via Hook

tsx
import { useThemeSystem } from '@/contexts/useThemeSystem';
const { currentTheme } = useThemeSystem();

<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>

Via CSS Variables

tsx
<div className="bg-[var(--surface-elevated)] hover:bg-[var(--interactive-hover)]">

Color Tokens

Surface Colors

TokenUsage
surface.backgroundMain app background
surface.elevatedInputs, cards, panels, popovers
surface.mutedSecondary backgrounds, sidebars
surface.foregroundPrimary text
surface.mutedForegroundSecondary text, hints
surface.subtleSubtle dividers

Interactive Colors

TokenUsage
interactive.borderDefault borders
interactive.hoverHover on clickable elements only
interactive.selectionActive/selected items
interactive.selectionForegroundText on selection
interactive.focusRingFocus indicators

Status Colors

TokenUsage
status.errorErrors, validation failures
status.warningWarnings, cautions
status.successSuccess messages
status.infoInformational messages

Each has variants: *, *Foreground, *Background, *Border.

Primary Colors

TokenUsage
primary.basePrimary CTA buttons
primary.hoverHover on primary elements
primary.foregroundText on primary background

Primary vs Selection: Primary = "click me" (CTA), Selection = "currently active" (state).

Syntax Colors

For code display only. Never use for UI elements.

TokenUsage
syntax.base.backgroundCode block background
syntax.base.foregroundDefault code text
syntax.base.keywordKeywords
syntax.base.stringStrings
syntax.highlights.diffAddedAdded lines
syntax.highlights.diffRemovedRemoved lines

Examples

Input Area

tsx
const { currentTheme } = useThemeSystem();

<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
  <textarea className="bg-transparent" />
  <div className="bg-transparent">{/* Footer - transparent! */}</div>
</div>

Active Tab

tsx
<button className={isActive 
  ? 'bg-interactive-selection text-interactive-selection-foreground'
  : 'hover:bg-interactive-hover/50'
}>

Error Message

tsx
<div style={{ 
  color: currentTheme.colors.status.error,
  backgroundColor: currentTheme.colors.status.errorBackground 
}}>

Card

tsx
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
  <h3 style={{ color: currentTheme.colors.surface.foreground }}>Title</h3>
  <p style={{ color: currentTheme.colors.surface.mutedForeground }}>Description</p>
</div>

Wrong vs Right

Wrong

tsx
// Hardcoded colors
<div style={{ backgroundColor: '#F2F0E5' }}>
<button className="bg-blue-500">

// Primary for active tab
<Tab className="bg-primary">Active</Tab>

// Hover on static element
<div className="hover:bg-interactive-hover">Static card</div>

// Colored footer on input
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
  <textarea />
  <div style={{ backgroundColor: currentTheme.colors.surface.muted }}>Footer</div>
</div>

Right

tsx
// Theme tokens
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
<button style={{ backgroundColor: currentTheme.colors.primary.base }}>

// Selection for active tab
<Tab style={{ backgroundColor: currentTheme.colors.interactive.selection }}>Active</Tab>

// Hover only on clickable
<button className="hover:bg-[var(--interactive-hover)]">Click</button>

// Transparent footer
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
  <textarea className="bg-transparent" />
  <div className="bg-transparent">Footer</div>
</div>

References

Key Files

  • Theme types: packages/ui/src/types/theme.ts
  • Theme hook: packages/ui/src/contexts/useThemeSystem.ts
  • CSS generator: packages/ui/src/lib/theme/cssGenerator.ts
  • Built-in themes: packages/ui/src/lib/theme/themes/