// ============================================================================ // OpenClaw Control Center — Design Tokens (TypeScript) // ============================================================================ // Typed representation of the design system tokens for programmatic access. // These mirror the SCSS tokens in styles/_tokens.scss and the CSS custom // properties emitted by styles/_css-properties.scss. // // Usage: // import { CcTokens } from '@app/design/tokens'; // const primary = CcTokens.color.primary; // const surface = CcTokens.surface.dark; // ============================================================================ // --------------------------------------------------------------------------- // Color Palette // --------------------------------------------------------------------------- export const CcColors = { primary: { 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee', 500: '#38bdf8', 600: '#0ea5e9', 700: '#0284c7', 800: '#0369a1', 900: '#075985', }, secondary: { 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', }, accent: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', }, danger: { 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d', }, } as const; // --------------------------------------------------------------------------- // Semantic Colors (Tactical Dark) // --------------------------------------------------------------------------- export const CcSemanticColors = { surface: { darkest: '#0D0F12', dark: '#13161A', medium: '#1C2027', light: '#252B33', lighter: '#2D3748', }, onSurface: { primary: '#E2E8F0', variant: '#8A9BB0', muted: '#64748B', }, } as const; // --------------------------------------------------------------------------- // Status Colors // --------------------------------------------------------------------------- export const CcStatusColors = { active: { fg: '#38bdf8', bg: 'rgba(56, 189, 248, 0.12)', border: 'rgba(56, 189, 248, 0.40)' }, idle: { fg: '#2dd4bf', bg: 'rgba(45, 212, 191, 0.12)', border: 'rgba(45, 212, 191, 0.40)' }, thinking: { fg: '#a78bfa', bg: 'rgba(167, 139, 250, 0.12)', border: 'rgba(167, 139, 250, 0.40)' }, error: { fg: '#f87171', bg: 'rgba(248, 113, 113, 0.12)', border: 'rgba(248, 113, 113, 0.40)' }, offline: { fg: '#64748b', bg: 'rgba(100, 116, 139, 0.12)', border: 'rgba(100, 116, 139, 0.40)' }, } as const; // --------------------------------------------------------------------------- // Convenience exports for component usage (CUB-20) // --------------------------------------------------------------------------- /** Status colors — maps AgentStatus to hex values */ export const STATUS_COLORS: Record = { active: '#38BDF8', idle: '#2DD4BF', thinking: '#A78BFA', error: '#F87171', offline: '#64748B', }; /** Status background tints (12% opacity) */ export const STATUS_BG_COLORS: Record = { active: 'rgba(56, 189, 248, 0.12)', idle: 'rgba(45, 212, 191, 0.12)', thinking: 'rgba(167, 139, 250, 0.12)', error: 'rgba(248, 113, 113, 0.12)', offline: 'rgba(100, 116, 139, 0.12)', }; /** Surface overrides (CUB-20 convenience) */ export const SURFACE = { background: '#0D0F12', surface: '#13161A', container: '#1C2027', containerHigh: '#252B33', onSurface: '#E2E8F0', onSurfaceVariant: '#8A9BB0', outline: '#2D3748', } as const; /** Tactical Dark Mode color palette (CUB-20 convenience) */ export const COLORS = { surface: '#0F172A', surfaceLight: '#1E293B', primary: '#38BDF8', secondary: '#2DD4BF', accent: '#A78BFA', danger: '#F87171', textPrimary: '#FFFFFF', textSecondary: '#94A3B8', border: '#334155', } as const; /** Layout constants (CUB-20 convenience) */ export const LAYOUT = { navRailCollapsedWidth: 72, navRailExpandedWidth: 256, headerHeight: 64, bottomNavHeight: 80, cardBorderRadius: 16, cardMinWidth: 320, cardGap: 16, cardPadding: 20, sectionPadding: 24, spacingUnit: 8, } as const; /** Breakpoints (px) (CUB-20 convenience) */ export const BREAKPOINTS = { mobile: 599, tablet: 1023, desktop: 1024, } as const; /** Channel icon mapping (CUB-20) */ export const CHANNEL_ICONS: Record = { telegram: 'telegram', slack: 'chat', discord: 'forum', whatsapp: 'chat', webchat: 'language', email: 'email', mqtt: 'sensors', }; /** Human-readable status labels (CUB-20) */ export const STATUS_LABELS: Record = { active: 'Active', idle: 'Idle', thinking: 'Thinking…', error: 'Error', offline: 'Offline', }; // --------------------------------------------------------------------------- // Typography // --------------------------------------------------------------------------- export const CcTypography = { fontFamily: { brand: "'Inter, Roboto, sans-serif'", body: "'Inter, Roboto, sans-serif'", mono: "'Roboto Mono, Cascadia Code, Fira Code, monospace'", }, size: { displayLarge: '57px', displayMedium: '45px', displaySmall: '36px', headlineLarge: '32px', headlineMedium: '28px', headlineSmall: '24px', titleLarge: '22px', titleMedium: '16px', titleSmall: '14px', bodyLarge: '16px', bodyMedium: '14px', bodySmall: '12px', labelLarge: '14px', labelMedium: '12px', labelSmall: '11px', }, weight: { regular: 400, medium: 500, bold: 600, heavy: 700, }, lineHeight: { tight: '1.2', normal: '1.5', relaxed: '1.6', }, letterSpacing: { tight: '-0.01em', normal: '0em', wide: '0.02em', mono: '0.05em', }, } as const; // --------------------------------------------------------------------------- // Spacing (4px grid) // --------------------------------------------------------------------------- export const CcSpacing = { 0: '0px', 1: '4px', 2: '8px', 3: '12px', 4: '16px', 5: '20px', 6: '24px', 7: '28px', 8: '32px', 9: '36px', 10: '40px', 12: '48px', 14: '56px', 16: '64px', 20: '80px', } as const; // --------------------------------------------------------------------------- // Layout // --------------------------------------------------------------------------- export const CcLayout = { navRailCollapsedWidth: '72px', navRailExpandedWidth: '256px', headerHeight: '64px', bottomNavHeight: '80px', cardBorderRadius: '16px', cardMinWidth: '320px', badgeHeight: '24px', badgeBorderRadius: '12px', statusDotSize: '10px', } as const; // --------------------------------------------------------------------------- // Breakpoints (M3 canonical) // --------------------------------------------------------------------------- export const CcBreakpoints = { compact: 599, medium: 767, expanded: 1023, large: 1439, } as const; // --------------------------------------------------------------------------- // Border Radius // --------------------------------------------------------------------------- export const CcRadius = { none: '0px', xs: '4px', sm: '8px', md: '12px', lg: '16px', xl: '24px', full: '9999px', } as const; // --------------------------------------------------------------------------- // Shadows (M3 elevation) // --------------------------------------------------------------------------- export const CcShadows = { level0: 'none', level1: '0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 1px 2px -1px rgba(0, 0, 0, 0.3)', level2: '0 2px 6px 0 rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.3)', level3: '0 4px 12px 0 rgba(0, 0, 0, 0.3), 0 4px 8px -4px rgba(0, 0, 0, 0.3)', level4: '0 8px 24px 0 rgba(0, 0, 0, 0.3), 0 8px 16px -8px rgba(0, 0, 0, 0.3)', } as const; // --------------------------------------------------------------------------- // Motion // --------------------------------------------------------------------------- export const CcMotion = { duration: { instant: 0, fast: 100, short: 150, medium: 200, standard: 300, long: 500, }, easing: { standard: 'cubic-bezier(0.4, 0, 0.2, 1)', decelerate: 'cubic-bezier(0, 0, 0.2, 1)', accelerate: 'cubic-bezier(0.4, 0, 1, 1)', sharp: 'cubic-bezier(0.4, 0, 0.6, 1)', }, } as const; // --------------------------------------------------------------------------- // Accessibility // --------------------------------------------------------------------------- export const CcA11y = { focusRing: { width: '2px', offset: '2px', color: '#38bdf8', style: 'solid', }, minTouchTarget: 48, minBodyFont: 16, } as const; // --------------------------------------------------------------------------- // Aggregate token object for convenient access // --------------------------------------------------------------------------- export const CcTokens = { color: CcColors, semantic: CcSemanticColors, status: CcStatusColors, typography: CcTypography, spacing: CcSpacing, layout: CcLayout, breakpoints: CcBreakpoints, radius: CcRadius, shadows: CcShadows, motion: CcMotion, a11y: CcA11y, } as const; // --------------------------------------------------------------------------- // CSS Custom Property Names // --------------------------------------------------------------------------- export const CcCssProps = { // Color colorPrimary: '--cc-color-primary', colorSecondary: '--cc-color-secondary', colorAccent: '--cc-color-accent', colorDanger: '--cc-color-danger', // Surface surfaceDarkest: '--cc-surface-darkest', surfaceDark: '--cc-surface-dark', surfaceMedium: '--cc-surface-medium', surfaceLight: '--cc-surface-light', surfaceLighter: '--cc-surface-lighter', // On-surface onSurface: '--cc-on-surface', onSurfaceVariant: '--cc-on-surface-variant', onSurfaceMuted: '--cc-on-surface-muted', // Status statusActive: '--cc-status-active', statusIdle: '--cc-status-idle', statusThinking: '--cc-status-thinking', statusError: '--cc-status-error', statusOffline: '--cc-status-offline', statusActiveBg: '--cc-status-active-bg', statusIdleBg: '--cc-status-idle-bg', statusThinkingBg: '--cc-status-thinking-bg', statusErrorBg: '--cc-status-error-bg', statusOfflineBg: '--cc-status-offline-bg', statusActiveBorder: '--cc-status-active-border', statusIdleBorder: '--cc-status-idle-border', statusThinkingBorder: '--cc-status-thinking-border', statusErrorBorder: '--cc-status-error-border', statusOfflineBorder: '--cc-status-offline-border', // Typography fontBrand: '--cc-font-brand', fontBody: '--cc-font-body', fontMono: '--cc-font-mono', // Spacing spacing2: '--cc-spacing-2', spacing4: '--cc-spacing-4', spacing6: '--cc-spacing-6', spacing8: '--cc-spacing-8', spacing12: '--cc-spacing-12', spacing16: '--cc-spacing-16', // Layout navRailCollapsed: '--cc-nav-rail-collapsed', navRailExpanded: '--cc-nav-rail-expanded', headerHeight: '--cc-header-height', bottomNavHeight: '--cc-bottom-nav-height', cardRadius: '--cc-card-radius', cardMinWidth: '--cc-card-min-width', // Radius radiusNone: '--cc-radius-none', radiusXs: '--cc-radius-xs', radiusSm: '--cc-radius-sm', radiusMd: '--cc-radius-md', radiusLg: '--cc-radius-lg', radiusXl: '--cc-radius-xl', radiusFull: '--cc-radius-full', // Shadows shadow0: '--cc-shadow-0', shadow1: '--cc-shadow-1', shadow2: '--cc-shadow-2', shadow3: '--cc-shadow-3', shadow4: '--cc-shadow-4', // Motion durationFast: '--cc-duration-fast', durationShort: '--cc-duration-short', durationMedium: '--cc-duration-medium', durationStandard: '--cc-duration-standard', durationLong: '--cc-duration-long', easingStandard: '--cc-easing-standard', easingDecelerate: '--cc-easing-decelerate', easingAccelerate: '--cc-easing-accelerate', // Accessibility focusWidth: '--cc-focus-width', focusOffset: '--cc-focus-offset', focusColor: '--cc-focus-color', touchMin: '--cc-touch-min', } as const; // --------------------------------------------------------------------------- // Utility: Read a CSS custom property from the document // --------------------------------------------------------------------------- export function getCssToken(propertyName: string): string { return getComputedStyle(document.documentElement).getPropertyValue(propertyName).trim(); } // --------------------------------------------------------------------------- // Utility: Set a CSS custom property on the document root // --------------------------------------------------------------------------- export function setCssToken(propertyName: string, value: string): void { document.documentElement.style.setProperty(propertyName, value); } // --------------------------------------------------------------------------- // Utility: Get status color by agent status type // --------------------------------------------------------------------------- export function getStatusColor(status: string): { fg: string; bg: string; border: string } { const statusMap: Record = CcStatusColors; return statusMap[status] ?? CcStatusColors.offline; }