@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.
- package/ai-manifest.json +35 -20
- package/components/composites/dashboard-list-item.tsx +172 -0
- package/components/composites/dashboard-panel.tsx +218 -0
- package/components/content/info-panel-primitives.tsx +9 -8
- package/components/diagrams/diagram-utils.tsx +2 -1
- package/components/hooks/use-dropdown-portal.ts +39 -0
- package/components/lib/accent-context.ts +10 -0
- package/components/lib/{ai-tools.tsx → coding-agents.tsx} +23 -8
- package/components/lib/custom-icons.tsx +37 -0
- package/components/lib/form-colors.ts +16 -16
- package/components/lib/git-providers.tsx +39 -0
- package/components/lib/theme-engine.ts +59 -10
- package/components/lib/toolr-brand.tsx +23 -9
- package/components/sections/captured-issues/captured-issues-panel.tsx +17 -8
- package/components/sections/{ai-tools-paths/tools-paths-panel.tsx → coding-agent-paths/agent-paths-panel.tsx} +70 -62
- package/components/sections/coding-agent-paths/index.ts +37 -0
- package/components/sections/{ai-tools-paths → coding-agent-paths}/types.ts +28 -28
- package/components/sections/coding-agent-paths/use-agent-paths.ts +159 -0
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +10 -9
- package/components/sections/golden-snapshots/golden-sync-panel.tsx +12 -3
- package/components/sections/golden-snapshots/snapshot-manager.tsx +9 -7
- package/components/sections/golden-snapshots/status-overview.tsx +8 -8
- package/components/sections/golden-snapshots/version-manager.tsx +6 -6
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +3 -3
- package/components/sections/prompt-editor/index.ts +1 -1
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +13 -5
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +18 -10
- package/components/sections/prompt-editor/types.ts +2 -2
- package/components/sections/report-bug/report-bug-form.tsx +12 -4
- package/components/sections/report-bug/screenshot-uploader.tsx +11 -3
- package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +12 -4
- package/components/sections/snapshot-browser/snapshot-tree.tsx +5 -4
- package/components/sections/snapshot-browser/types.ts +1 -1
- package/components/sections/snippets-editor/snippets-editor.tsx +16 -9
- package/components/settings/SettingsHeader.tsx +2 -2
- package/components/settings/SettingsPanel.tsx +11 -3
- package/components/settings/SettingsTreeNav.tsx +15 -9
- package/components/ui/action-dialog.tsx +24 -30
- package/components/ui/ai-action-button.tsx +10 -7
- package/components/ui/ai-execution-action-buttons.tsx +13 -5
- package/components/ui/badge.tsx +7 -4
- package/components/ui/bottom-panel-header.tsx +9 -5
- package/components/ui/breadcrumb.tsx +13 -5
- package/components/ui/{extension-list-card.tsx → capability-list-card.tsx} +13 -5
- package/components/ui/checkbox.tsx +6 -3
- package/components/ui/collapsible-section.tsx +38 -29
- package/components/ui/confirm-badge.tsx +7 -4
- package/components/ui/cookie-consent.tsx +13 -7
- package/components/ui/detail-section.tsx +24 -16
- package/components/ui/detail-view-wrapper.tsx +30 -22
- package/components/ui/editor-placeholder-card.tsx +28 -24
- package/components/ui/editor-toolbar.tsx +7 -4
- package/components/ui/execution-details-panel.tsx +10 -5
- package/components/ui/file-structure-section.tsx +7 -4
- package/components/ui/file-tree.tsx +3 -1
- package/components/ui/files-panel.tsx +147 -27
- package/components/ui/filter-dropdown.tsx +84 -74
- package/components/ui/form-actions.tsx +14 -6
- package/components/ui/frontmatter-form-header.tsx +10 -2
- package/components/ui/icon-button.tsx +22 -9
- package/components/ui/input.tsx +7 -4
- package/components/ui/label.tsx +5 -5
- package/components/ui/layout-tab-bar.tsx +7 -5
- package/components/ui/modal.tsx +18 -4
- package/components/ui/nav-card.tsx +6 -3
- package/components/ui/navigation-bar.tsx +164 -82
- package/components/ui/number-input.tsx +8 -4
- package/components/ui/project-explorer.tsx +666 -0
- package/components/ui/registry-browser.tsx +12 -1
- package/components/ui/registry-card.tsx +49 -42
- package/components/ui/registry-detail.tsx +40 -17
- package/components/ui/resizable-textarea.tsx +18 -11
- package/components/ui/scope-badge.tsx +18 -11
- package/components/ui/segmented-toggle.tsx +5 -2
- package/components/ui/select.tsx +12 -9
- package/components/ui/selection-grid.tsx +36 -37
- package/components/ui/setting-row.tsx +2 -2
- package/components/ui/settings-card.tsx +10 -3
- package/components/ui/settings-info-box.tsx +9 -5
- package/components/ui/settings-section-title.tsx +14 -2
- package/components/ui/snapshot-card.tsx +10 -2
- package/components/ui/snippets-panel.tsx +4 -2
- package/components/ui/sort-dropdown.tsx +39 -29
- package/components/ui/status-card.tsx +9 -1
- package/components/ui/tab-bar.tsx +12 -9
- package/components/ui/toggle.tsx +13 -7
- package/components/ui/tooltip.tsx +9 -1
- package/dist/content.js +8 -8
- package/dist/diagrams.d.ts +0 -1
- package/dist/index.d.ts +427 -184
- package/dist/index.js +3098 -1761
- package/dist/tokens/primitives.css +28 -6
- package/dist/tokens/semantic.css +15 -15
- package/dist/tokens/theme.css +23 -0
- package/index.ts +25 -11
- package/package.json +1 -1
- package/tokens/primitives.css +28 -6
- package/tokens/semantic.css +15 -15
- package/tokens/theme.css +23 -0
- package/components/sections/ai-tools-paths/index.ts +0 -37
- 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
|
-
|
|
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-
|
|
144
|
-
: 'border-transparent text-neutral-500 hover:text-neutral-300 hover:bg-neutral-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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'}`}>
|
|
@@ -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
|
-
<
|
|
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-
|
|
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-
|
|
163
|
-
isScenarioActive ? 'bg-neutral-
|
|
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-
|
|
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: <
|
|
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 {
|
|
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
|
-
<
|
|
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-
|
|
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-
|
|
324
|
-
: 'border-neutral-700 text-neutral-500 hover:text-neutral-400 hover:bg-neutral-
|
|
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 ?? <
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
|
13
|
-
export type {
|
|
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
|
-
<
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
156
|
-
: 'border-neutral-600 hover:border-neutral-500 hover:bg-neutral-
|
|
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-
|
|
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
|
}
|