@toolr/ui-design 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/ai-manifest.json +35 -20
  2. package/components/composites/dashboard-list-item.tsx +172 -0
  3. package/components/composites/dashboard-panel.tsx +218 -0
  4. package/components/content/info-panel-primitives.tsx +9 -8
  5. package/components/diagrams/diagram-utils.tsx +2 -1
  6. package/components/hooks/use-dropdown-portal.ts +39 -0
  7. package/components/lib/accent-context.ts +10 -0
  8. package/components/lib/{ai-tools.tsx → coding-agents.tsx} +23 -8
  9. package/components/lib/custom-icons.tsx +37 -0
  10. package/components/lib/form-colors.ts +16 -16
  11. package/components/lib/git-providers.tsx +39 -0
  12. package/components/lib/theme-engine.ts +59 -10
  13. package/components/lib/toolr-brand.tsx +23 -9
  14. package/components/sections/captured-issues/captured-issues-panel.tsx +17 -8
  15. package/components/sections/{ai-tools-paths/tools-paths-panel.tsx → coding-agent-paths/agent-paths-panel.tsx} +70 -62
  16. package/components/sections/coding-agent-paths/index.ts +37 -0
  17. package/components/sections/{ai-tools-paths → coding-agent-paths}/types.ts +28 -28
  18. package/components/sections/coding-agent-paths/use-agent-paths.ts +159 -0
  19. package/components/sections/golden-snapshots/file-diff-viewer.tsx +10 -9
  20. package/components/sections/golden-snapshots/golden-sync-panel.tsx +12 -3
  21. package/components/sections/golden-snapshots/snapshot-manager.tsx +9 -7
  22. package/components/sections/golden-snapshots/status-overview.tsx +8 -8
  23. package/components/sections/golden-snapshots/version-manager.tsx +6 -6
  24. package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +3 -3
  25. package/components/sections/prompt-editor/index.ts +1 -1
  26. package/components/sections/prompt-editor/simulator-prompt-editor.tsx +13 -5
  27. package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +18 -10
  28. package/components/sections/prompt-editor/types.ts +2 -2
  29. package/components/sections/report-bug/report-bug-form.tsx +12 -4
  30. package/components/sections/report-bug/screenshot-uploader.tsx +11 -3
  31. package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +12 -4
  32. package/components/sections/snapshot-browser/snapshot-tree.tsx +5 -4
  33. package/components/sections/snapshot-browser/types.ts +1 -1
  34. package/components/sections/snippets-editor/snippets-editor.tsx +16 -9
  35. package/components/settings/SettingsHeader.tsx +2 -2
  36. package/components/settings/SettingsPanel.tsx +11 -3
  37. package/components/settings/SettingsTreeNav.tsx +15 -9
  38. package/components/ui/action-dialog.tsx +24 -30
  39. package/components/ui/ai-action-button.tsx +10 -7
  40. package/components/ui/ai-execution-action-buttons.tsx +13 -5
  41. package/components/ui/badge.tsx +7 -4
  42. package/components/ui/bottom-panel-header.tsx +9 -5
  43. package/components/ui/breadcrumb.tsx +13 -5
  44. package/components/ui/{extension-list-card.tsx → capability-list-card.tsx} +13 -5
  45. package/components/ui/checkbox.tsx +6 -3
  46. package/components/ui/collapsible-section.tsx +38 -29
  47. package/components/ui/confirm-badge.tsx +7 -4
  48. package/components/ui/cookie-consent.tsx +13 -7
  49. package/components/ui/detail-section.tsx +24 -16
  50. package/components/ui/detail-view-wrapper.tsx +30 -22
  51. package/components/ui/editor-placeholder-card.tsx +28 -24
  52. package/components/ui/editor-toolbar.tsx +7 -4
  53. package/components/ui/execution-details-panel.tsx +10 -5
  54. package/components/ui/file-structure-section.tsx +7 -4
  55. package/components/ui/file-tree.tsx +3 -1
  56. package/components/ui/files-panel.tsx +147 -27
  57. package/components/ui/filter-dropdown.tsx +84 -74
  58. package/components/ui/form-actions.tsx +14 -6
  59. package/components/ui/frontmatter-form-header.tsx +10 -2
  60. package/components/ui/icon-button.tsx +22 -9
  61. package/components/ui/input.tsx +7 -4
  62. package/components/ui/label.tsx +5 -5
  63. package/components/ui/layout-tab-bar.tsx +7 -5
  64. package/components/ui/modal.tsx +18 -4
  65. package/components/ui/nav-card.tsx +6 -3
  66. package/components/ui/navigation-bar.tsx +164 -82
  67. package/components/ui/number-input.tsx +8 -4
  68. package/components/ui/project-explorer.tsx +666 -0
  69. package/components/ui/registry-browser.tsx +12 -1
  70. package/components/ui/registry-card.tsx +49 -42
  71. package/components/ui/registry-detail.tsx +40 -17
  72. package/components/ui/resizable-textarea.tsx +18 -11
  73. package/components/ui/scope-badge.tsx +18 -11
  74. package/components/ui/segmented-toggle.tsx +5 -2
  75. package/components/ui/select.tsx +12 -9
  76. package/components/ui/selection-grid.tsx +36 -37
  77. package/components/ui/setting-row.tsx +2 -2
  78. package/components/ui/settings-card.tsx +10 -3
  79. package/components/ui/settings-info-box.tsx +9 -5
  80. package/components/ui/settings-section-title.tsx +14 -2
  81. package/components/ui/snapshot-card.tsx +10 -2
  82. package/components/ui/snippets-panel.tsx +4 -2
  83. package/components/ui/sort-dropdown.tsx +39 -29
  84. package/components/ui/status-card.tsx +9 -1
  85. package/components/ui/tab-bar.tsx +12 -9
  86. package/components/ui/toggle.tsx +13 -7
  87. package/components/ui/tooltip.tsx +9 -1
  88. package/dist/content.js +8 -8
  89. package/dist/diagrams.d.ts +0 -1
  90. package/dist/index.d.ts +427 -184
  91. package/dist/index.js +3098 -1761
  92. package/dist/tokens/primitives.css +28 -6
  93. package/dist/tokens/semantic.css +15 -15
  94. package/dist/tokens/theme.css +23 -0
  95. package/index.ts +25 -11
  96. package/package.json +1 -1
  97. package/tokens/primitives.css +28 -6
  98. package/tokens/semantic.css +15 -15
  99. package/tokens/theme.css +23 -0
  100. package/components/sections/ai-tools-paths/index.ts +0 -37
  101. package/components/sections/ai-tools-paths/use-tools-paths.ts +0 -159
package/ai-manifest.json CHANGED
@@ -51,28 +51,28 @@
51
51
  "form": [
52
52
  { "name": "Input", "description": "Text input with search mode, action slot, error state", "replaces": "input", "keyProps": "value, onChange, type?: text|search, variant?: filled|ghost, size?: sm|md, error?, mono?, actionSlot?", "file": "components/ui/input.tsx" },
53
53
  { "name": "NumberInput", "description": "Numeric input with increment/decrement buttons", "replaces": "input[type=number]", "keyProps": "value, onChange, min?, max?, step?, size?: sm|md", "file": "components/ui/number-input.tsx" },
54
- { "name": "Select", "description": "Portal dropdown with keyboard nav and check indicators", "replaces": "select", "keyProps": "value, onChange, options: SelectOption[], color?: FormColor, size?: sm|md, variant?: filled|ghost", "file": "components/ui/select.tsx" },
54
+ { "name": "Select", "description": "Portal dropdown with keyboard nav and check indicators", "replaces": "select", "keyProps": "value, onChange, options: SelectOption[], accentColor?: FormColor, size?: sm|md, variant?: filled|ghost", "file": "components/ui/select.tsx" },
55
55
  { "name": "FilterDropdown", "description": "Clearable single-select filter with 'All' default and optional search", "keyProps": "value, onChange, options, allLabel?, searchable?", "file": "components/ui/filter-dropdown.tsx" },
56
56
  { "name": "SortDropdown", "description": "Field picker with direction toggle arrow", "keyProps": "field, ascending, fields: SortField[], onFieldChange, onToggleDirection", "file": "components/ui/sort-dropdown.tsx" },
57
- { "name": "Toggle", "description": "iOS-style boolean switch", "replaces": "input[type=checkbox] (for on/off settings)", "keyProps": "checked, onChange, color?: FormColor, size?: sm|md|lg", "file": "components/ui/toggle.tsx" },
58
- { "name": "Checkbox", "description": "Check-icon boolean for multi-select lists", "replaces": "input[type=checkbox] (for checklists)", "keyProps": "checked, onChange, color?: FormColor, size?: sm|md|lg", "file": "components/ui/checkbox.tsx" },
59
- { "name": "SegmentedToggle", "description": "Horizontal icon-based mutually-exclusive toggle group", "keyProps": "options: SegmentedToggleOption[], value, onChange, color?: FormColor", "file": "components/ui/segmented-toggle.tsx" },
57
+ { "name": "Toggle", "description": "iOS-style boolean switch", "replaces": "input[type=checkbox] (for on/off settings)", "keyProps": "checked, onChange, accentColor?: FormColor, size?: sm|md|lg", "file": "components/ui/toggle.tsx" },
58
+ { "name": "Checkbox", "description": "Check-icon boolean for multi-select lists", "replaces": "input[type=checkbox] (for checklists)", "keyProps": "checked, onChange, accentColor?: FormColor, size?: sm|md|lg", "file": "components/ui/checkbox.tsx" },
59
+ { "name": "SegmentedToggle", "description": "Horizontal icon-based mutually-exclusive toggle group", "keyProps": "options: SegmentedToggleOption[], value, onChange, accentColor?: FormColor", "file": "components/ui/segmented-toggle.tsx" },
60
60
  { "name": "ResizableTextarea", "description": "Textarea with drag-to-resize handle", "replaces": "textarea", "keyProps": "value, onChange, variant?: filled|ghost, minHeight?, maxHeight?", "file": "components/ui/resizable-textarea.tsx" },
61
61
  { "name": "FormActions", "description": "Flex row for form buttons with optional nav slot", "keyProps": "padding?: compact|normal|modal, children", "file": "components/ui/form-actions.tsx" },
62
62
  { "name": "SelectionGrid", "description": "Grid of selectable cards with icons and descriptions", "keyProps": "items: SelectionCardItem[], selected, onSelect", "file": "components/ui/selection-grid.tsx" }
63
63
  ],
64
64
 
65
65
  "action": [
66
- { "name": "IconButton", "description": "Icon-only button with tooltip, badge, status indicator, href mode", "replaces": "button", "keyProps": "icon: IconName|ReactNode, tooltip: TooltipContent, color?: FormColor, size?: xss|xs|sm|lg, status?, badge?, href?, strikethrough?, disabled?", "file": "components/ui/icon-button.tsx" },
66
+ { "name": "IconButton", "description": "Icon-only button with tooltip, badge, status indicator, href mode", "replaces": "button", "keyProps": "icon: IconName|ReactNode, tooltip: TooltipContent, accentColor?: FormColor, size?: xss|xs|sm|lg, status?, badge?, href?, strikethrough?, disabled?", "file": "components/ui/icon-button.tsx" },
67
67
  { "name": "CollapseButton", "description": "Animated chevron toggle button for expand/collapse", "keyProps": "isOpen, onToggle, tooltip: TooltipContent", "file": "components/ui/icon-button.tsx" },
68
68
  { "name": "AiActionButton", "description": "Button with AI loading/success/error states for async AI operations", "keyProps": "icon, tooltip, status: AiActionStatus, onClick, completionResult?", "file": "components/ui/ai-action-button.tsx" },
69
69
  { "name": "AiExecutionActionButtons", "description": "Run/stop/retry button group for AI execution workflows", "keyProps": "status: ExecutionStatus, onRun, onStop, onRetry", "file": "components/ui/ai-execution-action-buttons.tsx" },
70
- { "name": "ConfirmBadge", "description": "Badge that requires click-confirmation before triggering action", "keyProps": "label, onConfirm, color?: ConfirmBadgeColor", "file": "components/ui/confirm-badge.tsx" }
70
+ { "name": "ConfirmBadge", "description": "Badge that requires click-confirmation before triggering action", "keyProps": "label, onConfirm, accentColor?: ConfirmBadgeColor", "file": "components/ui/confirm-badge.tsx" }
71
71
  ],
72
72
 
73
73
  "display": [
74
- { "name": "Label", "description": "Border-focused colored badge/tag with icon and tooltip", "keyProps": "text, color: LabelColor, icon?, tooltip?: TooltipContent, size?: xs|sm|md", "file": "components/ui/label.tsx" },
75
- { "name": "Badge", "description": "Minimal inline badge for counts or short labels", "keyProps": "text, color?: BadgeColor", "file": "components/ui/badge.tsx" },
74
+ { "name": "Label", "description": "Border-focused colored badge/tag with icon and tooltip", "keyProps": "text, accentColor: LabelColor, icon?, tooltip?: TooltipContent, size?: xs|sm|md", "file": "components/ui/label.tsx" },
75
+ { "name": "Badge", "description": "Minimal inline badge for counts or short labels", "keyProps": "text, accentColor?: BadgeColor", "file": "components/ui/badge.tsx" },
76
76
  { "name": "ScopeBadge", "description": "Pre-configured Label for user/project/local/read-only scopes", "keyProps": "scope: ScopeType", "file": "components/ui/scope-badge.tsx" },
77
77
  { "name": "Tooltip", "description": "Portal-based tooltip with auto-positioning and arrow", "keyProps": "content: TooltipContent, position?: top|bottom|left|right|auto, children", "file": "components/ui/tooltip.tsx" },
78
78
  { "name": "TooltipButton", "description": "Icon button that toggles a persistent tooltip on click", "keyProps": "content: TooltipContent, icon?: IconName", "file": "components/ui/tooltip.tsx" },
@@ -89,7 +89,9 @@
89
89
  { "name": "EditorPlaceholderCard", "description": "Centered placeholder card shown when no editor content is active", "keyProps": "icon, title, description", "file": "components/ui/editor-placeholder-card.tsx" },
90
90
  { "name": "FrontmatterFormHeader", "description": "Form header for YAML frontmatter editing with field labels", "keyProps": "fields, onChange", "file": "components/ui/frontmatter-form-header.tsx" },
91
91
  { "name": "FilesPanel", "description": "File list panel with add/remove actions", "keyProps": "files: FileEntry[], onAdd?, onRemove?", "file": "components/ui/files-panel.tsx" },
92
- { "name": "SnippetsPanel", "description": "Panel displaying a list of text snippets with copy action", "keyProps": "snippets: Snippet[], onCopy?", "file": "components/ui/snippets-panel.tsx" }
92
+ { "name": "SnippetsPanel", "description": "Panel displaying a list of text snippets with copy action", "keyProps": "snippets: Snippet[], onCopy?", "file": "components/ui/snippets-panel.tsx" },
93
+ { "name": "ProjectExplorer", "description": "Resizable sidebar explorer with project tree, search, collapse, and top items", "keyProps": "tree: ExplorerNode[], selectedProjectId, onSelectProject, width, onWidthChange, collapsed, onToggleCollapsed, onAddProject, accentColor?: FormColor", "file": "components/ui/project-explorer.tsx" },
94
+ { "name": "AccentColorProvider", "description": "React context provider that sets accent color for all descendant ui-design components", "keyProps": "value: FormColor, children", "file": "components/lib/accent-context.ts" }
93
95
  ],
94
96
 
95
97
  "navigation": [
@@ -97,8 +99,8 @@
97
99
  { "name": "NavigationBar", "description": "Top navigation bar with title, back button, and actions", "keyProps": "title, onBack?, children", "file": "components/ui/navigation-bar.tsx" },
98
100
  { "name": "TabBar", "description": "Horizontal tab strip with optional badge counts", "keyProps": "tabs: Tab[], activeTab, onTabChange", "file": "components/ui/tab-bar.tsx" },
99
101
  { "name": "LayoutTabBar", "description": "Tab bar for switching layout views (e.g. split/full)", "keyProps": "tabs: LayoutTab[], activeTab, onTabChange", "file": "components/ui/layout-tab-bar.tsx" },
100
- { "name": "NavCard", "description": "Navigation card with icon, title, and description for app selection", "keyProps": "title, description, icon, onClick, color?", "file": "components/ui/nav-card.tsx" },
101
- { "name": "ExtensionListCard", "description": "Card showing extension info with type indicator and actions", "keyProps": "title, type, description, actions?", "file": "components/ui/extension-list-card.tsx" }
102
+ { "name": "NavCard", "description": "Navigation card with icon, title, and description for app selection", "keyProps": "title, description, icon, onClick, accentColor?", "file": "components/ui/nav-card.tsx" },
103
+ { "name": "CapabilityListCard", "description": "Card showing capability info with type indicator and actions", "keyProps": "title, type, description, actions?", "file": "components/ui/capability-list-card.tsx" }
102
104
  ],
103
105
 
104
106
  "modal": [
@@ -108,19 +110,28 @@
108
110
  ],
109
111
 
110
112
  "section": [
111
- { "name": "TabbedPromptEditor", "description": "Multi-tab prompt editor with variable insertion and dirty detection. Use with usePromptEditor() hook", "keyProps": "...usePromptEditor(), standalone?, className?", "hook": "usePromptEditor", "file": "components/sections/prompt-editor/index.ts" },
112
- { "name": "FileTypeTabbedPromptEditor", "description": "Prompt editor variant with file type tabs", "keyProps": "...usePromptEditor(), fileTypes: FileTypeOption[]", "hook": "usePromptEditor", "file": "components/sections/prompt-editor/index.ts" },
113
- { "name": "SimulatorPromptEditor", "description": "Prompt editor with scenario selector for testing prompts", "keyProps": "...usePromptEditor(), scenarios: ScenarioOption[]", "file": "components/sections/prompt-editor/index.ts" },
113
+ { "name": "TabbedPromptEditor", "description": "Multi-tab prompt editor with variable insertion and dirty detection", "keyProps": "prompts: Record<string, string>, onPromptChange, tools: ToolTab[], defaultPrompts?, variables?: PromptPlaceholder[], standalone?, accentColor?", "file": "components/sections/prompt-editor/index.ts" },
114
+ { "name": "FileTypeTabbedPromptEditor", "description": "Prompt editor variant with file type sidebar", "keyProps": "prompts: Record<string, Record<string, string>>, onPromptChange, fileTypes: FileTypeOption[], tools: ToolTab[], defaultPrompts?, variables?", "file": "components/sections/prompt-editor/index.ts" },
115
+ { "name": "SimulatorPromptEditor", "description": "Prompt editor with hierarchical scenario/step sidebar", "keyProps": "prompts: Record<string, Record<string, Record<string, string>>>, onPromptChange, scenarios: ScenarioOption[], tools: ToolTab[], defaultPrompts?, variables?", "file": "components/sections/prompt-editor/index.ts" },
114
116
  { "name": "RegistryBrowser", "description": "Browsable grid of registry items with search, filter, sort", "keyProps": "items, onSelect, selectedId?", "file": "components/ui/registry-browser.tsx" },
115
117
  { "name": "RegistryDetail", "description": "Detail view for a single registry item with file structure", "keyProps": "item, onBack, onInstall?", "file": "components/ui/registry-detail.tsx" },
116
118
  { "name": "RegistryCard", "description": "Card displaying a registry item with type badge and metadata", "keyProps": "item, onClick?, selected?", "file": "components/ui/registry-card.tsx" },
117
119
  { "name": "GoldenSyncPanel", "description": "Golden snapshot sync panel with diff viewer. Use with useGoldenSync() hook", "keyProps": "...useGoldenSync()", "hook": "useGoldenSync", "file": "components/sections/golden-snapshots/index.ts" },
120
+ { "name": "StatusOverview", "description": "Status dashboard for golden sync with component-level version info", "keyProps": "status: GoldenStatus, components: string[], componentLabels?, devtools, manifest?", "file": "components/sections/golden-snapshots/status-overview.tsx" },
121
+ { "name": "FileDiffViewer", "description": "Side-by-side diff viewer for golden vs live file comparison", "keyProps": "sync: UseGoldenSyncReturn, componentLabels?, monacoTheme?, renderFileIcon?", "file": "components/sections/golden-snapshots/file-diff-viewer.tsx" },
122
+ { "name": "SnapshotManager", "description": "Create, restore, and delete golden snapshots", "keyProps": "sync: UseGoldenSyncReturn", "file": "components/sections/golden-snapshots/snapshot-manager.tsx" },
123
+ { "name": "VersionManager", "description": "Manage component versions with update and bump actions", "keyProps": "sync: UseGoldenSyncReturn, components: string[], componentLabels?", "file": "components/sections/golden-snapshots/version-manager.tsx" },
118
124
  { "name": "SnapshotBrowserPanel", "description": "Browse and manage snapshots. Use with useSnapshotBrowser() hook", "keyProps": "...useSnapshotBrowser()", "hook": "useSnapshotBrowser", "file": "components/sections/snapshot-browser/index.ts" },
125
+ { "name": "SnapshotTree", "description": "Hierarchical tree view for browsing snapshots by scope/category/item", "keyProps": "scopes: SnapshotScope[], searchQuery, onSearchChange, expandedPaths, onToggleExpand, onExpandAll, onCollapseAll, allExpanded", "file": "components/sections/snapshot-browser/snapshot-tree.tsx" },
119
126
  { "name": "SnippetsEditor", "description": "Create and edit text snippets. Use with useSnippetsEditor() hook", "keyProps": "...useSnippetsEditor()", "hook": "useSnippetsEditor", "file": "components/sections/snippets-editor/index.ts" },
120
127
  { "name": "ReportBugForm", "description": "Bug report form with screenshot capture. Use with useReportBug() hook", "keyProps": "...useReportBug()", "hook": "useReportBug", "file": "components/sections/report-bug/index.ts" },
121
128
  { "name": "ScreenshotUploader", "description": "Drag & drop multi-image upload with base64 encoding and preview thumbnails", "keyProps": "screenshots: Screenshot[], onChange, maxTotalSize?, disabled?", "file": "components/sections/report-bug/index.ts" },
122
- { "name": "ToolsPathsPanel", "description": "AI tool path configuration panel. Use with useToolsPaths() hook", "keyProps": "...useToolsPaths()", "hook": "useToolsPaths", "file": "components/sections/ai-tools-paths/index.ts" },
129
+ { "name": "AgentPathsPanel", "description": "Coding agent path configuration panel. Use with useAgentPaths() hook", "keyProps": "...useAgentPaths()", "hook": "useAgentPaths", "file": "components/sections/coding-agent-paths/index.ts" },
123
130
  { "name": "CapturedIssuesPanel", "description": "View and manage captured error issues. Use with useCapturedIssues() hook", "keyProps": "...useCapturedIssues()", "hook": "useCapturedIssues", "file": "components/sections/captured-issues/index.ts" },
131
+ { "name": "DashboardPanel", "description": "Dashboard shell with tabbed navigation, accent-colored tab header, and content area", "keyProps": "tabs: DashboardTab[], activeTab, onTabChange, children, headerRight?", "file": "components/composites/dashboard-panel.tsx" },
132
+ { "name": "DashboardFilterBar", "description": "Search and filter bar for dashboard panels with left search and right filter slots", "keyProps": "search: ReactNode, filters?: ReactNode", "file": "components/composites/dashboard-panel.tsx" },
133
+ { "name": "DashboardList", "description": "List container with dividers between children and configurable empty state", "keyProps": "children?, isEmpty?, emptyIcon?, emptyTitle?, emptyDescription?", "file": "components/composites/dashboard-panel.tsx" },
134
+ { "name": "DashboardListItem", "description": "Composable list item with git provider, title, status label, metadata, and action slots", "keyProps": "title, variant?: overview|project, gitProvider?, repository?, status?: DashboardItemStatus, metadata?, actions?", "file": "components/composites/dashboard-list-item.tsx" },
124
135
  { "name": "FileStructureSection", "description": "File tree with code preview, syntax highlighting, and copy", "keyProps": "files: FileTreeNode[], accentColor?: AccentColor", "file": "components/ui/file-structure-section.tsx" },
125
136
  { "name": "FileTree", "description": "Expandable file/folder tree with selection", "keyProps": "nodes: FileTreeNode[], selectedPath?, onSelect", "file": "components/ui/file-tree.tsx" },
126
137
  { "name": "ExecutionDetailsPanel", "description": "Panel showing execution result rows with expandable details", "keyProps": "rows: ExecutionDetailRow[]", "file": "components/ui/execution-details-panel.tsx" }
@@ -138,27 +149,31 @@
138
149
 
139
150
  "brand": [
140
151
  { "name": "ToolrAppLogo", "description": "App logo with icon and name for toolr suite apps", "keyProps": "appId: ToolrAppId, size?: sm|md|lg", "file": "components/lib/toolr-brand.tsx" },
141
- { "name": "AiToolIcon", "description": "Logo icon for AI tools (Claude, GPT, Gemini, etc.)", "keyProps": "tool: AiToolKey, size?: number", "file": "components/lib/ai-tools.tsx" },
152
+ { "name": "CodingAgentIcon", "description": "Logo icon for coding agents (Claude, Gemini, Copilot, etc.). Supports selected state with accent-colored border.", "keyProps": "agent: CodingAgentKey, size?: number, showName?: boolean, selected?: boolean, accentColor?: FormColor", "file": "components/lib/coding-agents.tsx" },
153
+ { "name": "GitProviderIcon", "description": "Icon for git hosting providers (GitHub, GitLab, Gerrit) with brand colors", "keyProps": "provider: GitProviderKey, size?: number, className?", "file": "components/lib/git-providers.tsx" },
154
+ { "name": "CustomIcon", "description": "SVG icon for brands not available in lucide-react (e.g. Gerrit)", "keyProps": "icon: CustomIconKey, size?: number, className?", "file": "components/lib/custom-icons.tsx" },
142
155
  { "name": "CookieConsent", "description": "Cookie consent banner with accept/reject", "keyProps": "onConsent: (choice: ConsentChoice) => void", "file": "components/ui/cookie-consent.tsx" }
143
156
  ]
144
157
  },
145
158
 
146
159
  "hooks": [
147
- { "name": "usePromptEditor", "description": "State manager for TabbedPromptEditor — tabs, dirty detection, save, variables", "file": "components/sections/prompt-editor/index.ts" },
148
160
  { "name": "useGoldenSync", "description": "State manager for GoldenSyncPanel — diff tree, sync status, file comparison", "file": "components/sections/golden-snapshots/index.ts" },
149
161
  { "name": "useSnapshotBrowser", "description": "State manager for SnapshotBrowserPanel — snapshot list, categories, actions", "file": "components/sections/snapshot-browser/index.ts" },
150
162
  { "name": "useSnippetsEditor", "description": "State manager for SnippetsEditor — CRUD operations on snippets", "file": "components/sections/snippets-editor/index.ts" },
151
163
  { "name": "useReportBug", "description": "State manager for ReportBugForm — issue types, screenshots, submission", "file": "components/sections/report-bug/index.ts" },
152
- { "name": "useToolsPaths", "description": "State manager for ToolsPathsPanelAI tool detection, path configuration", "file": "components/sections/ai-tools-paths/index.ts" },
164
+ { "name": "useAgentPaths", "description": "State manager for AgentPathsPanelcoding agent detection, path configuration", "file": "components/sections/coding-agent-paths/index.ts" },
153
165
  { "name": "useCapturedIssues", "description": "State manager for CapturedIssuesPanel — error list, submission, dismissal", "file": "components/sections/captured-issues/index.ts" },
154
166
  { "name": "useClickOutside", "description": "Close menus/dropdowns when clicking outside the ref element", "file": "components/hooks/use-click-outside.ts" },
155
167
  { "name": "useDropdownMaxHeight", "description": "Calculate max height for dropdowns to stay within viewport", "file": "components/hooks/use-dropdown-max-height.ts" },
156
- { "name": "useNavigationHistory", "description": "Browser-like back/forward navigation state", "file": "components/hooks/use-navigation-history.ts" }
168
+ { "name": "useModalBehavior", "description": "Escape key close, body overflow lock, and focus trap for modals", "file": "components/hooks/use-modal-behavior.ts" },
169
+ { "name": "useNavigationHistory", "description": "Browser-like back/forward navigation state", "file": "components/hooks/use-navigation-history.ts" },
170
+ { "name": "useResizableSidebar", "description": "Drag-to-resize sidebar with min/max constraints", "file": "components/hooks/use-resizable-sidebar.ts" }
157
171
  ],
158
172
 
159
173
  "utilities": [
174
+ { "name": "AccentColorProvider", "description": "React context provider that sets accent color for all descendant components. Children read via useAccentColor()", "usage": "<AccentColorProvider value={color}>...</AccentColorProvider>", "file": "components/lib/accent-context.ts" },
160
175
  { "name": "cn", "description": "clsx + tailwind-merge for conditional class composition", "usage": "cn('base-class', condition && 'conditional-class', className)", "file": "components/lib/cn.ts" },
161
- { "name": "FORM_COLORS", "description": "Color config map — FORM_COLORS[color].border/.hover/.focus/.selectedBg/.accent", "file": "components/lib/form-colors.ts" },
176
+ { "name": "FORM_COLORS", "description": "Color config map — FORM_COLORS[accentColor].border/.hover/.focus/.selectedBg/.accent", "file": "components/lib/form-colors.ts" },
162
177
  { "name": "applyTheme", "description": "Apply theme to document — applyTheme(themeId, accentHue)", "file": "components/lib/theme-engine.ts" },
163
178
  { "name": "ACCENT_DEFS", "description": "Array of { id, label, hue } for all available accent colors", "file": "components/lib/theme-engine.ts" },
164
179
  { "name": "iconMap", "description": "Map of icon name strings to lucide-react components", "file": "components/ui/icon-button.tsx" }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * DashboardListItem — A composable list item for dashboard views.
3
+ *
4
+ * Two variants:
5
+ * - 'overview': [GitProviderIcon] repo-name → title [status] → metadata row
6
+ * - 'project': title [status] → metadata row (no platform/repo info)
7
+ *
8
+ * All labels, icons, and controls use ui-design primitives.
9
+ */
10
+
11
+ import { type ReactNode } from 'react'
12
+ import { GitProviderIcon, GIT_PROVIDER_NAMES, type GitProviderKey } from '../lib/git-providers.tsx'
13
+ import { Label, type LabelColor } from '../ui/label.tsx'
14
+ import { Tooltip } from '../ui/tooltip.tsx'
15
+ import type { IconName } from '../ui/icon-button.tsx'
16
+ import { cn } from '../lib/cn.ts'
17
+
18
+ // ─── Types ───────────────────────────────────────────────────────────
19
+
20
+ export interface DashboardItemStatus {
21
+ text: string
22
+ color: LabelColor
23
+ icon?: IconName
24
+ tooltip?: { title?: string; description: string }
25
+ onClick?: () => void
26
+ }
27
+
28
+ export interface DashboardListItemProps {
29
+ /** 'overview' shows git provider + repo row, 'project' omits it */
30
+ variant?: 'overview' | 'project'
31
+
32
+ /** Git provider (overview variant only) */
33
+ gitProvider?: GitProviderKey
34
+ onGitProviderClick?: () => void
35
+
36
+ /** Repository name (overview variant only) */
37
+ repository?: string
38
+ /** Suffix appended to repo (e.g. " #123") */
39
+ repositorySuffix?: string
40
+ onRepositoryClick?: () => void
41
+
42
+ /** Main title */
43
+ title: string
44
+ onTitleClick?: () => void
45
+
46
+ /** Status label displayed inline with the title */
47
+ status?: DashboardItemStatus
48
+
49
+ /** Additional content after status label (extra labels, badges) */
50
+ extraLabels?: ReactNode
51
+
52
+ /** Metadata row content (branch, time, stats) */
53
+ metadata?: ReactNode
54
+
55
+ /** Right-side action buttons */
56
+ actions?: ReactNode
57
+
58
+ className?: string
59
+ }
60
+
61
+ // ─── Component ───────────────────────────────────────────────────────
62
+
63
+ export function DashboardListItem({
64
+ variant = 'overview',
65
+ gitProvider,
66
+ onGitProviderClick,
67
+ repository,
68
+ repositorySuffix,
69
+ onRepositoryClick,
70
+ title,
71
+ onTitleClick,
72
+ status,
73
+ extraLabels,
74
+ metadata,
75
+ actions,
76
+ className,
77
+ }: DashboardListItemProps) {
78
+ const showRepoRow = variant === 'overview' && gitProvider && repository
79
+
80
+ return (
81
+ <div className={cn('p-4 hover:bg-neutral-960/30 transition-colors', className)}>
82
+ <div className="flex items-start justify-between gap-4">
83
+ <div className="flex-1 min-w-0">
84
+ {/* Row 1 (overview only): Git provider icon + repository name */}
85
+ {showRepoRow && (
86
+ <div className="flex items-center gap-2 mb-1">
87
+ <Tooltip
88
+ content={{
89
+ title: GIT_PROVIDER_NAMES[gitProvider],
90
+ description: `Filter by ${GIT_PROVIDER_NAMES[gitProvider]}`,
91
+ }}
92
+ position="top"
93
+ align="center"
94
+ >
95
+ {onGitProviderClick ? (
96
+ // toolr-design-ignore-next-line -- composite wraps GitProviderIcon in clickable span
97
+ <button
98
+ type="button"
99
+ onClick={onGitProviderClick}
100
+ className="flex items-center cursor-pointer transition-colors hover:opacity-80"
101
+ >
102
+ <GitProviderIcon provider={gitProvider} size={16} />
103
+ </button>
104
+ ) : (
105
+ <span className="flex items-center">
106
+ <GitProviderIcon provider={gitProvider} size={16} />
107
+ </span>
108
+ )}
109
+ </Tooltip>
110
+
111
+ {onRepositoryClick ? (
112
+ // toolr-design-ignore-next-line -- composite repo text is intentionally not a Label
113
+ <button
114
+ type="button"
115
+ onClick={onRepositoryClick}
116
+ className="text-sm font-medium text-neutral-300 hover:text-white transition-colors cursor-pointer truncate"
117
+ >
118
+ {repository}
119
+ {repositorySuffix}
120
+ </button>
121
+ ) : (
122
+ <span className="text-sm font-medium text-neutral-400 truncate">
123
+ {repository}
124
+ {repositorySuffix}
125
+ </span>
126
+ )}
127
+ </div>
128
+ )}
129
+
130
+ {/* Row 2: Title + status label */}
131
+ <div className="flex items-center gap-2 mb-1 flex-wrap">
132
+ <h3
133
+ className={cn(
134
+ 'font-medium truncate text-white',
135
+ onTitleClick && 'cursor-pointer hover:text-blue-300 transition-colors',
136
+ )}
137
+ title={title}
138
+ onClick={onTitleClick}
139
+ >
140
+ {title}
141
+ </h3>
142
+ {status && (
143
+ <Label
144
+ text={status.text}
145
+ accentColor={status.color}
146
+ icon={status.icon}
147
+ size="lg"
148
+ onClick={status.onClick}
149
+ tooltip={status.tooltip ?? { description: status.text }}
150
+ />
151
+ )}
152
+ {extraLabels}
153
+ </div>
154
+
155
+ {/* Row 3: Metadata */}
156
+ {metadata && (
157
+ <div className="flex items-center gap-3 text-sm text-neutral-500 flex-wrap">
158
+ {metadata}
159
+ </div>
160
+ )}
161
+ </div>
162
+
163
+ {/* Right-side action buttons */}
164
+ {actions && (
165
+ <div className="flex items-center gap-2 flex-shrink-0">
166
+ {actions}
167
+ </div>
168
+ )}
169
+ </div>
170
+ </div>
171
+ )
172
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * DashboardPanel — Full dashboard shell with tabbed navigation, filter bar, and list.
3
+ *
4
+ * Provides the structural card with:
5
+ * - Configurable tab header (icon + label + subtitle per tab, with accent color)
6
+ * - DashboardFilterBar for search + filter controls
7
+ * - DashboardList for items with dividers and empty state
8
+ *
9
+ * Consumer provides all content through slots and children.
10
+ */
11
+
12
+ import { type ReactNode } from 'react'
13
+ import { type AccentColor } from '../lib/form-colors.ts'
14
+ import { Tooltip } from '../ui/tooltip.tsx'
15
+ import { cn } from '../lib/cn.ts'
16
+
17
+ // ─── Color maps for tab active states ────────────────────────────────
18
+ // Stronger intensity than ACCENT_NAV (500/20 bg, 300 text, 500/30 icon box)
19
+
20
+ const TAB_ACTIVE_BG: Record<AccentColor, string> = {
21
+ blue: 'bg-blue-500/20', green: 'bg-green-500/20', red: 'bg-red-500/20',
22
+ orange: 'bg-orange-500/20', cyan: 'bg-cyan-500/20', yellow: 'bg-yellow-500/20',
23
+ purple: 'bg-purple-500/20', indigo: 'bg-indigo-500/20', emerald: 'bg-emerald-500/20',
24
+ amber: 'bg-amber-500/20', violet: 'bg-violet-500/20', neutral: 'bg-neutral-500/20',
25
+ sky: 'bg-sky-500/20', pink: 'bg-pink-500/20', teal: 'bg-teal-500/20',
26
+ }
27
+
28
+ const TAB_ACTIVE_TEXT: Record<AccentColor, string> = {
29
+ blue: 'text-blue-300', green: 'text-green-300', red: 'text-red-300',
30
+ orange: 'text-orange-300', cyan: 'text-cyan-300', yellow: 'text-yellow-300',
31
+ purple: 'text-purple-300', indigo: 'text-indigo-300', emerald: 'text-emerald-300',
32
+ amber: 'text-amber-300', violet: 'text-violet-300', neutral: 'text-neutral-300',
33
+ sky: 'text-sky-300', pink: 'text-pink-300', teal: 'text-teal-300',
34
+ }
35
+
36
+ const TAB_ACTIVE_ICON_BOX: Record<AccentColor, string> = {
37
+ blue: 'bg-blue-500/30', green: 'bg-green-500/30', red: 'bg-red-500/30',
38
+ orange: 'bg-orange-500/30', cyan: 'bg-cyan-500/30', yellow: 'bg-yellow-500/30',
39
+ purple: 'bg-purple-500/30', indigo: 'bg-indigo-500/30', emerald: 'bg-emerald-500/30',
40
+ amber: 'bg-amber-500/30', violet: 'bg-violet-500/30', neutral: 'bg-neutral-500/30',
41
+ sky: 'bg-sky-500/30', pink: 'bg-pink-500/30', teal: 'bg-teal-500/30',
42
+ }
43
+
44
+ const TAB_ACTIVE_SUBTITLE: Record<AccentColor, string> = {
45
+ blue: 'text-blue-400/70', green: 'text-green-400/70', red: 'text-red-400/70',
46
+ orange: 'text-orange-400/70', cyan: 'text-cyan-400/70', yellow: 'text-yellow-400/70',
47
+ purple: 'text-purple-400/70', indigo: 'text-indigo-400/70', emerald: 'text-emerald-400/70',
48
+ amber: 'text-amber-400/70', violet: 'text-violet-400/70', neutral: 'text-neutral-400/70',
49
+ sky: 'text-sky-400/70', pink: 'text-pink-400/70', teal: 'text-teal-400/70',
50
+ }
51
+
52
+ // ─── Types ───────────────────────────────────────────────────────────
53
+
54
+ export interface DashboardTab {
55
+ id: string
56
+ label: string
57
+ subtitle: string
58
+ icon: ReactNode
59
+ color: AccentColor
60
+ tooltip?: { title: string; description: string }
61
+ }
62
+
63
+ export interface DashboardPanelProps {
64
+ tabs: DashboardTab[]
65
+ activeTab: string
66
+ onTabChange: (tabId: string) => void
67
+ children: ReactNode
68
+ className?: string
69
+ /** Content rendered to the right of the tabs, vertically centered */
70
+ headerRight?: ReactNode
71
+ }
72
+
73
+ export interface DashboardFilterBarProps {
74
+ /** Left-side search (typically an Input component) */
75
+ search: ReactNode
76
+ /** Right-side filters and action buttons */
77
+ filters?: ReactNode
78
+ }
79
+
80
+ export interface DashboardListProps {
81
+ children?: ReactNode
82
+ /** When true, renders the empty state instead of children */
83
+ isEmpty?: boolean
84
+ /** Icon shown in the empty state */
85
+ emptyIcon?: ReactNode
86
+ /** Primary empty state text */
87
+ emptyTitle?: string
88
+ /** Secondary empty state text */
89
+ emptyDescription?: string
90
+ }
91
+
92
+ // ─── DashboardPanel ──────────────────────────────────────────────────
93
+
94
+ export function DashboardPanel({
95
+ tabs,
96
+ activeTab,
97
+ onTabChange,
98
+ children,
99
+ className,
100
+ headerRight,
101
+ }: DashboardPanelProps) {
102
+ return (
103
+ <div className={cn('bg-neutral-960/50 border border-neutral-700/50 rounded-xl overflow-hidden', className)}>
104
+ {/* Tab Header */}
105
+ <div className="bg-neutral-980/80 flex h-[60px]">
106
+ <div className={cn('flex', headerRight ? '' : 'flex-1')}>
107
+ {tabs.map((tab) => {
108
+ const isActive = activeTab === tab.id
109
+
110
+ const tabButton = (
111
+ // toolr-design-ignore-next-line -- dashboard tab button has custom styling
112
+ <button
113
+ key={tab.id}
114
+ type="button"
115
+ onClick={() => onTabChange(tab.id)}
116
+ className={cn(
117
+ 'h-full transition-all cursor-pointer',
118
+ headerRight ? '' : 'flex-1',
119
+ isActive
120
+ ? `${TAB_ACTIVE_BG[tab.color]} ${TAB_ACTIVE_TEXT[tab.color]}`
121
+ : 'text-neutral-400 hover:text-neutral-200 hover:bg-neutral-960/70',
122
+ )}
123
+ >
124
+ <div className="flex items-center gap-3 px-4 h-full">
125
+ {/* toolr-design-ignore-next-line -- icon box with accent background */}
126
+ <div
127
+ className={cn(
128
+ 'w-10 h-10 rounded-lg flex items-center justify-center flex-shrink-0',
129
+ isActive ? TAB_ACTIVE_ICON_BOX[tab.color] : 'bg-neutral-960',
130
+ )}
131
+ >
132
+ {tab.icon}
133
+ </div>
134
+ <div className="flex flex-col items-start">
135
+ <span className="text-md font-semibold">{tab.label}</span>
136
+ <span
137
+ className={cn(
138
+ 'text-sm font-medium',
139
+ isActive ? TAB_ACTIVE_SUBTITLE[tab.color] : 'text-neutral-500',
140
+ )}
141
+ >
142
+ {tab.subtitle}
143
+ </span>
144
+ </div>
145
+ </div>
146
+ </button>
147
+ )
148
+
149
+ if (tab.tooltip) {
150
+ return (
151
+ <Tooltip
152
+ key={tab.id}
153
+ content={{ title: tab.tooltip.title, description: tab.tooltip.description }}
154
+ position="bottom"
155
+ align="center"
156
+ >
157
+ {tabButton}
158
+ </Tooltip>
159
+ )
160
+ }
161
+ return tabButton
162
+ })}
163
+ </div>
164
+ {headerRight && (
165
+ <div className="flex items-center px-4 ml-auto flex-shrink-0">
166
+ {headerRight}
167
+ </div>
168
+ )}
169
+ </div>
170
+
171
+ {/* Active tab content */}
172
+ {children}
173
+ </div>
174
+ )
175
+ }
176
+
177
+ // ─── DashboardFilterBar ──────────────────────────────────────────────
178
+
179
+ export function DashboardFilterBar({ search, filters }: DashboardFilterBarProps) {
180
+ return (
181
+ <div className="px-4 py-3 border-t border-neutral-700/50 flex items-center justify-between gap-3 flex-wrap">
182
+ <div className="flex-shrink-0 w-44">
183
+ {search}
184
+ </div>
185
+ {filters && (
186
+ <div className="flex items-center gap-2 flex-shrink-0 ml-auto">
187
+ {filters}
188
+ </div>
189
+ )}
190
+ </div>
191
+ )
192
+ }
193
+
194
+ // ─── DashboardList ───────────────────────────────────────────────────
195
+
196
+ export function DashboardList({
197
+ children,
198
+ isEmpty,
199
+ emptyIcon,
200
+ emptyTitle,
201
+ emptyDescription,
202
+ }: DashboardListProps) {
203
+ if (isEmpty) {
204
+ return (
205
+ <div className="p-8 text-center">
206
+ {emptyIcon && <div className="flex justify-center mb-2 text-neutral-600">{emptyIcon}</div>}
207
+ {emptyTitle && <p className="text-md text-neutral-500">{emptyTitle}</p>}
208
+ {emptyDescription && <p className="text-sm text-neutral-600 mt-1">{emptyDescription}</p>}
209
+ </div>
210
+ )
211
+ }
212
+
213
+ return (
214
+ <div className="divide-y divide-neutral-700/50">
215
+ {children}
216
+ </div>
217
+ )
218
+ }
@@ -38,10 +38,10 @@ export function DLRow({ term, children, even }: { term: ReactNode; children: Rea
38
38
  const bg = even ? 'bg-white/[0.015]' : ''
39
39
  return (
40
40
  <>
41
- <div className={`py-2 border-b border-neutral-800/60 ${bg} font-semibold text-md whitespace-nowrap`}>
41
+ <div className={`py-2 border-b border-neutral-960/60 ${bg} font-semibold text-md whitespace-nowrap`}>
42
42
  {term}
43
43
  </div>
44
- <div className={`py-2 border-b border-neutral-800/60 ${bg} text-md text-neutral-400`}>{children}</div>
44
+ <div className={`py-2 border-b border-neutral-960/60 ${bg} text-md text-neutral-400`}>{children}</div>
45
45
  </>
46
46
  )
47
47
  }
@@ -114,7 +114,7 @@ export function Callout({ color, children }: { color: string; children: ReactNod
114
114
  export function CalloutCode({ color, children }: { color: string; children: ReactNode }) {
115
115
  const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
116
116
  return (
117
- <code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-md ${c.codeText}`}>
117
+ <code className={`block bg-neutral-960/80 px-2 py-1 rounded mt-1.5 text-md ${c.codeText}`}>
118
118
  {children}
119
119
  </code>
120
120
  )
@@ -128,7 +128,7 @@ export function CalloutDim({ children }: { children: ReactNode }) {
128
128
 
129
129
  export function CodeBlock({ children }: { children: ReactNode }) {
130
130
  return (
131
- <div className="bg-neutral-900/60 rounded-md p-3 font-mono text-sm text-neutral-400 mb-5 whitespace-pre overflow-x-auto leading-normal">{children}</div>
131
+ <div className="bg-neutral-980/60 rounded-md p-3 font-mono text-sm text-neutral-400 mb-5 whitespace-pre overflow-x-auto leading-normal">{children}</div>
132
132
  )
133
133
  }
134
134
 
@@ -136,8 +136,9 @@ export function CodeBlock({ children }: { children: ReactNode }) {
136
136
 
137
137
  export function CK({ color, children }: { color?: string; children: ReactNode }) {
138
138
  const textColor = color ? `text-${color}-400` : ''
139
+ // text-[0.9em]: relative sizing for inline code — scales proportionally to surrounding prose font size
139
140
  return (
140
- <code className={`bg-neutral-800/80 px-1.5 py-px rounded text-[0.9em] ${textColor}`}>{children}</code>
141
+ <code className={`bg-neutral-960/80 px-1.5 py-px rounded text-[0.9em] ${textColor}`}>{children}</code>
141
142
  )
142
143
  }
143
144
 
@@ -175,13 +176,13 @@ export function LocationItem({
175
176
  const bg = even ? 'bg-white/[0.015]' : ''
176
177
  return (
177
178
  <>
178
- <div className={`py-2 border-b border-neutral-800/60 ${bg} flex items-center gap-1.5`}>
179
+ <div className={`py-2 border-b border-neutral-960/60 ${bg} flex items-center gap-1.5`}>
179
180
  <span
180
181
  className={`w-2 h-2 rounded-full bg-${color}-500/50 border border-${color}-500 shrink-0`}
181
182
  />
182
183
  <span className={`text-${color}-400 text-md font-semibold`}>{label}</span>
183
184
  </div>
184
- <div className={`py-2 border-b border-neutral-800/60 ${bg} text-md text-neutral-400`}>{children}</div>
185
+ <div className={`py-2 border-b border-neutral-960/60 ${bg} text-md text-neutral-400`}>{children}</div>
185
186
  </>
186
187
  )
187
188
  }
@@ -204,7 +205,7 @@ export function TitledLI({ color, title, children }: { color: string; title: str
204
205
 
205
206
  export function CalloutDialog({ color, lines }: { color: string; lines: { speaker: string; text: string }[] }) {
206
207
  return (
207
- <div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-md">
208
+ <div className="bg-neutral-960/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-md">
208
209
  {lines.map((line, idx) => (
209
210
  <div key={idx}>
210
211
  <span className={`text-${color}-300 font-semibold mr-1`}>{line.speaker}:</span>
@@ -81,7 +81,8 @@ export const stroke = {
81
81
  hairline: 0.5,
82
82
  } as const
83
83
 
84
- /** Semantic text colors. */
84
+ // SVG elements require raw hex — Tailwind classes and CSS vars are not available in SVG attributes.
85
+ // Maps to: neutral-200, neutral-400, neutral-500, neutral-960, neutral-970, neutral-700
85
86
  export const color = {
86
87
  textBright: '#e5e7eb',
87
88
  textMedium: '#9ca3af',