import type { CSSProperties, ReactNode } from 'react'; import { AbsoluteFill, Easing, interpolate, useCurrentFrame } from 'remotion'; import packageJson from '../package.json'; import { filterFuzzySearchRecords, getMatchSegments, type FuzzySearchRecord } from '../src/utils/fuzzy'; type Screen = 'launch' | 'main' | 'lines' | 'items' | 'picker' | 'powerline' | 'themes' | 'final'; type PickerLevel = 'category' | 'widget'; type UsageDisplayMode = 'time' | 'progress' | 'progress-short' | 'slider' | 'slider-only'; type ThemeName = 'custom' | 'nord' | 'nord-aurora' | 'monokai' | 'solarized' | 'minimal' | 'dracula' | 'catppuccin' | 'gruvbox' | 'onedark' | 'tokyonight'; const PACKAGE_VERSION = packageJson.version; interface Swatch { foreground: string; background: string; } interface Theme { name: string; description: string; swatches: [ Swatch, Swatch, Swatch, Swatch, Swatch, Swatch ]; } interface Phase { title: string; subtitle: string; screen: Screen; powerline: boolean; selectedTheme: ThemeName; selectedMainIndex: number; selectedLineIndex: number; selectedItemIndex: number; lineOneConfigured: boolean; lineOneWidgetCount: number; lineNumber: 1 | 2; lineTwoConfigured: boolean; lineTwoWidgetCount: number; sessionUsageMode: UsageDisplayMode; weeklyUsageMode: UsageDisplayMode; pickerLevel?: PickerLevel; selectedCategory?: string; categoryQuery?: string; widgetQuery?: string; keys: string[]; } interface MenuItem { label: string; sublabel?: string; description?: string; disabled?: boolean; separator?: boolean; powerlineSeparator?: 'triangle-right'; } interface EditorWidget { displayText: string; description: string; } interface WidgetCatalogItem extends MenuItem { type: string; category: string; searchText: string; } const TUI_START_FRAME = 96; const COMMAND_TEXT = '$ npx ccstatusline@latest'; const THEMES: Record = { 'custom': { name: 'Custom', description: 'Uses individual widget background colors', swatches: [ { foreground: '#F8FAFC', background: '#334155' }, { foreground: '#E2E8F0', background: '#475569' }, { foreground: '#0F172A', background: '#94A3B8' }, { foreground: '#F8FAFC', background: '#1E293B' }, { foreground: '#0F172A', background: '#CBD5E1' }, { foreground: '#E2E8F0', background: '#64748B' } ] }, 'nord': { name: 'Nord', description: 'Arctic, north-bluish color palette', swatches: [ { foreground: '#2E3440', background: '#88C0D0' }, { foreground: '#D8DEE9', background: '#4C566A' }, { foreground: '#FDF6E3', background: '#5E81AC' }, { foreground: '#2E3440', background: '#B48EAD' }, { foreground: '#2E3440', background: '#A3BE8C' }, { foreground: '#D8DEE9', background: '#4C566A' } ] }, 'nord-aurora': { name: 'Nord Aurora', description: 'Nord theme with aurora colors', swatches: [ { foreground: '#ECEFF4', background: '#BF616A' }, { foreground: '#2E3440', background: '#EBCB8B' }, { foreground: '#FDF6E3', background: '#5E81AC' }, { foreground: '#2E3440', background: '#A3BE8C' }, { foreground: '#2E3440', background: '#B48EAD' }, { foreground: '#ECEFF4', background: '#4C566A' } ] }, 'monokai': { name: 'Monokai', description: 'Dark background with vibrant colors', swatches: [ { foreground: '#272822', background: '#A6E22E' }, { foreground: '#F8F8F2', background: '#49483E' }, { foreground: '#272822', background: '#E6DB74' }, { foreground: '#272822', background: '#AE81FF' }, { foreground: '#272822', background: '#66D9EF' }, { foreground: '#F8F8F2', background: '#75715E' } ] }, 'solarized': { name: 'Solarized', description: 'Precision colors for readability', swatches: [ { foreground: '#073642', background: '#268BD2' }, { foreground: '#073642', background: '#B58900' }, { foreground: '#FDF6E3', background: '#586E75' }, { foreground: '#073642', background: '#2AA198' }, { foreground: '#073642', background: '#EEE8D5' }, { foreground: '#073642', background: '#B58900' } ] }, 'minimal': { name: 'Minimal', description: 'Clean monochrome theme', swatches: [ { foreground: '#FFFFFF', background: '#585858' }, { foreground: '#1C1C1C', background: '#D0D0D0' }, { foreground: '#FFFFFF', background: '#1A1A1A' }, { foreground: '#1C1C1C', background: '#A8A8A8' }, { foreground: '#E4E4E4', background: '#303030' }, { foreground: '#1C1C1C', background: '#D0D0D0' } ] }, 'dracula': { name: 'Dracula', description: 'Dark theme with purple accents', swatches: [ { foreground: '#282A36', background: '#BD93F9' }, { foreground: '#282A36', background: '#F8F8F2' }, { foreground: '#282A36', background: '#FF5555' }, { foreground: '#282A36', background: '#8BE9FD' }, { foreground: '#F8F8F2', background: '#44475A' }, { foreground: '#282A36', background: '#BD93F9' } ] }, 'catppuccin': { name: 'Catppuccin', description: 'Soothing pastel theme', swatches: [ { foreground: '#1E1E2E', background: '#CBA6F7' }, { foreground: '#CDD6F4', background: '#45475A' }, { foreground: '#1E1E2E', background: '#A6E3A1' }, { foreground: '#1E1E2E', background: '#F38BA8' }, { foreground: '#CDD6F4', background: '#585B70' }, { foreground: '#1E1E2E', background: '#F9E2AF' } ] }, 'gruvbox': { name: 'Gruvbox', description: 'Retro groove color scheme', swatches: [ { foreground: '#EBDBB2', background: '#CC241D' }, { foreground: '#282828', background: '#FABD2F' }, { foreground: '#282828', background: '#A89984' }, { foreground: '#FDF6E3', background: '#458588' }, { foreground: '#282828', background: '#98971A' }, { foreground: '#EBDBB2', background: '#CC241D' } ] }, 'onedark': { name: 'One Dark', description: 'Atom-inspired dark theme', swatches: [ { foreground: '#282C34', background: '#61AFEF' }, { foreground: '#ABB2BF', background: '#3E4452' }, { foreground: '#282C34', background: '#98C379' }, { foreground: '#282C34', background: '#E06C75' }, { foreground: '#282C34', background: '#E5C07B' }, { foreground: '#ABB2BF', background: '#3E4452' } ] }, 'tokyonight': { name: 'Tokyo Night', description: 'Clean, dark theme inspired by Tokyo nightlife', swatches: [ { foreground: '#1A1B26', background: '#7AA2F7' }, { foreground: '#1A1B26', background: '#D5D6DB' }, { foreground: '#1A1B26', background: '#BB9AF7' }, { foreground: '#1A1B26', background: '#E0AF68' }, { foreground: '#1A1B26', background: '#7DCFFF' }, { foreground: '#C0CAF5', background: '#414868' } ] } }; const THEME_ORDER: ThemeName[] = [ 'custom', 'nord', 'nord-aurora', 'monokai', 'solarized', 'minimal', 'dracula', 'catppuccin', 'gruvbox', 'onedark', 'tokyonight' ]; const MAIN_MENU: MenuItem[] = [ { label: '📝 Edit Lines', description: 'Configure any number of status lines with various widgets like model info, git status, and token usage' }, { label: '🎨 Edit Colors', description: 'Customize colors for each widget including foreground, background, and bold styling' }, { label: '⚡ Powerline Setup', description: 'Install Powerline fonts for enhanced visual separators and symbols in your status line' }, { label: '', separator: true }, { label: '💻 Terminal Options', description: 'Configure terminal-specific settings for optimal display' }, { label: '🌐 Global Overrides', description: 'Set global padding, separators, and color overrides that apply to all widgets' }, { label: '', separator: true }, { label: '📦 Install to Claude Code', description: 'Add ccstatusline to your Claude Code settings for automatic status line rendering' }, { label: '🚪 Exit', description: 'Exit the configuration tool' }, { label: '', separator: true }, { label: '⭐ Like ccstatusline? Star us on GitHub', description: 'Open the ccstatusline GitHub repository in your browser so you can star the project' } ]; const FINAL_MENU: MenuItem[] = [ ...MAIN_MENU.slice(0, 8), { label: '💾 Save & Exit', description: 'Save all changes and exit the configuration tool' }, { label: '❌ Exit without saving', description: 'Exit without saving your changes' }, { label: '', separator: true }, MAIN_MENU[10] ?? { label: '⭐ Like ccstatusline? Star us on GitHub' } ]; const LINE_ONE_WIDGETS: EditorWidget[] = [ { displayText: 'Model', description: 'Displays the Claude model name (e.g., Claude 3.5 Sonnet)' }, { displayText: 'Context Length', description: 'Shows the current context window size in tokens' }, { displayText: 'Git Branch', description: 'Shows the current git branch name' }, { displayText: 'Git Changes', description: 'Shows git changes count (+insertions, -deletions)' }, { displayText: 'Tokens Total', description: 'Shows total token count (input + output + cache) for the current session' }, { displayText: 'Session Cost', description: 'Shows the total session cost in USD' } ]; const LINE_TWO_WIDGETS: EditorWidget[] = [ { displayText: 'Session Usage', description: 'Shows daily/session API usage percentage' }, { displayText: 'Weekly Usage', description: 'Shows weekly API usage percentage' }, { displayText: 'Block Reset Timer', description: 'Shows time remaining until current 5hr block reset window' }, { displayText: 'Weekly Reset Timer', description: 'Shows time remaining until weekly usage reset' } ]; const WIDGET_CATEGORIES: MenuItem[] = [ { label: 'All', description: 'Search across all widget categories.' }, { label: 'Core' }, { label: 'Git' }, { label: 'Jujutsu' }, { label: 'Environment' }, { label: 'Tokens' }, { label: 'Token Speed' }, { label: 'Context' }, { label: 'Session' }, { label: 'Usage' }, { label: 'Custom' }, { label: 'Layout' } ]; const WIDGET_CATALOG: WidgetCatalogItem[] = [ makeCatalogItem('model', 'Model', 'Displays the Claude model name (e.g., Claude 3.5 Sonnet)', 'Core'), makeCatalogItem('output-style', 'Output Style', 'Shows the current Claude Code output style', 'Core'), makeCatalogItem('version', 'Version', 'Shows the Claude Code version', 'Core'), makeCatalogItem('thinking-effort', 'Thinking Effort', 'Shows the active thinking effort setting', 'Core'), makeCatalogItem('git-branch', 'Git Branch', 'Shows the current git branch', 'Git'), makeCatalogItem('git-changes', 'Git Changes', 'Shows git changes count (+insertions, -deletions)', 'Git'), makeCatalogItem('git-status', 'Git Status', 'Shows concise git repository status', 'Git'), makeCatalogItem('jj-description', 'Jujutsu Description', 'Shows the current Jujutsu change description', 'Jujutsu'), makeCatalogItem('current-working-dir', 'Current Working Dir', 'Shows the current working directory', 'Environment'), makeCatalogItem('terminal-width', 'Terminal Width', 'Shows the detected terminal width', 'Environment'), makeCatalogItem('tokens-input', 'Tokens Input', 'Shows input token count for the current session', 'Tokens'), makeCatalogItem('tokens-output', 'Tokens Output', 'Shows output token count for the current session', 'Tokens'), makeCatalogItem('tokens-cached', 'Tokens Cached', 'Shows cached token count for the current session', 'Tokens'), makeCatalogItem('tokens-total', 'Tokens Total', 'Shows total token count (input + output + cache) for the current session', 'Tokens'), makeCatalogItem('input-speed', 'Input Speed', 'Shows input token processing speed', 'Token Speed'), makeCatalogItem('output-speed', 'Output Speed', 'Shows output token generation speed', 'Token Speed'), makeCatalogItem('total-speed', 'Total Speed', 'Shows total token processing speed', 'Token Speed'), makeCatalogItem('context-length', 'Context Length', 'Shows the current context window size in tokens', 'Context'), makeCatalogItem('context-percentage', 'Context Percentage', 'Shows percentage of context window used', 'Context'), makeCatalogItem('context-bar', 'Context Bar', 'Shows context usage as a progress bar', 'Context'), makeCatalogItem('session-clock', 'Session Clock', 'Shows elapsed time since current session started', 'Session'), makeCatalogItem('session-cost', 'Session Cost', 'Shows the total session cost in USD', 'Session'), makeCatalogItem('block-timer', 'Block Timer', 'Shows current 5hr block elapsed time or progress', 'Usage'), makeCatalogItem('session-usage', 'Session Usage', 'Shows daily/session API usage percentage', 'Usage'), makeCatalogItem('weekly-usage', 'Weekly Usage', 'Shows weekly API usage percentage', 'Usage'), makeCatalogItem('weekly-sonnet-usage', 'Weekly Sonnet Usage', 'Shows weekly Sonnet API usage percentage', 'Usage'), makeCatalogItem('weekly-opus-usage', 'Weekly Opus Usage', 'Shows weekly Opus API usage percentage', 'Usage'), makeCatalogItem('reset-timer', 'Block Reset Timer', 'Shows time remaining until current 5hr block reset window', 'Usage'), makeCatalogItem('weekly-reset-timer', 'Weekly Reset Timer', 'Shows time remaining until weekly usage reset', 'Usage'), makeCatalogItem('custom-text', 'Custom Text', 'Displays custom static text', 'Custom'), makeCatalogItem('custom-symbol', 'Custom Symbol', 'Displays a custom symbol', 'Custom'), makeCatalogItem('custom-command', 'Custom Command', 'Runs a custom shell command and displays output', 'Custom'), makeCatalogItem('separator', 'Separator', 'A separator character between status line widgets', 'Layout'), makeCatalogItem('flex-separator', 'Flex Separator', 'Expands to fill available terminal width', 'Layout') ]; function makeCatalogItem( type: string, label: string, description: string, category: string ): WidgetCatalogItem { return { type, label, description, category, searchText: `${label} ${description} ${type}`.toLowerCase() }; } const POWERLINE_ITEMS: MenuItem[] = [ { label: 'Separator', description: 'Choose the glyph used between powerline segments.' }, { label: 'Start Cap', description: 'Configure the cap glyph that appears at the start of each powerline line.' }, { label: 'End Cap', description: 'Configure the cap glyph that appears at the end of each powerline line.' }, { label: 'Themes', description: 'Preview built-in powerline themes or copy a theme into custom widget colors.' }, { label: '', separator: true }, { label: '← Back' } ]; function clampProgress( frame: number, start: number, end: number ): number { return interpolate(frame, [start, end], [0, 1], { easing: Easing.bezier(0.16, 1, 0.3, 1), extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); } function getTypedText( frame: number, start: number, end: number, text: string ): string { const length = getTypedTextLength(frame, start, end, text); return text.slice(0, length); } function getTypedTextLength( frame: number, start: number, end: number, text: string ): number { if (frame < start) { return 0; } if (frame >= end) { return text.length; } const span = Math.max(1, end - start); const progress = (frame - start) / span; return Math.min(text.length, Math.floor(progress * text.length) + 1); } function getTypingKeys( frame: number, start: number, end: number, text: string, openingKey?: string ): string[] { if (frame < start) { return openingKey ? [openingKey] : []; } const length = getTypedTextLength(frame, start, end, text); const key = text[Math.max(0, length - 1)]; if (!key) { return openingKey ? [openingKey] : []; } return [key === ' ' ? 'Space' : key]; } function makePhase(overrides: Partial): Phase { const lineOneWidgetCount = overrides.lineOneWidgetCount ?? 4; const lineTwoWidgetCount = overrides.lineTwoWidgetCount ?? 0; return { title: 'Configure ccstatusline', subtitle: '', screen: 'main', powerline: false, selectedTheme: 'nord-aurora', selectedMainIndex: 0, selectedLineIndex: 0, selectedItemIndex: 0, lineOneConfigured: lineOneWidgetCount >= LINE_ONE_WIDGETS.length, lineOneWidgetCount, lineNumber: 1, lineTwoConfigured: lineTwoWidgetCount >= LINE_TWO_WIDGETS.length, lineTwoWidgetCount, sessionUsageMode: 'time', weeklyUsageMode: 'time', keys: [], ...overrides }; } function getPhase(frame: number): Phase { if (frame < TUI_START_FRAME) { return makePhase({ title: 'Launch ccstatusline', screen: 'launch', lineOneWidgetCount: 4, keys: frame > 82 ? ['Enter'] : [] }); } if (frame < 140) { return makePhase({ title: 'Open Edit Lines', screen: 'main', keys: ['Enter'] }); } if (frame < 180) { return makePhase({ title: 'Choose line 1', screen: 'lines', selectedLineIndex: 0, keys: ['Enter'] }); } if (frame < 210) { return makePhase({ title: 'Edit line 1', screen: 'items', lineNumber: 1, selectedItemIndex: 0, keys: ['Enter'] }); } if (frame < 230) { return makePhase({ screen: 'items', lineNumber: 1, selectedItemIndex: 1, keys: ['Down'] }); } if (frame < 250) { return makePhase({ screen: 'items', lineNumber: 1, selectedItemIndex: 2, keys: ['Down'] }); } if (frame < 270) { return makePhase({ screen: 'items', lineNumber: 1, selectedItemIndex: 3, keys: ['Down'] }); } if (frame < 300) { return makePhase({ title: 'Add Tokens Total', screen: 'picker', lineNumber: 1, selectedItemIndex: 0, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: '', keys: ['a'] }); } if (frame < 335) { const query = 'tokens total'; return makePhase({ title: 'Search Tokens Total', screen: 'picker', lineNumber: 1, selectedItemIndex: 0, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: getTypedText(frame, 302, 330, query), keys: getTypingKeys(frame, 302, 330, query) }); } if (frame < 370) { return makePhase({ title: 'Tokens Total added', screen: 'items', lineNumber: 1, selectedItemIndex: 4, lineOneWidgetCount: 5, keys: ['Enter'] }); } if (frame < 400) { const query = 'session cost'; return makePhase({ title: 'Search Session Cost', screen: 'picker', lineNumber: 1, selectedItemIndex: 0, lineOneWidgetCount: 5, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: getTypedText(frame, 374, 396, query), keys: getTypingKeys(frame, 374, 396, query, 'a') }); } if (frame < 435) { return makePhase({ title: 'Session Cost added', screen: 'items', lineNumber: 1, selectedItemIndex: 5, lineOneWidgetCount: 6, keys: ['Enter'] }); } if (frame < 455) { return makePhase({ screen: 'lines', selectedLineIndex: 0, lineOneWidgetCount: 6, keys: ['Esc'] }); } if (frame < 475) { return makePhase({ screen: 'lines', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, keys: ['Down'] }); } if (frame < 505) { return makePhase({ title: 'Edit line 2', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 0, selectedItemIndex: 0, keys: ['Enter'] }); } if (frame < 525) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'category', selectedCategory: 'All', keys: ['a'] }); } if (frame < 565) { const categoryIndex = Math.min( 9, Math.floor((frame - 525) / 4) + 1 ); const selectedCategory = WIDGET_CATEGORIES[categoryIndex]?.label ?? 'Usage'; return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'category', selectedCategory, keys: ['Down'] }); } if (frame < 578) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'category', selectedCategory: 'Usage', keys: ['Enter'] }); } if (frame < 591) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'widget', selectedCategory: 'Usage', selectedItemIndex: 0, keys: [] }); } if (frame < 604) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'widget', selectedCategory: 'Usage', selectedItemIndex: 1, keys: ['Down'] }); } if (frame < 617) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'widget', selectedCategory: 'Usage', selectedItemIndex: 2, keys: ['Down'] }); } if (frame < 630) { return makePhase({ screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, pickerLevel: 'widget', selectedCategory: 'Usage', selectedItemIndex: 2, keys: ['Enter'] }); } if (frame < 645) { return makePhase({ title: 'Session Usage added', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 1, selectedItemIndex: 0, keys: [] }); } if (frame < 675) { const query = 'weekly usage'; return makePhase({ title: 'Search Weekly Usage', screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 1, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: getTypedText(frame, 649, 671, query), selectedItemIndex: 0, keys: getTypingKeys(frame, 649, 671, query, 'a') }); } if (frame < 705) { return makePhase({ title: 'Weekly Usage added', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 2, selectedItemIndex: 1, keys: ['Enter'] }); } if (frame < 735) { const query = 'block reset'; return makePhase({ title: 'Search Block Reset Timer', screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 2, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: getTypedText(frame, 709, 731, query), selectedItemIndex: 0, keys: getTypingKeys(frame, 709, 731, query, 'a') }); } if (frame < 765) { return makePhase({ title: 'Block Reset Timer added', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 3, selectedItemIndex: 2, keys: ['Enter'] }); } if (frame < 795) { const query = 'weekly reset'; return makePhase({ title: 'Search Weekly Reset Timer', screen: 'picker', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 3, pickerLevel: 'category', selectedCategory: 'All', categoryQuery: getTypedText(frame, 769, 791, query), selectedItemIndex: 0, keys: getTypingKeys(frame, 769, 791, query, 'a') }); } if (frame < 825) { return makePhase({ title: 'Weekly Reset Timer added', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 3, keys: ['Enter'] }); } if (frame < 845) { return makePhase({ screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 2, keys: ['Up'] }); } if (frame < 865) { return makePhase({ screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 1, keys: ['Up'] }); } if (frame < 885) { return makePhase({ screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 0, keys: ['Up'] }); } if (frame < 910) { return makePhase({ title: 'Session Usage long bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 0, sessionUsageMode: 'progress', keys: ['p'] }); } if (frame < 935) { return makePhase({ title: 'Session Usage medium bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 0, sessionUsageMode: 'progress-short', keys: ['p'] }); } if (frame < 960) { return makePhase({ title: 'Session Usage short bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 0, sessionUsageMode: 'slider', keys: ['p'] }); } if (frame < 980) { return makePhase({ screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 1, sessionUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1005) { return makePhase({ title: 'Weekly Usage long bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 1, sessionUsageMode: 'slider', weeklyUsageMode: 'progress', keys: ['p'] }); } if (frame < 1030) { return makePhase({ title: 'Weekly Usage medium bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 1, sessionUsageMode: 'slider', weeklyUsageMode: 'progress-short', keys: ['p'] }); } if (frame < 1055) { return makePhase({ title: 'Weekly Usage short bar', screen: 'items', selectedLineIndex: 1, lineOneWidgetCount: 6, lineNumber: 2, lineTwoWidgetCount: 4, selectedItemIndex: 1, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['p'] }); } if (frame < 1085) { return makePhase({ screen: 'lines', selectedLineIndex: 1, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', lineNumber: 2, keys: ['Esc'] }); } if (frame < 1105) { return makePhase({ screen: 'main', selectedMainIndex: 0, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Esc'] }); } if (frame < 1125) { return makePhase({ screen: 'main', selectedMainIndex: 1, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1145) { return makePhase({ screen: 'main', selectedMainIndex: 2, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1175) { return makePhase({ title: 'Open Powerline setup', screen: 'powerline', powerline: false, selectedMainIndex: 2, selectedTheme: 'minimal', selectedItemIndex: 5, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Enter'] }); } if (frame < 1205) { return makePhase({ title: 'Turn on Powerline mode', screen: 'powerline', powerline: true, selectedMainIndex: 2, selectedTheme: 'minimal', selectedItemIndex: 0, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['t'] }); } if (frame < 1225) { return makePhase({ screen: 'powerline', powerline: true, selectedMainIndex: 2, selectedTheme: 'minimal', selectedItemIndex: 1, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1245) { return makePhase({ screen: 'powerline', powerline: true, selectedMainIndex: 2, selectedTheme: 'minimal', selectedItemIndex: 2, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1275) { return makePhase({ screen: 'powerline', powerline: true, selectedMainIndex: 2, selectedTheme: 'minimal', selectedItemIndex: 3, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Down'] }); } if (frame < 1385) { const themeIndex = Math.min( THEME_ORDER.length - 1, Math.max(5, 5 + Math.floor((frame - 1295) / 14)) ); return makePhase({ title: 'Preview built-in themes', screen: 'themes', powerline: true, selectedTheme: THEME_ORDER[themeIndex] ?? 'minimal', selectedMainIndex: 2, selectedItemIndex: themeIndex, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: frame < 1295 ? ['Enter'] : ['Down'] }); } if (frame < 1425) { return makePhase({ title: 'Apply Tokyo Night', screen: 'powerline', powerline: true, selectedTheme: 'tokyonight', selectedMainIndex: 2, selectedItemIndex: 3, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Enter'] }); } return makePhase({ title: 'Exit Powerline setup', screen: 'main', powerline: true, selectedTheme: 'tokyonight', selectedMainIndex: 2, selectedItemIndex: 3, lineOneWidgetCount: 6, lineTwoWidgetCount: 4, sessionUsageMode: 'slider', weeklyUsageMode: 'slider', keys: ['Esc'] }); } function getPreviewLines(phase: Phase): string[][] { const firstLine = [ 'Model: Claude', 'Ctx: 18.6k', '⎇ main', '(+42,-10)', 'Total: 30.6k', 'Cost: $2.45' ].slice(0, phase.lineOneWidgetCount); const secondLine = getLineTwoPreviewSegments(phase); if (secondLine.length === 0) { return [firstLine]; } return [ firstLine, secondLine ]; } function getLineTwoPreviewSegments(phase: Phase): string[] { const segments = [ renderUsagePreview('Session', 20, phase.sessionUsageMode), renderUsagePreview('Weekly', 12, phase.weeklyUsageMode), 'Reset: 4hr 30m', 'Weekly Reset: 1d 12hr 30m' ]; return segments.slice(0, phase.lineTwoWidgetCount); } function renderUsagePreview( label: 'Session' | 'Weekly', percent: number, mode: UsageDisplayMode ): string { if (mode === 'progress') { return `${label}: [${makeProgressBar(percent, 32)}] ${percent.toFixed(1)}%`; } if (mode === 'progress-short') { return `${label}: [${makeProgressBar(percent, 16)}] ${percent.toFixed(1)}%`; } if (mode === 'slider') { return `${label}: ${makeSliderPreview(percent)} ${percent.toFixed(1)}%`; } if (mode === 'slider-only') { return `${label}: ${makeSliderPreview(percent)}`; } return `${label}: ${percent.toFixed(1)}%`; } function makeProgressBar(percent: number, width: number): string { const clamped = Math.max(0, Math.min(100, percent)); const filled = Math.floor((clamped / 100) * width); return '█'.repeat(filled) + '░'.repeat(width - filled); } function makeSliderPreview(percent: number): string { const width = 10; const clamped = Math.max(0, Math.min(100, percent)); const filled = Math.round((clamped / 100) * width); return '▓'.repeat(filled) + '░'.repeat(width - filled); } export const TUIDemo = () => { const frame = useCurrentFrame(); const phase = getPhase(frame); const enter = clampProgress(frame, 0, 36); const terminalX = interpolate(enter, [0, 1], [-46, 0]); return (
); }; function Background({ frame }: { frame: number }) { const shade = interpolate( Math.sin(frame / 46), [-1, 1], [0.88, 1] ); return ( ); } function TerminalWindow({ frame, phase }: { frame: number; phase: Phase; }) { const launched = frame >= TUI_START_FRAME; const tuiOpacity = clampProgress(frame, TUI_START_FRAME, TUI_START_FRAME + 18); return (
ccstatusline - npx ccstatusline@latest
{!launched ? ( ) : (
)}
{launched && ( )}
); } function KeypressHint({ frame, keys }: { frame: number; keys: string[]; }) { if (keys.length === 0) { return null; } const key = keys[keys.length - 1] ?? ''; const pulseFrame = frame % 20; const scale = interpolate(pulseFrame, [0, 3, 10, 20], [1.18, 1.1, 1, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); const glow = interpolate(pulseFrame, [0, 8, 20], [0.44, 0.12, 0.12], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); return (
key {key}
); } function LaunchCommand({ frame }: { frame: number }) { const typedLength = Math.min(COMMAND_TEXT.length, Math.floor(frame / 3)); const typed = COMMAND_TEXT.slice(0, typedLength); const cursorOpacity = Math.floor(frame / 12) % 2 === 0 ? 1 : 0.18; const executed = typedLength >= COMMAND_TEXT.length && frame > 82; return (
{typed} {!executed && ( )}
{executed && (
Starting ccstatusline...
)}
); } function TuiScreen({ phase }: { phase: Phase }) { const theme = THEMES[phase.selectedTheme]; const previewLines = getPreviewLines(phase); const alignedWidths = phase.powerline ? getAlignedSegmentWidths(previewLines) : undefined; return ( <>
CCStatusline Configuration  | v {PACKAGE_VERSION} {phase.screen === 'final' && ( ✓ Configuration saved )}
> Preview (ctrl+s to save configuration at any time)
{previewLines.map((segments, index) => (
{phase.powerline ? ( ) : }
))}
{renderScreenContent(phase)}
); } function PlainPreview({ segments }: { segments: string[] }) { return (
{segments.map((segment, index) => ( {segment} {index < segments.length - 1 &&  | } ))}
); } function PowerlinePreview({ segments, theme, alignedWidths, lineIndex, lineCount }: { segments: string[]; theme: Theme; alignedWidths?: number[]; lineIndex: number; lineCount: number; }) { const isFirstLine = lineIndex === 0; const isLastLine = lineIndex === lineCount - 1; return (
{segments.map((segment, index) => { const swatch = theme.swatches[index % theme.swatches.length] ?? theme.swatches[0]; const nextSwatch = theme.swatches[(index + 1) % theme.swatches.length] ?? theme.swatches[0]; const isLast = index === segments.length - 1; return (
{segment}
{!isLast && (
)}
); })}
); } function getAlignedSegmentWidths(lines: string[][]): number[] { const maxSegments = Math.max(...lines.map(line => line.length)); return Array.from({ length: maxSegments }, (_, index) => { const longest = Math.max(...lines.map(line => line[index]?.length ?? 0)); return Math.max(72, longest * 8 + 30); }); } function plainSegmentStyle(segment: string): CSSProperties { return { color: getFreshInstallWidgetColor(segment), fontWeight: 700 }; } function getFreshInstallWidgetColor(segment: string): string { if (segment.startsWith('Model:') || segment.startsWith('Total:')) { return '#06989a'; } if (segment.startsWith('Ctx:')) { return '#555753'; } if (segment.startsWith('⎇')) { return '#75507b'; } if (segment.startsWith('(+')) { return '#c4a000'; } if (segment.startsWith('Cost:')) { return '#4e9a06'; } return '#729fcf'; } function renderScreenContent(phase: Phase): ReactNode { switch (phase.screen) { case 'lines': return ; case 'items': return ; case 'picker': return ; case 'powerline': return ; case 'themes': return ; case 'final': return ( ); case 'main': default: return ( ); } } function MainScreen({ items, selectedIndex }: { items: MenuItem[]; selectedIndex: number; }) { return (
Main Menu
); } function LineSelectorScreen({ phase }: { phase: Phase }) { const firstLineWidgets = phase.lineOneWidgetCount; const secondLineWidgets = phase.lineTwoWidgetCount; const items: MenuItem[] = [ { label: '☰ Line 1', sublabel: `(${firstLineWidgets} widgets)` }, { label: '☰ Line 2', sublabel: secondLineWidgets > 0 ? '(4 widgets)' : '(empty)' }, { label: '', separator: true }, { label: '← Back' } ]; return (
Select Line to Edit Items
Choose which status line to configure
(a) to append new line, (d) to delete line, (m) to move line, ESC to go back
); } function ItemsScreen({ phase }: { phase: Phase }) { const widgets = getEditorWidgets(phase); const selectedWidget = widgets[phase.selectedItemIndex] ?? widgets[0]; const help = getItemsHelpText(phase, widgets); return (
Edit Line {' '} {phase.lineNumber} {' '} {phase.powerline && ( ⚠ Powerline mode active: separators controlled by powerline settings )}
{help.main}
{help.custom}
{widgets.length === 0 ? (
No widgets. Press 'a' to add one.
) : (
{widgets.map((widget, index) => { const selected = index === phase.selectedItemIndex; const modifierText = getWidgetModifierText(phase, index); return (
{selected ? '▶ ' : ' '} {`${index + 1}. ${widget.displayText}`} {modifierText && ( {modifierText} )}
); })}
)} {selectedWidget && widgets.length > 0 && (
{selectedWidget.description}
)}
); } function getEditorWidgets(phase: Phase): EditorWidget[] { return phase.lineNumber === 1 ? LINE_ONE_WIDGETS.slice(0, phase.lineOneWidgetCount) : LINE_TWO_WIDGETS.slice(0, phase.lineTwoWidgetCount); } function getWidgetModifierText(phase: Phase, index: number): string | undefined { if (phase.lineNumber !== 2) { return undefined; } if (index === 0) { return getUsageModifierText(phase.sessionUsageMode); } if (index === 1) { return getUsageModifierText(phase.weeklyUsageMode); } return undefined; } function getUsageModifierText(mode: UsageDisplayMode): string | undefined { if (mode === 'progress') { return '(long bar)'; } if (mode === 'progress-short') { return '(medium bar)'; } if (mode === 'slider') { return '(short bar)'; } if (mode === 'slider-only') { return '(short bar only)'; } return undefined; } function getItemsHelpText( phase: Phase, widgets: EditorWidget[] ): { main: string; custom: string } { if (widgets.length === 0) { return { main: '(a)dd via picker, (i)nsert via picker, ESC back', custom: ' ' }; } let main = '↑↓ select, ←→ open type picker, Enter to move, (a)dd via picker, (i)nsert via picker, (k) clone, (d)elete, (c)lear line'; main += ', (r)aw value'; main += ', ESC back'; return { main, custom: getCustomKeybindsText(phase) || ' ' }; } function getCustomKeybindsText(phase: Phase): string { if (phase.lineNumber !== 2) { return ''; } if (phase.selectedItemIndex === 0) { return getUsagePercentKeybindsText(phase.sessionUsageMode); } if (phase.selectedItemIndex === 1) { return getUsagePercentKeybindsText(phase.weeklyUsageMode); } if (phase.selectedItemIndex === 2) { return '(p)rogress toggle, (s)hort time, (t)imestamp'; } if (phase.selectedItemIndex === 3) { return '(p)rogress toggle, (s)hort time, (t)imestamp, (h)ours only'; } return ''; } function getUsagePercentKeybindsText(mode: UsageDisplayMode): string { if (mode === 'time') { return '(p)rogress toggle'; } return '(p)rogress toggle, in(v)ert fill, (t)ime cursor'; } function WidgetPicker({ phase }: { phase: Phase }) { const pickerActionLabel = 'Add Widget'; const pickerLevel = phase.pickerLevel ?? 'category'; const categoryQuery = phase.categoryQuery ?? ''; const widgetQuery = phase.widgetQuery ?? ''; const selectedCategory = phase.selectedCategory ?? 'All'; const categoryIndex = Math.max( 0, WIDGET_CATEGORIES.findIndex(category => category.label === selectedCategory) ); const isTopLevelSearch = pickerLevel === 'category' && categoryQuery.trim().length > 0; const items = getPickerItems( pickerLevel, selectedCategory, categoryQuery, widgetQuery ); const selected = isTopLevelSearch || pickerLevel === 'widget' ? Math.min(phase.selectedItemIndex, Math.max(0, items.length - 1)) : categoryIndex; const selectedItem = items[selected] ?? { label: '' }; return (
Edit Line {' '} {phase.lineNumber} {' '} {`[${pickerActionLabel.toUpperCase()}]`}
{pickerLevel === 'category' ? ( <>
{categoryQuery.trim().length > 0 ? '↑↓ select widget match, Enter apply, ESC clear/cancel' : '↑↓ select category, type to search all widgets, Enter continue, ESC cancel'}
Search: {categoryQuery || '(none)'}
) : ( <>
↑↓ select widget, type to search widgets, Enter apply, ESC back
Category: {' '} {selectedCategory} {' '} | Search: {' '} {widgetQuery || '(none)'}
)}
{items.map((item, index) => { const isSelected = index === selected; const query = isTopLevelSearch ? categoryQuery : pickerLevel === 'widget' ? widgetQuery : ''; return (
{isSelected ? '▶ ' : ' '} {`${index + 1}.\u00A0`}
); })}
{selectedItem.description && (
{selectedItem.description}
)}
); } function getPickerItems( pickerLevel: PickerLevel, selectedCategory: string, categoryQuery: string, widgetQuery: string ): MenuItem[] { if (pickerLevel === 'category') { if (!categoryQuery.trim()) { return WIDGET_CATEGORIES; } return filterDemoWidgetCatalog('All', categoryQuery); } return filterDemoWidgetCatalog(selectedCategory, widgetQuery); } function filterDemoWidgetCatalog( category: string, query: string ): WidgetCatalogItem[] { const categoryFiltered = category === 'All' ? [...WIDGET_CATALOG] : WIDGET_CATALOG.filter(entry => entry.category === category); const records: FuzzySearchRecord[] = categoryFiltered.map(entry => ({ item: entry, name: entry.label, type: entry.type, description: entry.description ?? '', searchText: entry.searchText, sortText: entry.label, secondarySortText: entry.type })); return filterFuzzySearchRecords(records, query); } function HighlightedLabel({ label, query, selected }: { label: string; query: string; selected: boolean; }) { if (!query.trim()) { return {label}; } const segments = getMatchSegments(label, query); return ( {segments.map((segment, index) => ( {segment.text} ))} ); } function PowerlineScreen({ phase }: { phase: Phase }) { const items = getPowerlineMenuItems(phase); return (
Powerline Setup
{phase.powerline ? ( <>
When enabled, global overrides are disabled and powerline separators are used
Continue Theme keeps the Powerline color sequence running across lines
) : (
Enable Powerline mode to configure separators, caps, and themes.
)}
); } function getPowerlineMenuItems(phase: Phase): MenuItem[] { const disabled = !phase.powerline; return POWERLINE_ITEMS.map((item) => { if (item.separator || item.label === '← Back') { return item; } const sublabel = item.label === 'Separator' ? '( - Triangle Right)' : item.label === 'Start Cap' ? '(multiple)' : item.label === 'End Cap' ? '( - Triangle)' : `(${getPowerlineThemeDisplay(phase.selectedTheme)})`; return { ...item, sublabel, disabled }; }); } function getPowerlineThemeDisplay(themeName: ThemeName): string { return THEMES[themeName].name; } function PowerlineSettingRow({ label, status, statusStyle, detail }: { label: string; status: string; statusStyle: CSSProperties; detail: string; }) { return (
{label} : {' '} {status} {`- ${detail}`}
); } function PowerlineMenuList({ items, selectedIndex }: { items: MenuItem[]; selectedIndex: number; }) { const selectedItem = items[selectedIndex]; return (
{items.map((item, index) => { if (item.separator || item.label.length === 0) { return
; } const selected = index === selectedIndex; const color = selected ? '#22C55E' : item.disabled ? '#64748B' : '#D7DEE8'; return (
{selected ? '▶ ' : ' '} {item.label} {item.sublabel && ( )}
); })} {selectedItem?.description && (
{selectedItem.description}
)}
); } function PowerlineMenuValue({ item }: { item: MenuItem }) { if (item.label === 'Separator') { return ( <> ( - Triangle Right) ); } if (item.label === 'End Cap') { return ( <> ( - Triangle) ); } return <>{item.sublabel}; } function PowerlineInlineGlyph() { return ; } function ThemeScreen({ phase }: { phase: Phase }) { const items: MenuItem[] = THEME_ORDER.map(themeName => ({ label: THEMES[themeName].name, sublabel: themeName === 'minimal' ? '(original)' : undefined, description: THEMES[themeName].description })); const selectedThemeName = THEME_ORDER[phase.selectedItemIndex] ?? phase.selectedTheme; return (
Powerline Theme Selection | {' '} Original: minimal
{`↑↓ navigate, Enter apply${selectedThemeName !== 'custom' ? ', (c)ustomize theme' : ''}, ESC cancel`}
{selectedThemeName !== 'custom' && (
Press (c) to customize this theme - copies colors to widgets
)}
); } function MenuList({ items, selectedIndex }: { items: MenuItem[]; selectedIndex: number; }) { const selectedItem = items[selectedIndex]; return (
{items.map((item, index) => { if (item.separator || item.label.length === 0) { return
; } const selected = index === selectedIndex; const color = selected ? '#22C55E' : item.disabled ? '#64748B' : '#D7DEE8'; return (
{selected ? '▶ ' : ' '} {item.label} {item.sublabel && ( <> {'\u00A0'} {item.sublabel} )} {item.powerlineSeparator && ( <> {'\u00A0'} ( - Triangle Right) )}
); })} {selectedItem?.description && (
{selectedItem.description}
)}
); } function PowerlineMenuGlyph({ selected }: { selected: boolean }) { return ( ); } const styles = { root: { backgroundColor: '#0A0F16', color: '#F8FAFC', fontFamily: '"Inter", "SF Pro Display", "Segoe UI", sans-serif' }, background: { backgroundImage: 'linear-gradient(135deg, #081018 0%, #101820 46%, #15130f 100%)' }, shell: { position: 'absolute', inset: '26px 28px', display: 'flex', alignItems: 'stretch', justifyContent: 'center' }, terminalWrap: { width: '100%', minWidth: 0 }, terminal: { position: 'relative', height: '100%', borderRadius: 22, backgroundColor: '#0E141B', border: '1px solid rgba(148, 163, 184, 0.22)', boxShadow: '0 34px 90px rgba(0, 0, 0, 0.55)', overflow: 'hidden' }, windowChrome: { height: 54, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', backgroundColor: '#121A24', borderBottom: '1px solid rgba(148, 163, 184, 0.16)' }, windowButtons: { position: 'absolute', left: 22, top: 20, display: 'flex', gap: 9 }, dot: { width: 13, height: 13, borderRadius: '50%' }, windowTitle: { color: '#93A4B8', fontFamily: '"SFMono-Regular", "Cascadia Code", "Menlo", monospace', fontSize: 14, letterSpacing: 0 }, terminalBody: { padding: '24px 30px', fontFamily: '"SFMono-Regular", "Cascadia Code", "Menlo", monospace', fontSize: 14, lineHeight: 1.25 }, launchBody: { height: 700, display: 'flex', flexDirection: 'column', justifyContent: 'flex-start' }, commandLine: { height: 42, display: 'flex', alignItems: 'center', color: '#CBD5E1', marginBottom: 12, fontSize: 14 }, commandText: { color: '#A7F3D0' }, cursor: { display: 'inline-block', width: 8, height: 18, marginLeft: 4, backgroundColor: '#A7F3D0' }, launchDimText: { color: '#94A3B8', fontSize: 14 }, tuiHeader: { display: 'flex', alignItems: 'center', marginBottom: 20 }, tuiTitle: { fontWeight: 800, color: '#7DD3FC' }, version: { color: '#E2E8F0', fontWeight: 700 }, savedMessage: { marginLeft: 14, color: '#4ADE80', fontWeight: 800 }, previewBox: { border: '1px solid rgba(148, 163, 184, 0.40)', borderRadius: 12, height: 48, display: 'flex', alignItems: 'center', paddingLeft: 20, color: '#94A3B8', marginBottom: 12 }, previewHeader: { display: 'flex', gap: 8, alignItems: 'center' }, promptChar: { color: '#E2E8F0' }, previewLines: { display: 'flex', flexDirection: 'column', gap: 0, marginBottom: 24 }, previewLine: { minHeight: 32, display: 'flex', alignItems: 'center' }, previewIndent: { whiteSpace: 'pre' }, plainPreview: { display: 'flex', alignItems: 'center', whiteSpace: 'nowrap' }, plainSeparator: { color: '#64748B' }, powerlinePreview: { display: 'flex', alignItems: 'stretch', height: 32, maxWidth: '100%', filter: 'drop-shadow(0 12px 22px rgba(0, 0, 0, 0.25))' }, powerlineGroup: { display: 'flex', alignItems: 'stretch' }, powerlineSegment: { display: 'flex', alignItems: 'center', boxSizing: 'border-box', height: 32, padding: '0 10px', fontWeight: 800, whiteSpace: 'nowrap', fontSize: 14 }, powerlineSeparator: { position: 'relative', width: 18, height: 32 }, powerlineTriangle: { position: 'absolute', left: 0, top: 0, width: 0, height: 0, borderTop: '16px solid transparent', borderBottom: '16px solid transparent', borderLeft: '18px solid' }, screenContent: { minHeight: 420 }, screenTitle: { fontWeight: 900, color: '#F8FAFC', marginBottom: 10, whiteSpace: 'pre' }, inlineWarning: { color: '#FACC15', fontWeight: 700, marginLeft: '3ch' }, helpText: { color: '#94A3B8', marginBottom: 4 }, helpSpacer: { height: 18, color: '#94A3B8' }, emptyLine: { color: '#94A3B8', marginTop: 10 }, menuList: { display: 'grid', gap: 5, marginTop: 10 }, menuRow: { display: 'flex', alignItems: 'center', gap: 0, minHeight: 28 }, menuGap: { height: 8 }, menuPointer: { width: '3ch', color: '#22C55E', fontWeight: 900, whiteSpace: 'pre' }, menuSelectedText: { fontWeight: 900 }, description: { marginTop: 14, paddingLeft: '2ch', color: '#94A3B8', lineHeight: 1.28 }, modePill: { color: '#22D3EE', fontWeight: 900 }, searchLine: { color: '#94A3B8', marginBottom: 10 }, searchValue: { color: '#22D3EE', fontWeight: 800 }, pickerList: { display: 'grid', gap: 3, marginTop: 10 }, pickerRow: { display: 'flex', alignItems: 'center', minHeight: 24 }, pickerPointer: { width: '3ch', color: '#22C55E', fontWeight: 900, whiteSpace: 'pre' }, matchText: { color: '#FDE68A', fontWeight: 900 }, powerlineSetting: { display: 'flex', alignItems: 'center', marginBottom: 7, color: '#CBD5E1' }, powerlineSettingLabel: { display: 'inline-block', width: '16ch', textAlign: 'right', whiteSpace: 'pre' }, powerlineStatus: { display: 'inline-block', width: '13ch', textAlign: 'left' }, powerlineNotes: { marginTop: 20, marginBottom: 4, color: '#94A3B8' }, powerlineMenuList: { display: 'grid', gap: 5, marginTop: 18 }, powerlineMenuRow: { display: 'flex', alignItems: 'center', minHeight: 28 }, powerlineMenuLabel: { display: 'inline-block', width: '12ch', whiteSpace: 'pre' }, powerlineMenuSelectedLabel: { display: 'inline-block', width: '12ch', whiteSpace: 'pre', fontWeight: 900 }, powerlineMenuValue: { fontFamily: '"Symbols Nerd Font Mono", "MesloLGS NF", "JetBrainsMono Nerd Font", "SFMono-Regular", "Cascadia Code", "Menlo", monospace' }, powerlineInlineGlyph: { display: 'inline-block', width: 0, height: 0, borderTop: '0.5em solid transparent', borderBottom: '0.5em solid transparent', borderLeft: '0.72em solid currentColor', transform: 'translateY(0.14em)', marginLeft: 1, marginRight: 2 }, goodText: { color: '#4ADE80', fontWeight: 900 }, badText: { color: '#F87171', fontWeight: 900 }, dimText: { color: '#94A3B8', fontWeight: 500 }, powerlineMenuGlyph: { display: 'inline-block', width: 0, height: 0, borderTop: '9px solid transparent', borderBottom: '9px solid transparent', borderLeft: '12px solid', transform: 'translateY(3px)', marginLeft: 2, marginRight: 2 }, themeFooter: { marginTop: 14, color: '#94A3B8', fontSize: 14 }, featurePanel: { height: '100%', borderRadius: 22, background: 'rgba(15, 23, 42, 0.78)', border: '1px solid rgba(148, 163, 184, 0.24)', boxShadow: '0 34px 90px rgba(0, 0, 0, 0.40)', padding: '42px 40px', display: 'flex', flexDirection: 'column', gap: 24 }, panelHeader: { minHeight: 220 }, eyebrow: { color: '#38BDF8', fontSize: 14, letterSpacing: 0, textTransform: 'uppercase', fontWeight: 900, marginBottom: 14 }, panelTitle: { margin: 0, fontSize: 14, lineHeight: 1.02, letterSpacing: 0, color: '#F8FAFC' }, panelSubtitle: { margin: '18px 0 0 0', fontSize: 14, lineHeight: 1.32, color: '#B6C2D2' }, keyStack: { display: 'flex', flexWrap: 'wrap', gap: 10 }, keyCap: { padding: '10px 14px', borderRadius: 8, backgroundColor: '#0F172A', color: '#E0F2FE', border: '1px solid rgba(56, 189, 248, 0.35)', fontFamily: '"SFMono-Regular", "Cascadia Code", "Menlo", monospace', fontSize: 14, fontWeight: 800 }, featureCard: { borderRadius: 14, border: '1px solid rgba(148, 163, 184, 0.20)', backgroundColor: 'rgba(2, 6, 23, 0.42)', padding: 22 }, cardTitle: { color: '#94A3B8', textTransform: 'uppercase', fontSize: 14, letterSpacing: 0, fontWeight: 900, marginBottom: 16 }, lineMetric: { fontSize: 14, color: '#A7F3D0', fontWeight: 900, lineHeight: 1 }, themeName: { fontSize: 14, fontWeight: 900, marginBottom: 12, color: '#F8FAFC' }, themeDescription: { marginTop: 12, color: '#B6C2D2', fontSize: 14, lineHeight: 1.35 }, timelineShell: { position: 'absolute', left: 76, right: 76, bottom: 54 }, timelineTrack: { height: 7, borderRadius: 999, backgroundColor: 'rgba(148, 163, 184, 0.18)', overflow: 'hidden' }, timelineFill: { height: '100%', borderRadius: 999, background: 'linear-gradient(90deg, #38BDF8 0%, #A6E3A1 58%, #E0AF68 100%)' }, timelineLabels: { display: 'flex', justifyContent: 'space-between', color: '#94A3B8', fontSize: 14, marginTop: 12, fontFamily: '"SFMono-Regular", "Cascadia Code", "Menlo", monospace', textTransform: 'uppercase', letterSpacing: 0 }, keypressHint: { position: 'absolute', right: 24, bottom: 18, display: 'flex', alignItems: 'center', gap: 8, color: 'rgba(203, 213, 225, 0.72)', fontFamily: '"SFMono-Regular", "Cascadia Code", "Menlo", monospace', fontSize: 14, pointerEvents: 'none' }, keypressLabel: { color: 'rgba(148, 163, 184, 0.62)' }, keypressValue: { minWidth: 44, textAlign: 'center', padding: '4px 8px', borderRadius: 7, border: '1px solid rgba(148, 163, 184, 0.20)', backgroundColor: 'rgba(2, 6, 23, 0.34)', color: 'rgba(226, 232, 240, 0.82)', fontWeight: 800 } } satisfies Record;