@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
@@ -3,6 +3,8 @@ import { useState, useEffect } from 'react'
3
3
  import { RefreshCw, AlertCircle, Check, Activity, GitCompareArrows, Archive, Tag } from 'lucide-react'
4
4
  import { IconButton } from '../../ui/icon-button.tsx'
5
5
  import { ConfirmModal } from '../../ui/modal.tsx'
6
+ import { useAccentColor, AccentColorProvider } from '../../lib/accent-context.ts'
7
+ import type { FormColor } from '../../lib/form-colors.ts'
6
8
  import type { GoldenSnapshotsApi } from './types.ts'
7
9
  import { useGoldenSync, type UseGoldenSyncReturn } from './use-golden-sync.ts'
8
10
  import { StatusOverview } from './status-overview.tsx'
@@ -20,6 +22,7 @@ export interface GoldenSyncPanelProps {
20
22
  monacoTheme?: string
21
23
  renderFileIcon?: (filename: string, component: string) => ReactNode
22
24
  onTabChange?: (tab: TabId) => void
25
+ accentColor?: FormColor
23
26
  }
24
27
 
25
28
  export function GoldenSyncPanel({
@@ -30,7 +33,10 @@ export function GoldenSyncPanel({
30
33
  monacoTheme,
31
34
  renderFileIcon,
32
35
  onTabChange,
36
+ accentColor,
33
37
  }: GoldenSyncPanelProps) {
38
+ const contextAccent = useAccentColor()
39
+ const effectiveColor = accentColor ?? contextAccent ?? 'blue'
34
40
  const sync = useGoldenSync({ api, devtools })
35
41
  const [activeTab, setActiveTab] = useState<TabId>('status')
36
42
 
@@ -110,6 +116,7 @@ export function GoldenSyncPanel({
110
116
  const visibleTabs = tabs.filter((t) => !t.devtoolsOnly || devtools)
111
117
 
112
118
  return (
119
+ <AccentColorProvider value={effectiveColor}>
113
120
  <div className={`flex-1 flex flex-col ${activeTab === 'diff' ? 'overflow-hidden' : 'overflow-y-auto'}`}>
114
121
  {/* Header */}
115
122
  <div className="flex-shrink-0">
@@ -126,7 +133,7 @@ export function GoldenSyncPanel({
126
133
  icon={<RefreshCw className={isLoading ? 'animate-spin' : ''} />}
127
134
  onClick={handleRefresh}
128
135
  disabled={isLoading}
129
- color="neutral"
136
+ accentColor="neutral"
130
137
  size="sm"
131
138
  tooltip={{ title: 'Reload', description: 'Refresh data' }}
132
139
  />
@@ -140,8 +147,8 @@ export function GoldenSyncPanel({
140
147
  onClick={() => handleTabChange(tab.id)}
141
148
  className={`h-[41px] flex items-center gap-2 px-4 text-md border-b-2 transition-colors cursor-pointer ${
142
149
  activeTab === tab.id
143
- ? `${tab.color} border-current bg-neutral-800/50`
144
- : 'border-transparent text-neutral-500 hover:text-neutral-300 hover:bg-neutral-800/30'
150
+ ? `${tab.color} border-current bg-neutral-960/50`
151
+ : 'border-transparent text-neutral-500 hover:text-neutral-300 hover:bg-neutral-960/30'
145
152
  }`}
146
153
  >
147
154
  {tab.icon}
@@ -174,6 +181,7 @@ export function GoldenSyncPanel({
174
181
  {/* Content */}
175
182
  <div className={activeTab === 'diff' ? 'flex-1 min-h-0 mt-4' : 'space-y-6 mt-4'}>
176
183
  {loading && activeTab === 'status' ? (
184
+ /* py-8: loading state needs extra vertical breathing room beyond the p-6 scale max */
177
185
  <div className="text-md text-neutral-500 text-center py-8">Loading...</div>
178
186
  ) : activeTab === 'status' ? (
179
187
  <StatusOverview
@@ -217,6 +225,7 @@ export function GoldenSyncPanel({
217
225
  isLoading={resettingAll}
218
226
  />
219
227
  </div>
228
+ </AccentColorProvider>
220
229
  )
221
230
  }
222
231
 
@@ -45,13 +45,14 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
45
45
  }
46
46
 
47
47
  if (manifestLoading && !manifest) {
48
+ // py-8: empty/loading states need extra vertical breathing room beyond the p-6 scale max
48
49
  return <div className="text-md text-neutral-500 text-center py-8">Loading snapshots...</div>
49
50
  }
50
51
 
51
52
  return (
52
53
  <div className="space-y-4">
53
54
  {/* Create Snapshot */}
54
- <div className="bg-neutral-900 rounded-lg p-4 border border-neutral-700">
55
+ <div className="bg-neutral-980 rounded-lg p-4 border border-neutral-700">
55
56
  <div className="flex items-center gap-3 mb-3">
56
57
  <Plus className="w-5 h-5 text-green-400" />
57
58
  <h4 className="text-md text-neutral-300 font-medium">Create Snapshot</h4>
@@ -74,14 +75,14 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
74
75
  onClick={onCreate}
75
76
  disabled={snapshotBusy}
76
77
  size="sm"
77
- color="green"
78
+ accentColor="cyan"
78
79
  tooltip={{ title: 'Create snapshot', description: 'Archive current live state' }}
79
80
  />
80
81
  </div>
81
82
  </div>
82
83
 
83
84
  {/* Snapshots List */}
84
- <div className="bg-neutral-900 rounded-lg border border-neutral-700 overflow-hidden">
85
+ <div className="bg-neutral-980 rounded-lg border border-neutral-700 overflow-hidden">
85
86
  <div className="flex items-center justify-between px-4 py-3 border-b border-neutral-700">
86
87
  <div className="flex items-center gap-2">
87
88
  <Archive className="w-4 h-4 text-neutral-500" />
@@ -93,12 +94,13 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
93
94
  onClick={loadManifest}
94
95
  disabled={manifestLoading}
95
96
  size="xs"
96
- color="neutral"
97
+ accentColor="orange"
97
98
  tooltip={{ title: 'Refresh', description: 'Reload snapshot list' }}
98
99
  />
99
100
  </div>
100
101
 
101
102
  {!manifest || manifest.snapshots.length === 0 ? (
103
+ /* py-8: empty state needs extra vertical breathing room beyond the p-6 scale max */
102
104
  <div className="text-md text-neutral-500 text-center py-8">No snapshots yet</div>
103
105
  ) : (
104
106
  <div className="divide-y divide-neutral-700">
@@ -140,7 +142,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
140
142
  onClick={() => handlePinSnapshot(snap.version, !snap.pinned)}
141
143
  disabled={snapshotBusy}
142
144
  size="xs"
143
- color={snap.pinned ? 'amber' : 'neutral'}
145
+ accentColor="neutral"
144
146
  tooltip={{
145
147
  title: snap.pinned ? 'Unpin' : 'Pin',
146
148
  description: snap.pinned ? 'Allow auto-pruning' : 'Protect from auto-pruning',
@@ -151,7 +153,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
151
153
  onClick={() => { setRestoreTarget(snap); setRestoreResetLive(true) }}
152
154
  disabled={snapshotBusy}
153
155
  size="xs"
154
- color="blue"
156
+ accentColor="orange"
155
157
  tooltip={{ title: 'Restore', description: 'Restore golden from this snapshot' }}
156
158
  />
157
159
  <IconButton
@@ -159,7 +161,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
159
161
  onClick={() => setDeleteTarget(snap)}
160
162
  disabled={snapshotBusy || snap.pinned}
161
163
  size="xs"
162
- color="red"
164
+ accentColor="red"
163
165
  tooltip={{
164
166
  title: 'Delete',
165
167
  description: snap.pinned ? 'Unpin first to delete' : 'Delete this snapshot',
@@ -81,7 +81,7 @@ export function StatusOverview({
81
81
  return (
82
82
  <div className="space-y-4">
83
83
  {/* Bundled Seed Info */}
84
- <div className="bg-neutral-900 rounded-lg p-4 border border-amber-500/30">
84
+ <div className="bg-neutral-980 rounded-lg p-4 border border-amber-500/30">
85
85
  <div className="flex items-center gap-3 mb-3">
86
86
  <Archive className="w-5 h-5 text-amber-400" />
87
87
  <h3 className="text-md text-neutral-300 font-medium">Bundled Seed (App Distribution)</h3>
@@ -118,7 +118,7 @@ export function StatusOverview({
118
118
  {/* Local Directories */}
119
119
  <div className="grid grid-cols-2 gap-4">
120
120
  {/* Golden */}
121
- <div className="bg-neutral-900 rounded-lg p-4 border border-blue-500/30">
121
+ <div className="bg-neutral-980 rounded-lg p-4 border border-blue-500/30">
122
122
  <div className="flex items-center gap-2 mb-3">
123
123
  <div className="w-3 h-3 rounded-full bg-blue-400" />
124
124
  <h4 className="text-md text-neutral-300 font-medium">Golden (Reference)</h4>
@@ -150,7 +150,7 @@ export function StatusOverview({
150
150
  </div>
151
151
 
152
152
  {/* Live */}
153
- <div className="bg-neutral-900 rounded-lg p-4 border border-green-500/30">
153
+ <div className="bg-neutral-980 rounded-lg p-4 border border-green-500/30">
154
154
  <div className="flex items-center gap-2 mb-3">
155
155
  <div className="w-3 h-3 rounded-full bg-green-400" />
156
156
  <h4 className="text-md text-neutral-300 font-medium">Live (Working Copy)</h4>
@@ -161,11 +161,11 @@ export function StatusOverview({
161
161
  onClick={() => setShowResetMenu((prev) => !prev)}
162
162
  disabled={anyResetting}
163
163
  size="xs"
164
- color="orange"
164
+ accentColor="orange"
165
165
  tooltip={{ title: 'Reset options', description: 'Reset live files to golden' }}
166
166
  />
167
167
  {showResetMenu && (
168
- <div ref={resetMenuDropdownRef} className="absolute right-0 top-full mt-1 w-56 bg-neutral-850 border border-neutral-700 rounded-lg shadow-lg z-50 py-1 overflow-hidden">
168
+ <div ref={resetMenuDropdownRef} className="absolute right-0 top-full mt-1 w-56 bg-neutral-970 border border-neutral-700 rounded-lg shadow-lg z-50 py-1 overflow-hidden">
169
169
  <button
170
170
  onClick={() => { onResetAll(); setShowResetMenu(false) }}
171
171
  className="w-full text-left px-3 py-2 text-md text-neutral-300 hover:bg-neutral-700 transition-colors"
@@ -203,7 +203,7 @@ export function StatusOverview({
203
203
  onClick={() => onResetComponent(comp)}
204
204
  disabled={anyResetting}
205
205
  size="xss"
206
- color="orange"
206
+ accentColor="orange"
207
207
  tooltip={{ title: `Reset ${getLabel(comp)}`, description: `Reset ${getLabel(comp).toLowerCase()} to golden version` }}
208
208
  />
209
209
  </span>
@@ -221,7 +221,7 @@ export function StatusOverview({
221
221
 
222
222
  {/* Update Flow — settings only */}
223
223
  {!devtools && (
224
- <div className="bg-neutral-900/50 border border-neutral-700 rounded-lg p-4">
224
+ <div className="bg-neutral-980/50 border border-neutral-700 rounded-lg p-4">
225
225
  <p className="text-sm font-medium text-neutral-400 mb-4">
226
226
  How updates work <span className="font-normal text-neutral-600">— checked per component ({components.map(getLabel).join(', ')})</span>
227
227
  </p>
@@ -287,7 +287,7 @@ export function StatusOverview({
287
287
 
288
288
  {/* Local Snapshots - devtools only */}
289
289
  {devtools && manifest && (
290
- <div className="bg-neutral-900 rounded-lg p-4 border border-neutral-700">
290
+ <div className="bg-neutral-980 rounded-lg p-4 border border-neutral-700">
291
291
  <div className="flex items-center gap-2 mb-3">
292
292
  <Archive className="w-4 h-4 text-neutral-500" />
293
293
  <h4 className="text-md text-neutral-300 font-medium">Local Snapshots</h4>
@@ -53,7 +53,7 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
53
53
  return (
54
54
  <div className="space-y-4">
55
55
  {/* Global Version Bump */}
56
- <div className="bg-neutral-900 rounded-lg p-4 border border-teal-500/30">
56
+ <div className="bg-neutral-980 rounded-lg p-4 border border-teal-500/30">
57
57
  <div className="flex items-center gap-3 mb-3">
58
58
  <Tag className="w-5 h-5 text-teal-400" />
59
59
  <h4 className="text-md text-neutral-300 font-medium">Golden Version</h4>
@@ -91,14 +91,14 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
91
91
  onClick={onBumpGlobal}
92
92
  disabled={bumpingGlobal || !globalVersion.trim()}
93
93
  size="sm"
94
- color="cyan"
94
+ accentColor="neutral"
95
95
  tooltip={{ title: 'Bump version', description: 'Update the golden version' }}
96
96
  />
97
97
  </div>
98
98
  </div>
99
99
 
100
100
  {/* Component Versions */}
101
- <div className="bg-neutral-900 rounded-lg border border-neutral-700 overflow-hidden">
101
+ <div className="bg-neutral-980 rounded-lg border border-neutral-700 overflow-hidden">
102
102
  <div className="px-4 py-3 border-b border-neutral-700">
103
103
  <h4 className="text-md text-neutral-300 font-medium">Component Versions</h4>
104
104
  <p className="text-sm text-neutral-600 mt-1">
@@ -132,7 +132,7 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
132
132
  icon={<Tag />}
133
133
  onClick={() => startEditComponent(comp)}
134
134
  size="xs"
135
- color="neutral"
135
+ accentColor="neutral"
136
136
  tooltip={{ title: 'Edit version', description: `Change ${getLabel(comp)} version` }}
137
137
  />
138
138
  )}
@@ -164,14 +164,14 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
164
164
  onClick={onBumpComponent}
165
165
  disabled={bumpingComponent || !componentVersion.trim()}
166
166
  size="sm"
167
- color="green"
167
+ accentColor="neutral"
168
168
  tooltip={{ title: 'Update', description: 'Save new version' }}
169
169
  />
170
170
  <IconButton
171
171
  icon="close"
172
172
  onClick={() => setEditingComponent(null)}
173
173
  size="sm"
174
- color="neutral"
174
+ accentColor="neutral"
175
175
  tooltip={{ title: 'Cancel', description: 'Cancel editing' }}
176
176
  />
177
177
  </div>
@@ -98,10 +98,10 @@ export function FileTypeTabbedPromptEditor({
98
98
  : undefined
99
99
 
100
100
  return (
101
- <div className={`flex w-full max-w-full bg-neutral-900 border border-neutral-700 rounded-lg overflow-hidden ${className}`}>
101
+ <div className={`flex w-full max-w-full bg-neutral-980 border border-neutral-700 rounded-lg overflow-hidden ${className}`}>
102
102
  {/* Left Sidebar — File Type Selector */}
103
103
  <div
104
- className="relative shrink-0 bg-neutral-950 overflow-hidden flex flex-col"
104
+ className="relative shrink-0 bg-neutral-990 overflow-hidden flex flex-col"
105
105
  style={{ width: sidebarWidth, minWidth: 160, maxWidth: 320 }}
106
106
  >
107
107
  {/* Header */}
@@ -126,7 +126,7 @@ export function FileTypeTabbedPromptEditor({
126
126
  className={`w-full min-h-[44px] py-2 flex items-center gap-2.5 px-3 text-left transition-colors ${
127
127
  isSelected
128
128
  ? 'bg-neutral-700/50 border-l-2 border-blue-400'
129
- : 'hover:bg-neutral-850 border-l-2 border-transparent'
129
+ : 'hover:bg-neutral-970 border-l-2 border-transparent'
130
130
  }`}
131
131
  >
132
132
  <div className={`flex-shrink-0 ${isSelected ? 'text-blue-400' : 'text-neutral-500'}`}>
@@ -88,7 +88,7 @@
88
88
 
89
89
  // Types
90
90
  export type {
91
- AiToolKey,
91
+ CodingAgentKey,
92
92
  ToolTab,
93
93
  PromptPlaceholder,
94
94
  PromptSnapshot,
@@ -22,6 +22,8 @@
22
22
  import { useState, useCallback, useMemo } from 'react'
23
23
  import { useResizableSidebar } from '../../hooks/use-resizable-sidebar.ts'
24
24
  import { ChevronDown, ChevronRight, GripVertical, Crosshair } from 'lucide-react'
25
+ import { useAccentColor, AccentColorProvider } from '../../lib/accent-context.ts'
26
+ import type { FormColor } from '../../lib/form-colors.ts'
25
27
  import { TabbedPromptEditor } from './tabbed-prompt-editor.tsx'
26
28
  import type { ToolTab, PromptPlaceholder, ScenarioOption } from './types.ts'
27
29
 
@@ -48,6 +50,7 @@ export interface SimulatorPromptEditorProps {
48
50
  onSave?: (scenario: string, step: string, tool: string, content: string) => void
49
51
  /** When true, validates "## Verification Checklist" section */
50
52
  validateChecklist?: boolean
53
+ accentColor?: FormColor
51
54
  className?: string
52
55
  }
53
56
 
@@ -65,8 +68,11 @@ export function SimulatorPromptEditor({
65
68
  onReset,
66
69
  onSave,
67
70
  validateChecklist = false,
71
+ accentColor,
68
72
  className = '',
69
73
  }: SimulatorPromptEditorProps) {
74
+ const contextAccent = useAccentColor()
75
+ const effectiveColor = accentColor ?? contextAccent ?? 'blue'
70
76
  const defaultScenarioId = scenarios[0]?.id ?? ''
71
77
  const defaultStepId = scenarios[0]?.steps[0]?.id ?? ''
72
78
 
@@ -131,10 +137,11 @@ export function SimulatorPromptEditor({
131
137
  }
132
138
 
133
139
  return (
134
- <div className={`flex w-full max-w-full bg-neutral-900 border border-neutral-700 rounded-lg overflow-hidden ${className}`}>
140
+ <AccentColorProvider value={effectiveColor}>
141
+ <div className={`flex w-full max-w-full bg-neutral-980 border border-neutral-700 rounded-lg overflow-hidden ${className}`}>
135
142
  {/* Left Sidebar — Tree Selector */}
136
143
  <div
137
- className="relative shrink-0 bg-neutral-950 overflow-hidden flex flex-col"
144
+ className="relative shrink-0 bg-neutral-990 overflow-hidden flex flex-col"
138
145
  style={{ width: sidebarWidth, minWidth: 180, maxWidth: 360 }}
139
146
  >
140
147
  {/* Header */}
@@ -159,8 +166,8 @@ export function SimulatorPromptEditor({
159
166
  {/* Scenario Header */}
160
167
  <button
161
168
  onClick={() => toggleScenario(scenario.id)}
162
- className={`w-full min-h-[44px] py-2 flex items-start gap-2 px-3 text-left transition-colors hover:bg-neutral-850 ${
163
- isScenarioActive ? 'bg-neutral-850/50' : ''
169
+ className={`w-full min-h-[44px] py-2 flex items-start gap-2 px-3 text-left transition-colors hover:bg-neutral-970 ${
170
+ isScenarioActive ? 'bg-neutral-970/50' : ''
164
171
  }`}
165
172
  >
166
173
  <div className="flex-shrink-0 mt-0.5 text-neutral-500">
@@ -194,7 +201,7 @@ export function SimulatorPromptEditor({
194
201
  className={`w-full h-[32px] flex items-center gap-2 pl-9 pr-3 text-left transition-colors ${
195
202
  isStepSelected
196
203
  ? 'bg-neutral-700/50 border-l-2 border-blue-400'
197
- : 'hover:bg-neutral-850 border-l-2 border-transparent'
204
+ : 'hover:bg-neutral-970 border-l-2 border-transparent'
198
205
  }`}
199
206
  >
200
207
  <div className={`w-1.5 h-1.5 rounded-full flex-shrink-0 ${
@@ -236,5 +243,6 @@ export function SimulatorPromptEditor({
236
243
  />
237
244
  </div>
238
245
  </div>
246
+ </AccentColorProvider>
239
247
  )
240
248
  }
@@ -14,7 +14,7 @@
14
14
  * <TabbedPromptEditor
15
15
  * prompts={{ claude: '...', gemini: '...' }}
16
16
  * onPromptChange={(tool, value) => save(tool, value)}
17
- * tools={[{ id: 'claude', name: 'Claude Code', icon: <AiToolIcon tool="claude" /> }]}
17
+ * tools={[{ id: 'claude', name: 'Claude Code', icon: <CodingAgentIcon agent="claude" /> }]}
18
18
  * variables={[{ name: 'FILE_PATH', description: 'Path to the file' }]}
19
19
  * />
20
20
  */
@@ -28,8 +28,10 @@ import { IconButton } from '../../ui/icon-button.tsx'
28
28
  import { Input } from '../../ui/input.tsx'
29
29
  import { EditorToolbar } from '../../ui/editor-toolbar.tsx'
30
30
  import { EditorPlaceholderCard } from '../../ui/editor-placeholder-card.tsx'
31
+ import { useAccentColor, AccentColorProvider } from '../../lib/accent-context.ts'
32
+ import type { FormColor } from '../../lib/form-colors.ts'
31
33
  import type { ToolTab, PromptPlaceholder } from './types.ts'
32
- import { AiToolIcon } from '../../lib/ai-tools.tsx'
34
+ import { CodingAgentIcon } from '../../lib/coding-agents.tsx'
33
35
 
34
36
  // ---------------------------------------------------------------------------
35
37
  // Constants
@@ -63,6 +65,7 @@ export interface TabbedPromptEditorProps {
63
65
  validateChecklist?: boolean
64
66
  /** When true, adds border and rounding for standalone usage */
65
67
  standalone?: boolean
68
+ accentColor?: FormColor
66
69
  className?: string
67
70
  }
68
71
 
@@ -80,8 +83,11 @@ export function TabbedPromptEditor({
80
83
  onSave,
81
84
  validateChecklist = false,
82
85
  standalone = false,
86
+ accentColor,
83
87
  className = '',
84
88
  }: TabbedPromptEditorProps) {
89
+ const contextAccent = useAccentColor()
90
+ const effectiveColor = accentColor ?? contextAccent ?? 'blue'
85
91
  const [activeTab, setActiveTab] = useState(tools[0]?.id ?? '')
86
92
  const { width: sidebarWidth, onPointerDown: handleSidebarPointerDown } = useResizableSidebar({ min: 220, max: 400, defaultWidth: 280, direction: 'left' })
87
93
  const [variableSearch, setVariableSearch] = useState('')
@@ -305,11 +311,12 @@ export function TabbedPromptEditor({
305
311
  }, [variables, variableSearch])
306
312
 
307
313
  return (
308
- <div className={`flex w-full h-full bg-neutral-900 overflow-hidden ${standalone ? 'border border-neutral-700 rounded-lg' : ''} ${className}`}>
314
+ <AccentColorProvider value={effectiveColor}>
315
+ <div className={`flex w-full h-full bg-neutral-980 overflow-hidden ${standalone ? 'border border-neutral-700 rounded-lg' : ''} ${className}`}>
309
316
  {/* Main content area */}
310
317
  <div className="flex-1 min-w-0 w-0 flex flex-col overflow-hidden">
311
318
  {/* Tool Tabs */}
312
- <div className="relative flex h-[26px] bg-neutral-950 shrink-0">
319
+ <div className="relative flex h-[26px] bg-neutral-990 shrink-0">
313
320
  {tools.map((tool) => {
314
321
  const isActive = activeTab === tool.id
315
322
  const activeColor = tool.activeColor ?? 'text-blue-400'
@@ -320,12 +327,12 @@ export function TabbedPromptEditor({
320
327
  onClick={() => setActiveTab(tool.id)}
321
328
  className={`flex-1 flex items-center justify-center gap-1.5 px-2 text-sm font-medium border-b-2 transition-colors ${
322
329
  isActive
323
- ? `border-current ${activeColor} bg-neutral-850`
324
- : 'border-neutral-700 text-neutral-500 hover:text-neutral-400 hover:bg-neutral-850/50'
330
+ ? `border-current ${activeColor} bg-neutral-970`
331
+ : 'border-neutral-700 text-neutral-500 hover:text-neutral-400 hover:bg-neutral-970/50'
325
332
  }`}
326
333
  title={tool.name}
327
334
  >
328
- {tool.icon ?? <AiToolIcon tool={tool.id} size={14} />}
335
+ {tool.icon ?? <CodingAgentIcon agent={tool.id} size={14} />}
329
336
  <span className="hidden sm:inline">{tool.shortName ?? tool.name}</span>
330
337
  </button>
331
338
  )
@@ -398,7 +405,7 @@ export function TabbedPromptEditor({
398
405
  {/* Variables Sidebar */}
399
406
  {hasVariables && (
400
407
  <div
401
- className="relative shrink-0 bg-neutral-950 overflow-hidden flex flex-col border-l border-neutral-700"
408
+ className="relative shrink-0 bg-neutral-990 overflow-hidden flex flex-col border-l border-neutral-700"
402
409
  style={{ width: sidebarWidth, minWidth: 220, maxWidth: 400 }}
403
410
  >
404
411
  {/* Resize handle on left edge */}
@@ -436,7 +443,7 @@ export function TabbedPromptEditor({
436
443
  <IconButton
437
444
  icon={<X className="w-3 h-3" />}
438
445
  onClick={() => setVariableSearch('')}
439
- color="neutral"
446
+ accentColor="neutral"
440
447
  size="xss"
441
448
  className="absolute right-2 top-1/2 -translate-y-1/2"
442
449
  tooltip={{ title: 'Clear', description: 'Clear search' }}
@@ -457,7 +464,7 @@ export function TabbedPromptEditor({
457
464
  <div className="flex-1 overflow-y-auto p-2.5 space-y-2">
458
465
  {filteredVariables.length > 0 ? (
459
466
  filteredVariables.map((variable: PromptPlaceholder) => (
460
- <div key={variable.name} className="bg-neutral-850 border border-neutral-700 rounded-lg">
467
+ <div key={variable.name} className="bg-neutral-970 border border-neutral-700 rounded-lg">
461
468
  <EditorPlaceholderCard
462
469
  name={variable.name}
463
470
  description={variable.description}
@@ -478,5 +485,6 @@ export function TabbedPromptEditor({
478
485
  </div>
479
486
  )}
480
487
  </div>
488
+ </AccentColorProvider>
481
489
  )
482
490
  }
@@ -9,8 +9,8 @@
9
9
 
10
10
  import type { ReactNode } from 'react'
11
11
 
12
- // Re-export the AI tool key type from the shared lib
13
- export type { AiToolKey } from '../../lib/ai-tools.tsx'
12
+ // Re-export the coding agent key type from the shared lib
13
+ export type { CodingAgentKey } from '../../lib/coding-agents.tsx'
14
14
 
15
15
  // ---------------------------------------------------------------------------
16
16
  // Tool definition (generic — not tied to specific AI tools)
@@ -32,6 +32,8 @@ import { cn } from '../../lib/cn.ts'
32
32
  import { Input } from '../../ui/input.tsx'
33
33
  import { ResizableTextarea } from '../../ui/resizable-textarea.tsx'
34
34
  import { Checkbox } from '../../ui/checkbox.tsx'
35
+ import { useAccentColor, AccentColorProvider } from '../../lib/accent-context.ts'
36
+ import type { FormColor } from '../../lib/form-colors.ts'
35
37
  import { ScreenshotUploader } from './screenshot-uploader.tsx'
36
38
  import { useReportBug, type UseReportBugOptions } from './use-report-bug.ts'
37
39
  import { ISSUE_TYPES, type IssueType, type IssueReport, type IssueReportResult, type SystemInfo } from './issue-reporter-api.ts'
@@ -66,6 +68,7 @@ export interface ReportBugFormProps {
66
68
  onErrorsSubmitted?: () => void
67
69
  /** Override default API submission (for testing/mocking) */
68
70
  submitFn?: (report: IssueReport) => Promise<IssueReportResult>
71
+ accentColor?: FormColor
69
72
  className?: string
70
73
  }
71
74
 
@@ -84,8 +87,11 @@ export function ReportBugForm({
84
87
  onCancel,
85
88
  onErrorsSubmitted,
86
89
  submitFn,
90
+ accentColor,
87
91
  className,
88
92
  }: ReportBugFormProps) {
93
+ const contextAccent = useAccentColor()
94
+ const effectiveColor = accentColor ?? contextAccent ?? 'blue'
89
95
  const hookOptions: UseReportBugOptions = {
90
96
  workerUrl,
91
97
  getSystemInfo,
@@ -122,7 +128,8 @@ export function ReportBugForm({
122
128
  const hasErrors = (errorCount ?? 0) > 0 || (warnCount ?? 0) > 0
123
129
 
124
130
  return (
125
- <div className={cn('rounded-lg border border-neutral-700 bg-neutral-800', className)}>
131
+ <AccentColorProvider value={effectiveColor}>
132
+ <div className={cn('rounded-lg border border-neutral-700 bg-neutral-960', className)}>
126
133
  <div className="border-b border-neutral-700 px-4 py-3">
127
134
  <h3 className="text-md font-medium text-neutral-200">Report a Bug</h3>
128
135
  </div>
@@ -173,7 +180,7 @@ export function ReportBugForm({
173
180
  onChange={(e) => setDescription(e.target.value)}
174
181
  placeholder="Describe the issue in detail. Include steps to reproduce if applicable."
175
182
  rows={6}
176
- className="w-full px-3 py-1.5 bg-neutral-800 border border-neutral-700 rounded-lg text-md text-neutral-200 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none min-h-[120px]"
183
+ className="w-full px-3 py-1.5 bg-neutral-960 border border-neutral-700 rounded-lg text-md text-neutral-200 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none min-h-[120px]"
177
184
  />
178
185
  </div>
179
186
 
@@ -222,11 +229,11 @@ export function ReportBugForm({
222
229
 
223
230
  {/* Captured errors list */}
224
231
  {includeLogs && capturedErrors && capturedErrors.length > 0 && (
225
- <div className="rounded-md border border-neutral-700 bg-neutral-900/50">
232
+ <div className="rounded-md border border-neutral-700 bg-neutral-980/50">
226
233
  <div className="px-3 py-2 border-b border-neutral-700">
227
234
  <span className="text-sm font-medium text-neutral-400">Captured Errors</span>
228
235
  </div>
229
- <div className="max-h-[200px] overflow-y-auto divide-y divide-neutral-800">
236
+ <div className="max-h-[200px] overflow-y-auto divide-y divide-neutral-960">
230
237
  {capturedErrors.map((error) => (
231
238
  <div key={error.fingerprint} className="px-3 py-2 text-sm">
232
239
  <div className="flex items-start gap-2">
@@ -278,5 +285,6 @@ export function ReportBugForm({
278
285
  </button>
279
286
  </div>
280
287
  </div>
288
+ </AccentColorProvider>
281
289
  )
282
290
  }
@@ -22,6 +22,8 @@
22
22
  import { useCallback, useRef, useState } from 'react'
23
23
  import { ImagePlus, X, AlertCircle } from 'lucide-react'
24
24
  import { cn } from '../../lib/cn.ts'
25
+ import { useAccentColor, AccentColorProvider } from '../../lib/accent-context.ts'
26
+ import type { FormColor } from '../../lib/form-colors.ts'
25
27
 
26
28
  export interface Screenshot {
27
29
  id: string
@@ -36,6 +38,7 @@ export interface ScreenshotUploaderProps {
36
38
  onChange: (screenshots: Screenshot[]) => void
37
39
  maxTotalSize?: number
38
40
  disabled?: boolean
41
+ accentColor?: FormColor
39
42
  className?: string
40
43
  }
41
44
 
@@ -52,8 +55,11 @@ export function ScreenshotUploader({
52
55
  onChange,
53
56
  maxTotalSize = DEFAULT_MAX_SIZE,
54
57
  disabled = false,
58
+ accentColor,
55
59
  className,
56
60
  }: ScreenshotUploaderProps) {
61
+ const contextAccent = useAccentColor()
62
+ const effectiveColor = accentColor ?? contextAccent ?? 'blue'
57
63
  const fileInputRef = useRef<HTMLInputElement>(null)
58
64
  const [isDragging, setIsDragging] = useState(false)
59
65
  const [error, setError] = useState<string | null>(null)
@@ -141,6 +147,7 @@ export function ScreenshotUploader({
141
147
  )
142
148
 
143
149
  return (
150
+ <AccentColorProvider value={effectiveColor}>
144
151
  <div className={cn('space-y-3', className)}>
145
152
  <div
146
153
  onClick={() => !disabled && fileInputRef.current?.click()}
@@ -152,8 +159,8 @@ export function ScreenshotUploader({
152
159
  isDragging
153
160
  ? 'border-blue-500 bg-blue-500/10'
154
161
  : disabled
155
- ? 'border-neutral-700 bg-neutral-900/50 cursor-not-allowed opacity-50'
156
- : 'border-neutral-600 hover:border-neutral-500 hover:bg-neutral-800/30',
162
+ ? 'border-neutral-700 bg-neutral-980/50 cursor-not-allowed opacity-50'
163
+ : 'border-neutral-600 hover:border-neutral-500 hover:bg-neutral-960/30',
157
164
  )}
158
165
  >
159
166
  <ImagePlus className={cn('w-6 h-6', isDragging ? 'text-blue-400' : 'text-neutral-500')} />
@@ -188,7 +195,7 @@ export function ScreenshotUploader({
188
195
  {screenshots.map((s) => (
189
196
  <div
190
197
  key={s.id}
191
- className="relative group aspect-video bg-neutral-900 border border-neutral-700 rounded-lg overflow-hidden"
198
+ className="relative group aspect-video bg-neutral-980 border border-neutral-700 rounded-lg overflow-hidden"
192
199
  >
193
200
  <img
194
201
  src={`data:${s.contentType};base64,${s.data}`}
@@ -224,5 +231,6 @@ export function ScreenshotUploader({
224
231
  </div>
225
232
  )}
226
233
  </div>
234
+ </AccentColorProvider>
227
235
  )
228
236
  }