## Summary Complete sidebar redesign and comprehensive UI polish pass with performance optimizations, theme system refinements, and desktop integration improvements. ## Key Changes **Sidebar & Navigation Redesign** - Redesigned sessions sidebar layout with unified button primitives - Added activity sections with project grouping and improved session organization - Refined sidebar corners, spacing, and visual hierarchy - Removed NavRail component in favor of streamlined sidebar - Stabilized sessions bar toggle position in fullscreen mode **Performance Optimizations** - Reduced chat streaming CPU usage and storage churn - Optimized task tool polling and live timers with debouncing - Prevented chat state races and reduced background request load - Debounced draft writes and coalesced session reloads - Optimized message store updates and turn tracking **Theme & Visual System** - Added theme-aware window corners (desktop) and border radius tokens - Introduced glassmorphism effects on desktop sidebar - Added backdrop blur to UI elements **Chat Experience** - Added session-based permission auto-accept toggle in chat input - Polished permission shield UX with improved icon sizing and spacing - Fixed chat scroll-to-bottom behavior and timeline tracking - Enhanced tool output display with better path label detection - Removed duplicate draft context details in chat header - Added text selection menu to chat messages **Git Improvements** - Refreshed git history visual design with cleaner dividers - Added remote removal action in sync selector - Stabilized git polling to prevent excessive requests - Improved tool output rendering for git operations **Settings & Panels** - Fixed mobile scrolling on settings pages - Made outside-click settings close instantly - Reduced settings load churn and CPU spikes - Improved services dropdown layout and spacing - Softened panel resize handles **Desktop Integration** - Synced macOS window theme with app theme - Restored window dragging in sidebar header zones - Fixed system window corners on macOS - Improved header session metadata and action controls **Button & Component Standardization** - Unified button primitives across all components - Standardized destructive action patterns - Removed unused button variants (button-large, button-small) - Aligned context tab close hit areas --------- Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
7.0 KiB
7.0 KiB
name, description, license, compatibility
| name | description | license | compatibility |
|---|---|---|---|
| theme-system | 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. | MIT | 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
- Code display? →
syntax.* - Feedback/status? →
status.* - Primary CTA? →
primary.* - Interactive/clickable? →
interactive.* - Background layer? →
surface.* - Text? →
surface.foregroundorsurface.mutedForeground
Critical Rules
surface.elevated= inputs, cards, panelsinteractive.hover= ONLY on clickable elementsinteractive.selection= active/selected states (not primary!)- Status colors = ONLY for actual feedback (errors, warnings, success)
- Input footers =
bg-transparenton elevated background
Button Rules (MANDATORY)
Use only the shared Button component from packages/ui/src/components/ui/button.tsx.
- Do not create wrapper button components (for example
ButtonLarge,ButtonSmall). - Do not hardcode button height/padding classes when a
sizevariant exists. - Use semantic button variants consistently; avoid ad-hoc one-off button styling.
Allowed Button Variants
| Variant | Use for | Token direction |
|---|---|---|
default |
Primary action in a local section/dialog | primary.* |
outline |
Secondary visible action | surface.elevated + interactive.* |
secondary |
Soft secondary action | interactive.hover / interactive.active |
ghost |
Low-emphasis row/toolbar action | transparent + interactive.hover |
destructive |
Destructive actions (Delete, Revert all) |
status.error* |
link |
Rare inline text action only | text-link style |
Allowed Button Sizes
| Size | Use for |
|---|---|
xs |
Dense controls in rows/lists |
sm |
Default compact action buttons |
default |
Standard form/page actions |
lg |
Prominent large actions |
icon |
Icon-only square button |
Button Selection Quick Guide
- Main CTA in section/dialog ->
default - Side action next to CTA ->
outline - Quiet auxiliary action ->
ghost - Dangerous action ->
destructive - Tiny row action -> keep same variant, set
size="xs"
Never Use
- Hardcoded hex colors (
#FF0000) - Tailwind colors (
bg-white,text-blue-500,bg-gray-*) - Deprecated:
bg-secondary,bg-muted
Usage
Via Hook
import { useThemeSystem } from '@/contexts/useThemeSystem';
const { currentTheme } = useThemeSystem();
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
Via CSS Variables
<div className="bg-[var(--surface-elevated)] hover:bg-[var(--interactive-hover)]">
Color Tokens
Surface Colors
| Token | Usage |
|---|---|
surface.background |
Main app background |
surface.elevated |
Inputs, cards, panels, popovers |
surface.muted |
Secondary backgrounds, sidebars |
surface.foreground |
Primary text |
surface.mutedForeground |
Secondary text, hints |
surface.subtle |
Subtle dividers |
Interactive Colors
| Token | Usage |
|---|---|
interactive.border |
Default borders |
interactive.hover |
Hover on clickable elements only |
interactive.selection |
Active/selected items |
interactive.selectionForeground |
Text on selection |
interactive.focusRing |
Focus indicators |
Status Colors
| Token | Usage |
|---|---|
status.error |
Errors, validation failures |
status.warning |
Warnings, cautions |
status.success |
Success messages |
status.info |
Informational messages |
Each has variants: *, *Foreground, *Background, *Border.
Primary Colors
| Token | Usage |
|---|---|
primary.base |
Primary CTA buttons |
primary.hover |
Hover on primary elements |
primary.foreground |
Text 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.
| Token | Usage |
|---|---|
syntax.base.background |
Code block background |
syntax.base.foreground |
Default code text |
syntax.base.keyword |
Keywords |
syntax.base.string |
Strings |
syntax.highlights.diffAdded |
Added lines |
syntax.highlights.diffRemoved |
Removed lines |
Examples
Input Area
const { currentTheme } = useThemeSystem();
<div style={{ backgroundColor: currentTheme.colors.surface.elevated }}>
<textarea className="bg-transparent" />
<div className="bg-transparent">{/* Footer - transparent! */}</div>
</div>
Active Tab
<button className={isActive
? 'bg-interactive-selection text-interactive-selection-foreground'
: 'hover:bg-interactive-hover/50'
}>
Error Message
<div style={{
color: currentTheme.colors.status.error,
backgroundColor: currentTheme.colors.status.errorBackground
}}>
Card
<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
// 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
// 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
- Adding Themes - Built-in and custom themes
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/