@toolr/ui-design 0.1.5 → 0.1.6
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/agent-rules.json +91 -0
- package/ai-manifest.json +190 -0
- package/components/content/info-panel-primitives.tsx +14 -14
- package/components/lib/ai-tools.tsx +1 -1
- package/components/sections/ai-tools-paths/tools-paths-panel.tsx +7 -7
- package/components/sections/captured-issues/captured-issues-panel.tsx +11 -11
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +13 -13
- package/components/sections/golden-snapshots/golden-sync-panel.tsx +5 -5
- package/components/sections/golden-snapshots/snapshot-manager.tsx +11 -11
- package/components/sections/golden-snapshots/status-overview.tsx +20 -20
- package/components/sections/golden-snapshots/version-manager.tsx +8 -8
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +4 -4
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +5 -5
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +7 -7
- package/components/sections/report-bug/report-bug-form.tsx +14 -14
- package/components/sections/report-bug/screenshot-uploader.tsx +6 -6
- package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +3 -3
- package/components/sections/snapshot-browser/snapshot-tree.tsx +8 -8
- package/components/sections/snippets-editor/snippets-editor.tsx +81 -22
- package/components/settings/SettingsHeader.tsx +1 -1
- package/components/settings/SettingsTreeNav.tsx +22 -4
- package/components/ui/action-dialog.tsx +5 -5
- package/components/ui/badge.tsx +4 -4
- package/components/ui/bottom-panel-header.tsx +4 -4
- package/components/ui/breadcrumb.tsx +2 -2
- package/components/ui/collapsible-section.tsx +1 -1
- package/components/ui/cookie-consent.tsx +5 -5
- package/components/ui/detail-section.tsx +3 -3
- package/components/ui/editor-placeholder-card.tsx +7 -7
- package/components/ui/editor-toolbar.tsx +12 -0
- package/components/ui/execution-details-panel.tsx +6 -6
- package/components/ui/extension-list-card.tsx +3 -3
- package/components/ui/file-structure-section.tsx +17 -17
- package/components/ui/file-tree.tsx +3 -1
- package/components/ui/files-panel.tsx +27 -9
- package/components/ui/filter-dropdown.tsx +5 -5
- package/components/ui/form-actions.tsx +1 -1
- package/components/ui/frontmatter-form-header.tsx +4 -4
- package/components/ui/icon-button.tsx +1 -1
- package/components/ui/input.tsx +5 -5
- package/components/ui/label.tsx +4 -4
- package/components/ui/layout-tab-bar.tsx +4 -4
- package/components/ui/modal.tsx +2 -2
- package/components/ui/nav-card.tsx +3 -3
- package/components/ui/navigation-bar.tsx +5 -5
- package/components/ui/number-input.tsx +4 -4
- package/components/ui/registry-browser.tsx +4 -4
- package/components/ui/registry-card.tsx +13 -13
- package/components/ui/registry-detail.tsx +6 -6
- package/components/ui/segmented-toggle.tsx +4 -4
- package/components/ui/select.tsx +5 -5
- package/components/ui/selection-grid.tsx +4 -4
- package/components/ui/setting-row.tsx +1 -1
- package/components/ui/settings-card.tsx +3 -3
- package/components/ui/settings-info-box.tsx +1 -1
- package/components/ui/settings-section-title.tsx +1 -1
- package/components/ui/snapshot-card.tsx +7 -7
- package/components/ui/snippets-panel.tsx +10 -10
- package/components/ui/sort-dropdown.tsx +2 -2
- package/components/ui/status-card.tsx +4 -4
- package/components/ui/tab-bar.tsx +2 -2
- package/components/ui/tooltip.tsx +3 -3
- package/dist/content.js +14 -14
- package/dist/index.d.ts +11 -4
- package/dist/index.js +428 -336
- package/dist/tokens/primitives.css +9 -2
- package/package.json +13 -3
- package/tokens/primitives.css +9 -2
|
@@ -124,13 +124,13 @@ export function ReportBugForm({
|
|
|
124
124
|
return (
|
|
125
125
|
<div className={cn('rounded-lg border border-neutral-700 bg-neutral-800', className)}>
|
|
126
126
|
<div className="border-b border-neutral-700 px-4 py-3">
|
|
127
|
-
<h3 className="text-
|
|
127
|
+
<h3 className="text-md font-medium text-neutral-200">Report a Bug</h3>
|
|
128
128
|
</div>
|
|
129
129
|
|
|
130
130
|
<div className="space-y-4 p-4">
|
|
131
131
|
{/* Issue type pills */}
|
|
132
132
|
<div>
|
|
133
|
-
<label className="mb-2 block text-
|
|
133
|
+
<label className="mb-2 block text-sm text-neutral-400">Issue Type</label>
|
|
134
134
|
<div className="flex flex-wrap gap-2">
|
|
135
135
|
{ISSUE_TYPES.map((type) => (
|
|
136
136
|
<button
|
|
@@ -138,7 +138,7 @@ export function ReportBugForm({
|
|
|
138
138
|
type="button"
|
|
139
139
|
onClick={() => setIssueType(type.value as IssueType)}
|
|
140
140
|
className={cn(
|
|
141
|
-
'px-3 py-1.5 text-
|
|
141
|
+
'px-3 py-1.5 text-sm font-medium rounded-md transition-all',
|
|
142
142
|
issueType === type.value
|
|
143
143
|
? 'bg-blue-600 text-white'
|
|
144
144
|
: 'bg-neutral-700 text-neutral-400 hover:bg-neutral-600 hover:text-neutral-200',
|
|
@@ -152,7 +152,7 @@ export function ReportBugForm({
|
|
|
152
152
|
|
|
153
153
|
{/* Title */}
|
|
154
154
|
<div>
|
|
155
|
-
<label className="mb-1.5 block text-
|
|
155
|
+
<label className="mb-1.5 block text-sm text-neutral-400">
|
|
156
156
|
Title <span className="text-red-400">*</span>
|
|
157
157
|
</label>
|
|
158
158
|
<Input
|
|
@@ -165,7 +165,7 @@ export function ReportBugForm({
|
|
|
165
165
|
|
|
166
166
|
{/* Description */}
|
|
167
167
|
<div>
|
|
168
|
-
<label className="mb-1.5 block text-
|
|
168
|
+
<label className="mb-1.5 block text-sm text-neutral-400">
|
|
169
169
|
Description <span className="text-red-400">*</span>
|
|
170
170
|
</label>
|
|
171
171
|
<ResizableTextarea
|
|
@@ -173,13 +173,13 @@ export function ReportBugForm({
|
|
|
173
173
|
onChange={(e) => setDescription(e.target.value)}
|
|
174
174
|
placeholder="Describe the issue in detail. Include steps to reproduce if applicable."
|
|
175
175
|
rows={6}
|
|
176
|
-
className="w-full px-3 py-1.5 bg-neutral-800 border border-neutral-700 rounded-lg text-
|
|
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]"
|
|
177
177
|
/>
|
|
178
178
|
</div>
|
|
179
179
|
|
|
180
180
|
{/* Email */}
|
|
181
181
|
<div>
|
|
182
|
-
<label className="mb-1.5 block text-
|
|
182
|
+
<label className="mb-1.5 block text-sm text-neutral-400">Email (optional)</label>
|
|
183
183
|
<Input
|
|
184
184
|
type="text"
|
|
185
185
|
value={email}
|
|
@@ -192,7 +192,7 @@ export function ReportBugForm({
|
|
|
192
192
|
|
|
193
193
|
{/* Screenshots */}
|
|
194
194
|
<div>
|
|
195
|
-
<label className="mb-2 block text-
|
|
195
|
+
<label className="mb-2 block text-sm text-neutral-400">
|
|
196
196
|
Screenshots (optional, max 20MB total)
|
|
197
197
|
</label>
|
|
198
198
|
<ScreenshotUploader
|
|
@@ -208,7 +208,7 @@ export function ReportBugForm({
|
|
|
208
208
|
<div className="flex items-center gap-2.5">
|
|
209
209
|
<Checkbox checked={includeLogs} onChange={setIncludeLogs} />
|
|
210
210
|
<span
|
|
211
|
-
className="text-
|
|
211
|
+
className="text-md text-neutral-400 cursor-pointer select-none"
|
|
212
212
|
onClick={() => setIncludeLogs(!includeLogs)}
|
|
213
213
|
>
|
|
214
214
|
Include error logs
|
|
@@ -224,11 +224,11 @@ export function ReportBugForm({
|
|
|
224
224
|
{includeLogs && capturedErrors && capturedErrors.length > 0 && (
|
|
225
225
|
<div className="rounded-md border border-neutral-700 bg-neutral-900/50">
|
|
226
226
|
<div className="px-3 py-2 border-b border-neutral-700">
|
|
227
|
-
<span className="text-
|
|
227
|
+
<span className="text-sm font-medium text-neutral-400">Captured Errors</span>
|
|
228
228
|
</div>
|
|
229
229
|
<div className="max-h-[200px] overflow-y-auto divide-y divide-neutral-800">
|
|
230
230
|
{capturedErrors.map((error) => (
|
|
231
|
-
<div key={error.fingerprint} className="px-3 py-2 text-
|
|
231
|
+
<div key={error.fingerprint} className="px-3 py-2 text-sm">
|
|
232
232
|
<div className="flex items-start gap-2">
|
|
233
233
|
{error.count > 1 && (
|
|
234
234
|
<span className="shrink-0 text-orange-400 font-mono font-medium">
|
|
@@ -251,14 +251,14 @@ export function ReportBugForm({
|
|
|
251
251
|
{/* Footer */}
|
|
252
252
|
<div className="flex items-center justify-end gap-2 border-t border-neutral-700 px-4 py-3">
|
|
253
253
|
{isSubmitting && submissionStatus && (
|
|
254
|
-
<span className="text-
|
|
254
|
+
<span className="text-sm text-neutral-400 mr-auto">{submissionStatus}</span>
|
|
255
255
|
)}
|
|
256
256
|
{onCancel && (
|
|
257
257
|
<button
|
|
258
258
|
type="button"
|
|
259
259
|
onClick={onCancel}
|
|
260
260
|
disabled={isSubmitting}
|
|
261
|
-
className="rounded-md border border-neutral-700 bg-transparent px-3 py-1.5 text-
|
|
261
|
+
className="rounded-md border border-neutral-700 bg-transparent px-3 py-1.5 text-md text-neutral-400 transition-colors hover:bg-neutral-700 hover:text-neutral-200 disabled:opacity-50"
|
|
262
262
|
>
|
|
263
263
|
Cancel
|
|
264
264
|
</button>
|
|
@@ -267,7 +267,7 @@ export function ReportBugForm({
|
|
|
267
267
|
type="button"
|
|
268
268
|
onClick={handleSubmit}
|
|
269
269
|
disabled={!canSubmit}
|
|
270
|
-
className="flex items-center gap-1.5 rounded-md bg-blue-600 px-3 py-1.5 text-
|
|
270
|
+
className="flex items-center gap-1.5 rounded-md bg-blue-600 px-3 py-1.5 text-md text-white transition-colors hover:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50"
|
|
271
271
|
>
|
|
272
272
|
{isSubmitting ? (
|
|
273
273
|
<Loader2 className="w-3.5 h-3.5 animate-spin" />
|
|
@@ -158,10 +158,10 @@ export function ScreenshotUploader({
|
|
|
158
158
|
>
|
|
159
159
|
<ImagePlus className={cn('w-6 h-6', isDragging ? 'text-blue-400' : 'text-neutral-500')} />
|
|
160
160
|
<div className="text-center">
|
|
161
|
-
<p className="text-
|
|
161
|
+
<p className="text-md text-neutral-400">
|
|
162
162
|
{isDragging ? 'Drop images here' : 'Click or drag images to attach'}
|
|
163
163
|
</p>
|
|
164
|
-
<p className="text-
|
|
164
|
+
<p className="text-sm text-neutral-500 mt-1">
|
|
165
165
|
{formatFileSize(remainingSize)} remaining of {formatFileSize(maxTotalSize)}
|
|
166
166
|
</p>
|
|
167
167
|
</div>
|
|
@@ -177,7 +177,7 @@ export function ScreenshotUploader({
|
|
|
177
177
|
</div>
|
|
178
178
|
|
|
179
179
|
{error && (
|
|
180
|
-
<div className="flex items-center gap-2 text-
|
|
180
|
+
<div className="flex items-center gap-2 text-md text-red-400">
|
|
181
181
|
<AlertCircle className="w-4 h-4 flex-shrink-0" />
|
|
182
182
|
<span>{error}</span>
|
|
183
183
|
</div>
|
|
@@ -207,9 +207,9 @@ export function ScreenshotUploader({
|
|
|
207
207
|
>
|
|
208
208
|
<X className="w-3 h-3" />
|
|
209
209
|
</button>
|
|
210
|
-
<span className="text-
|
|
210
|
+
<span className="text-sm text-white truncate">{s.filename}</span>
|
|
211
211
|
</div>
|
|
212
|
-
<div className="absolute bottom-1 right-1 px-1.5 py-0.5 bg-[var(--background)]/70 rounded text-
|
|
212
|
+
<div className="absolute bottom-1 right-1 px-1.5 py-0.5 bg-[var(--background)]/70 rounded text-sm text-neutral-400">
|
|
213
213
|
{formatFileSize(s.size)}
|
|
214
214
|
</div>
|
|
215
215
|
</div>
|
|
@@ -218,7 +218,7 @@ export function ScreenshotUploader({
|
|
|
218
218
|
)}
|
|
219
219
|
|
|
220
220
|
{screenshots.length > 0 && (
|
|
221
|
-
<div className="flex items-center justify-between text-
|
|
221
|
+
<div className="flex items-center justify-between text-sm text-neutral-500">
|
|
222
222
|
<span>{screenshots.length} image{screenshots.length !== 1 ? 's' : ''} attached</span>
|
|
223
223
|
<span>Total: {formatFileSize(totalSize)}</span>
|
|
224
224
|
</div>
|
|
@@ -75,7 +75,7 @@ export function SnapshotBrowserPanel({
|
|
|
75
75
|
<div className="flex items-center justify-between">
|
|
76
76
|
<div>
|
|
77
77
|
<label className="text-neutral-300">Snapshot Limit</label>
|
|
78
|
-
<p className="text-
|
|
78
|
+
<p className="text-md text-neutral-500">
|
|
79
79
|
Maximum number of snapshots to keep per item (1-50)
|
|
80
80
|
</p>
|
|
81
81
|
</div>
|
|
@@ -92,7 +92,7 @@ export function SnapshotBrowserPanel({
|
|
|
92
92
|
<div className="flex items-center justify-between mb-3">
|
|
93
93
|
<div>
|
|
94
94
|
<label className="text-neutral-300">Browse Snapshots</label>
|
|
95
|
-
<p className="text-
|
|
95
|
+
<p className="text-md text-neutral-500">
|
|
96
96
|
{totalSnapshotCount === 0
|
|
97
97
|
? 'No snapshots saved yet'
|
|
98
98
|
: `${totalSnapshotCount} snapshot${totalSnapshotCount === 1 ? '' : 's'} stored`}
|
|
@@ -129,7 +129,7 @@ export function SnapshotBrowserPanel({
|
|
|
129
129
|
<div className="bg-neutral-900/50 border border-neutral-700 rounded-lg p-4">
|
|
130
130
|
<div className="flex items-start gap-3">
|
|
131
131
|
<HelpCircle className="w-4 h-4 text-neutral-500 mt-0.5 shrink-0" />
|
|
132
|
-
<div className="text-
|
|
132
|
+
<div className="text-md text-neutral-500 space-y-2">
|
|
133
133
|
<p>
|
|
134
134
|
<strong className="text-neutral-400">How snapshots work:</strong>
|
|
135
135
|
</p>
|
|
@@ -194,14 +194,14 @@ function SnapshotEntryRow({
|
|
|
194
194
|
|
|
195
195
|
return (
|
|
196
196
|
<div
|
|
197
|
-
className="flex items-center gap-2 px-2 py-1.5 text-
|
|
197
|
+
className="flex items-center gap-2 px-2 py-1.5 text-md rounded-md group transition-colors hover:bg-neutral-700/50 text-neutral-400"
|
|
198
198
|
style={{ paddingLeft: `${depth * 16 + 8}px` }}
|
|
199
199
|
>
|
|
200
200
|
<Clock className="w-3 h-3 shrink-0 text-neutral-500" />
|
|
201
|
-
<span className="text-
|
|
201
|
+
<span className="text-sm flex-1 truncate">
|
|
202
202
|
{searchQuery ? highlightMatch(displayName, searchQuery) : displayName}
|
|
203
203
|
</span>
|
|
204
|
-
<span className="text-
|
|
204
|
+
<span className="text-xs text-neutral-500 shrink-0" title={formatFullDate(entry.savedAt)}>
|
|
205
205
|
{formatRelativeTime(entry.savedAt)}
|
|
206
206
|
</span>
|
|
207
207
|
<IconButton
|
|
@@ -248,7 +248,7 @@ function ExpandableNode({
|
|
|
248
248
|
<div>
|
|
249
249
|
<button
|
|
250
250
|
onClick={() => onToggle(path)}
|
|
251
|
-
className="w-full flex items-center gap-2 px-2 py-1.5 text-
|
|
251
|
+
className="w-full flex items-center gap-2 px-2 py-1.5 text-md rounded-md transition-colors cursor-pointer text-neutral-400 hover:bg-neutral-700/50 hover:text-neutral-300"
|
|
252
252
|
style={{ paddingLeft: `${depth * 16 + 8}px` }}
|
|
253
253
|
>
|
|
254
254
|
<span className="w-4 h-4 flex items-center justify-center shrink-0">
|
|
@@ -266,7 +266,7 @@ function ExpandableNode({
|
|
|
266
266
|
</span>
|
|
267
267
|
|
|
268
268
|
{snapshotCount > 0 && (
|
|
269
|
-
<span className="text-
|
|
269
|
+
<span className="text-sm text-neutral-500 bg-neutral-700 px-1.5 py-0.5 rounded shrink-0">
|
|
270
270
|
{snapshotCount}
|
|
271
271
|
</span>
|
|
272
272
|
)}
|
|
@@ -322,10 +322,10 @@ export function SnapshotTree({
|
|
|
322
322
|
|
|
323
323
|
if (totalCount === 0) {
|
|
324
324
|
return (
|
|
325
|
-
<div className={cn('text-
|
|
325
|
+
<div className={cn('text-md text-neutral-500 py-8 text-center', className)}>
|
|
326
326
|
No snapshots saved yet.
|
|
327
327
|
<br />
|
|
328
|
-
<span className="text-
|
|
328
|
+
<span className="text-sm">Use the camera button in editors to save snapshots.</span>
|
|
329
329
|
</div>
|
|
330
330
|
)
|
|
331
331
|
}
|
|
@@ -377,7 +377,7 @@ export function SnapshotTree({
|
|
|
377
377
|
{/* Tree */}
|
|
378
378
|
<div className="bg-neutral-900 border border-neutral-700 rounded-lg p-2 min-h-[200px] max-h-[60vh] overflow-y-auto">
|
|
379
379
|
{filteredScopes.length === 0 && searchQuery ? (
|
|
380
|
-
<p className="text-
|
|
380
|
+
<p className="text-sm text-neutral-500 text-center py-4">
|
|
381
381
|
No snapshots match “{searchQuery}”
|
|
382
382
|
</p>
|
|
383
383
|
) : (
|
|
@@ -39,6 +39,59 @@ export interface SnippetsEditorProps {
|
|
|
39
39
|
/** Section description, e.g. "Define snippets to reuse in skills prompts..." */
|
|
40
40
|
description?: string
|
|
41
41
|
className?: string
|
|
42
|
+
accentColor?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ACCENT_DIVIDER_HOVER: Record<string, string> = {
|
|
46
|
+
blue: 'hover:bg-blue-500/30',
|
|
47
|
+
purple: 'hover:bg-purple-500/30',
|
|
48
|
+
orange: 'hover:bg-orange-500/30',
|
|
49
|
+
green: 'hover:bg-green-500/30',
|
|
50
|
+
pink: 'hover:bg-pink-500/30',
|
|
51
|
+
amber: 'hover:bg-amber-500/30',
|
|
52
|
+
emerald: 'hover:bg-emerald-500/30',
|
|
53
|
+
teal: 'hover:bg-teal-500/30',
|
|
54
|
+
sky: 'hover:bg-sky-500/30',
|
|
55
|
+
violet: 'hover:bg-violet-500/30',
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ACCENT_TEXT: Record<string, string> = {
|
|
59
|
+
blue: 'text-blue-400',
|
|
60
|
+
purple: 'text-purple-400',
|
|
61
|
+
orange: 'text-orange-400',
|
|
62
|
+
green: 'text-green-400',
|
|
63
|
+
pink: 'text-pink-400',
|
|
64
|
+
amber: 'text-amber-400',
|
|
65
|
+
emerald: 'text-emerald-400',
|
|
66
|
+
teal: 'text-teal-400',
|
|
67
|
+
sky: 'text-sky-400',
|
|
68
|
+
violet: 'text-violet-400',
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ACCENT_BORDER: Record<string, string> = {
|
|
72
|
+
blue: 'border-l-blue-400',
|
|
73
|
+
purple: 'border-l-purple-400',
|
|
74
|
+
orange: 'border-l-orange-400',
|
|
75
|
+
green: 'border-l-green-400',
|
|
76
|
+
pink: 'border-l-pink-400',
|
|
77
|
+
amber: 'border-l-amber-400',
|
|
78
|
+
emerald: 'border-l-emerald-400',
|
|
79
|
+
teal: 'border-l-teal-400',
|
|
80
|
+
sky: 'border-l-sky-400',
|
|
81
|
+
violet: 'border-l-violet-400',
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const ACCENT_BUTTON: Record<string, string> = {
|
|
85
|
+
blue: 'bg-blue-600 hover:bg-blue-500',
|
|
86
|
+
purple: 'bg-purple-600 hover:bg-purple-500',
|
|
87
|
+
orange: 'bg-orange-600 hover:bg-orange-500',
|
|
88
|
+
green: 'bg-green-600 hover:bg-green-500',
|
|
89
|
+
pink: 'bg-pink-600 hover:bg-pink-500',
|
|
90
|
+
amber: 'bg-amber-600 hover:bg-amber-500',
|
|
91
|
+
emerald: 'bg-emerald-600 hover:bg-emerald-500',
|
|
92
|
+
teal: 'bg-teal-600 hover:bg-teal-500',
|
|
93
|
+
sky: 'bg-sky-600 hover:bg-sky-500',
|
|
94
|
+
violet: 'bg-violet-600 hover:bg-violet-500',
|
|
42
95
|
}
|
|
43
96
|
|
|
44
97
|
const MIN_SIDEBAR = 200
|
|
@@ -51,6 +104,7 @@ export function SnippetsEditor({
|
|
|
51
104
|
title = 'Snippets',
|
|
52
105
|
description = 'Define reusable snippets for prompts using {{SNIPPET_NAME}} syntax.',
|
|
53
106
|
className,
|
|
107
|
+
accentColor = 'blue',
|
|
54
108
|
}: SnippetsEditorProps) {
|
|
55
109
|
const {
|
|
56
110
|
selectedName,
|
|
@@ -103,12 +157,12 @@ export function SnippetsEditor({
|
|
|
103
157
|
<div className="flex items-center justify-between px-4 py-3 border-b border-neutral-700 bg-purple-500/5">
|
|
104
158
|
<div className="flex items-center gap-2">
|
|
105
159
|
<Braces className="w-4 h-4 text-purple-400" />
|
|
106
|
-
<h3 className="text-
|
|
107
|
-
<span className="px-2 py-0.5 text-
|
|
160
|
+
<h3 className="text-md font-medium text-neutral-300">{title}</h3>
|
|
161
|
+
<span className="px-2 py-0.5 text-sm rounded-full bg-neutral-700 text-neutral-400">
|
|
108
162
|
{snippets.length}
|
|
109
163
|
</span>
|
|
110
164
|
</div>
|
|
111
|
-
<p className="text-
|
|
165
|
+
<p className="text-sm text-neutral-500 hidden sm:block">{description}</p>
|
|
112
166
|
</div>
|
|
113
167
|
|
|
114
168
|
{/* Body: two columns */}
|
|
@@ -141,10 +195,10 @@ export function SnippetsEditor({
|
|
|
141
195
|
{filteredSnippets.length === 0 && !isAdding && (
|
|
142
196
|
<div className="text-center py-10 px-4">
|
|
143
197
|
<Braces className="w-8 h-8 mx-auto text-purple-400/40 mb-3" />
|
|
144
|
-
<p className="text-
|
|
198
|
+
<p className="text-sm text-neutral-500 mb-1">
|
|
145
199
|
{searchQuery ? 'No matching snippets' : 'No snippets defined'}
|
|
146
200
|
</p>
|
|
147
|
-
<p className="text-
|
|
201
|
+
<p className="text-xs text-neutral-600">
|
|
148
202
|
{searchQuery ? 'Try a different search term' : 'Click + to add your first snippet'}
|
|
149
203
|
</p>
|
|
150
204
|
</div>
|
|
@@ -156,6 +210,7 @@ export function SnippetsEditor({
|
|
|
156
210
|
selected={selectedName === snippet.name}
|
|
157
211
|
onSelect={() => selectSnippet(snippet.name)}
|
|
158
212
|
onDelete={() => remove(snippet.name)}
|
|
213
|
+
accentColor={accentColor}
|
|
159
214
|
/>
|
|
160
215
|
))}
|
|
161
216
|
</div>
|
|
@@ -163,7 +218,7 @@ export function SnippetsEditor({
|
|
|
163
218
|
|
|
164
219
|
{/* Resizable divider */}
|
|
165
220
|
<div
|
|
166
|
-
className=
|
|
221
|
+
className={`w-1 cursor-col-resize bg-transparent ${ACCENT_DIVIDER_HOVER[accentColor] ?? ACCENT_DIVIDER_HOVER.blue} transition-colors flex-shrink-0`}
|
|
167
222
|
onMouseDown={onDividerMouseDown}
|
|
168
223
|
/>
|
|
169
224
|
|
|
@@ -181,15 +236,16 @@ export function SnippetsEditor({
|
|
|
181
236
|
onReset={resetForm}
|
|
182
237
|
onDelete={isEditing && selectedName ? () => remove(selectedName) : undefined}
|
|
183
238
|
onCancel={isAdding ? cancelForm : undefined}
|
|
239
|
+
accentColor={accentColor}
|
|
184
240
|
/>
|
|
185
241
|
) : (
|
|
186
242
|
<div className="flex-1 flex items-center justify-center p-6">
|
|
187
243
|
<div className="text-center max-w-xs">
|
|
188
244
|
<Braces className="w-10 h-10 mx-auto text-purple-400/30 mb-4" />
|
|
189
|
-
<p className="text-
|
|
190
|
-
<p className="text-
|
|
245
|
+
<p className="text-md text-neutral-500 mb-2">Select a snippet to edit</p>
|
|
246
|
+
<p className="text-sm text-neutral-600 leading-relaxed">
|
|
191
247
|
Choose a snippet from the list, or click{' '}
|
|
192
|
-
<span className=
|
|
248
|
+
<span className={ACCENT_TEXT[accentColor] ?? ACCENT_TEXT.blue}>+</span> to create a new one.
|
|
193
249
|
Reference snippets in prompts with{' '}
|
|
194
250
|
<span className="font-mono text-purple-400">{'{{SNIPPET_NAME}}'}</span> syntax.
|
|
195
251
|
</p>
|
|
@@ -211,28 +267,29 @@ interface SnippetListItemProps {
|
|
|
211
267
|
selected: boolean
|
|
212
268
|
onSelect: () => void
|
|
213
269
|
onDelete: () => void
|
|
270
|
+
accentColor: string
|
|
214
271
|
}
|
|
215
272
|
|
|
216
|
-
function SnippetListItem({ snippet, selected, onSelect, onDelete }: SnippetListItemProps) {
|
|
273
|
+
function SnippetListItem({ snippet, selected, onSelect, onDelete, accentColor }: SnippetListItemProps) {
|
|
217
274
|
return (
|
|
218
275
|
<div
|
|
219
276
|
className={cn(
|
|
220
277
|
'group flex items-start gap-2 px-3 py-2.5 cursor-pointer transition-colors border-l-2',
|
|
221
278
|
selected
|
|
222
|
-
?
|
|
279
|
+
? `bg-neutral-850 ${ACCENT_BORDER[accentColor] ?? ACCENT_BORDER.blue}`
|
|
223
280
|
: 'border-l-transparent hover:bg-neutral-850/50',
|
|
224
281
|
)}
|
|
225
282
|
onClick={onSelect}
|
|
226
283
|
>
|
|
227
284
|
<div className="flex-1 min-w-0">
|
|
228
|
-
<p className="text-
|
|
285
|
+
<p className="text-sm font-mono font-medium text-neutral-300 truncate">
|
|
229
286
|
{snippet.name}
|
|
230
287
|
</p>
|
|
231
|
-
<p className="text-
|
|
288
|
+
<p className="text-xs text-neutral-500 truncate mt-0.5">
|
|
232
289
|
{snippet.description}
|
|
233
290
|
</p>
|
|
234
291
|
{snippet.value && (
|
|
235
|
-
<p className="text-
|
|
292
|
+
<p className="text-xs text-neutral-600 truncate mt-0.5 font-mono">
|
|
236
293
|
{snippet.value.slice(0, 80)}{snippet.value.length > 80 ? '...' : ''}
|
|
237
294
|
</p>
|
|
238
295
|
)}
|
|
@@ -263,6 +320,7 @@ interface SnippetFormProps {
|
|
|
263
320
|
onReset: () => void
|
|
264
321
|
onDelete?: () => void
|
|
265
322
|
onCancel?: () => void
|
|
323
|
+
accentColor: string
|
|
266
324
|
}
|
|
267
325
|
|
|
268
326
|
function SnippetForm({
|
|
@@ -276,13 +334,14 @@ function SnippetForm({
|
|
|
276
334
|
onReset,
|
|
277
335
|
onDelete,
|
|
278
336
|
onCancel,
|
|
337
|
+
accentColor,
|
|
279
338
|
}: SnippetFormProps) {
|
|
280
339
|
return (
|
|
281
340
|
<div className="flex-1 flex flex-col">
|
|
282
341
|
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
|
283
342
|
{/* Name */}
|
|
284
343
|
<div>
|
|
285
|
-
<label className="block text-
|
|
344
|
+
<label className="block text-sm text-neutral-500 mb-1.5">
|
|
286
345
|
Snippet Name <span className="text-red-400">*</span>
|
|
287
346
|
</label>
|
|
288
347
|
<Input
|
|
@@ -292,14 +351,14 @@ function SnippetForm({
|
|
|
292
351
|
error={nameHasError}
|
|
293
352
|
autoFocus={!isEditing}
|
|
294
353
|
/>
|
|
295
|
-
<p className="mt-1 text-
|
|
354
|
+
<p className="mt-1 text-xs text-neutral-600">
|
|
296
355
|
Use in prompts as <span className="font-mono text-purple-400">{'{{' + (formData.name || 'NAME') + '}}'}</span>
|
|
297
356
|
</p>
|
|
298
357
|
</div>
|
|
299
358
|
|
|
300
359
|
{/* Description */}
|
|
301
360
|
<div>
|
|
302
|
-
<label className="block text-
|
|
361
|
+
<label className="block text-sm text-neutral-500 mb-1.5">
|
|
303
362
|
Description <span className="text-red-400">*</span>
|
|
304
363
|
</label>
|
|
305
364
|
<Input
|
|
@@ -311,7 +370,7 @@ function SnippetForm({
|
|
|
311
370
|
|
|
312
371
|
{/* Value */}
|
|
313
372
|
<div>
|
|
314
|
-
<label className="block text-
|
|
373
|
+
<label className="block text-sm text-neutral-500 mb-1.5">Value</label>
|
|
315
374
|
<ResizableTextarea
|
|
316
375
|
mode="code"
|
|
317
376
|
language="markdown"
|
|
@@ -319,7 +378,7 @@ function SnippetForm({
|
|
|
319
378
|
onChange={(val) => setFormField('value', val)}
|
|
320
379
|
minHeight={160}
|
|
321
380
|
/>
|
|
322
|
-
<p className="mt-1 text-
|
|
381
|
+
<p className="mt-1 text-xs text-neutral-600">
|
|
323
382
|
Can be a single value, multi-line text, or an entire document
|
|
324
383
|
</p>
|
|
325
384
|
</div>
|
|
@@ -327,7 +386,7 @@ function SnippetForm({
|
|
|
327
386
|
{/* Error */}
|
|
328
387
|
{formError && (
|
|
329
388
|
<div className="px-3 py-2 bg-red-500/10 border border-red-500/30 rounded-lg">
|
|
330
|
-
<p className="text-
|
|
389
|
+
<p className="text-sm text-red-400">{formError}</p>
|
|
331
390
|
</div>
|
|
332
391
|
)}
|
|
333
392
|
</div>
|
|
@@ -352,7 +411,7 @@ function SnippetForm({
|
|
|
352
411
|
type="button"
|
|
353
412
|
onClick={onCancel}
|
|
354
413
|
disabled={isSaving}
|
|
355
|
-
className="rounded-md border border-neutral-700 bg-transparent px-3 py-1.5 text-
|
|
414
|
+
className="rounded-md border border-neutral-700 bg-transparent px-3 py-1.5 text-sm text-neutral-400 transition-colors hover:bg-neutral-700 hover:text-neutral-300 disabled:opacity-50"
|
|
356
415
|
>
|
|
357
416
|
Cancel
|
|
358
417
|
</button>
|
|
@@ -369,7 +428,7 @@ function SnippetForm({
|
|
|
369
428
|
type="button"
|
|
370
429
|
onClick={onSave}
|
|
371
430
|
disabled={isSaving}
|
|
372
|
-
className=
|
|
431
|
+
className={`flex items-center gap-1.5 rounded-md ${ACCENT_BUTTON[accentColor] ?? ACCENT_BUTTON.blue} px-3 py-1.5 text-sm text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50`}
|
|
373
432
|
>
|
|
374
433
|
<Save className="w-3 h-3" />
|
|
375
434
|
{isEditing ? 'Save' : 'Add'}
|
|
@@ -55,7 +55,7 @@ export function SettingsHeader({
|
|
|
55
55
|
<div className={`flex-shrink-0 w-8 h-8 rounded-lg ${styles.iconBg} flex items-center justify-center`}>
|
|
56
56
|
{icon ?? <Info className={`w-4 h-4 ${styles.iconColor}`} />}
|
|
57
57
|
</div>
|
|
58
|
-
<p className="flex-1 text-
|
|
58
|
+
<p className="flex-1 text-md text-neutral-400 leading-relaxed">{description}</p>
|
|
59
59
|
<div className="flex-shrink-0 flex items-center gap-2">
|
|
60
60
|
{action}
|
|
61
61
|
{onReset && (
|
|
@@ -14,6 +14,20 @@ export interface SettingsTreeNavProps {
|
|
|
14
14
|
tree: SettingsTreeNode[]
|
|
15
15
|
selectedPath: string
|
|
16
16
|
onSelectPath: (path: string) => void
|
|
17
|
+
accentColor?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ACCENT_SELECTED: Record<string, string> = {
|
|
21
|
+
blue: 'bg-blue-500/20 text-blue-400',
|
|
22
|
+
purple: 'bg-purple-500/20 text-purple-400',
|
|
23
|
+
orange: 'bg-orange-500/20 text-orange-400',
|
|
24
|
+
green: 'bg-green-500/20 text-green-400',
|
|
25
|
+
pink: 'bg-pink-500/20 text-pink-400',
|
|
26
|
+
amber: 'bg-amber-500/20 text-amber-400',
|
|
27
|
+
emerald: 'bg-emerald-500/20 text-emerald-400',
|
|
28
|
+
teal: 'bg-teal-500/20 text-teal-400',
|
|
29
|
+
sky: 'bg-sky-500/20 text-sky-400',
|
|
30
|
+
violet: 'bg-violet-500/20 text-violet-400',
|
|
17
31
|
}
|
|
18
32
|
|
|
19
33
|
interface TreeNodeProps {
|
|
@@ -25,6 +39,7 @@ interface TreeNodeProps {
|
|
|
25
39
|
onToggleExpand: (path: string) => void
|
|
26
40
|
depth: number
|
|
27
41
|
searchQuery?: string
|
|
42
|
+
accentColor: string
|
|
28
43
|
}
|
|
29
44
|
|
|
30
45
|
function highlightMatch(text: string, query: string | undefined) {
|
|
@@ -53,6 +68,7 @@ function TreeNode({
|
|
|
53
68
|
onToggleExpand,
|
|
54
69
|
depth,
|
|
55
70
|
searchQuery,
|
|
71
|
+
accentColor,
|
|
56
72
|
}: TreeNodeProps) {
|
|
57
73
|
const isLeaf = isLeafNode(node)
|
|
58
74
|
const isExpanded = expandedPaths.has(path)
|
|
@@ -72,8 +88,8 @@ function TreeNode({
|
|
|
72
88
|
<button
|
|
73
89
|
onClick={handleClick}
|
|
74
90
|
className={`
|
|
75
|
-
w-full flex items-center gap-2 px-2 py-1.5 text-
|
|
76
|
-
${isSelected ?
|
|
91
|
+
w-full flex items-center gap-2 px-2 py-1.5 text-md rounded-md transition-colors cursor-pointer
|
|
92
|
+
${isSelected ? ACCENT_SELECTED[accentColor] ?? ACCENT_SELECTED.blue : isInSelectedPath ? 'text-neutral-300' : 'text-neutral-400'}
|
|
77
93
|
${!isSelected && 'hover:bg-neutral-800 hover:text-neutral-200'}
|
|
78
94
|
`}
|
|
79
95
|
style={{ paddingLeft: `${depth * 12 + 8}px` }}
|
|
@@ -110,6 +126,7 @@ function TreeNode({
|
|
|
110
126
|
onToggleExpand={onToggleExpand}
|
|
111
127
|
depth={depth + 1}
|
|
112
128
|
searchQuery={searchQuery}
|
|
129
|
+
accentColor={accentColor}
|
|
113
130
|
/>
|
|
114
131
|
))}
|
|
115
132
|
</div>
|
|
@@ -118,7 +135,7 @@ function TreeNode({
|
|
|
118
135
|
)
|
|
119
136
|
}
|
|
120
137
|
|
|
121
|
-
export function SettingsTreeNav({ tree, selectedPath, onSelectPath }: SettingsTreeNavProps) {
|
|
138
|
+
export function SettingsTreeNav({ tree, selectedPath, onSelectPath, accentColor = 'blue' }: SettingsTreeNavProps) {
|
|
122
139
|
const [expandedPaths, setExpandedPaths] = useState<Set<string>>(() => {
|
|
123
140
|
const expanded = new Set<string>()
|
|
124
141
|
if (selectedPath) {
|
|
@@ -232,7 +249,7 @@ export function SettingsTreeNav({ tree, selectedPath, onSelectPath }: SettingsTr
|
|
|
232
249
|
|
|
233
250
|
<div className="flex-1 overflow-y-auto py-2">
|
|
234
251
|
{filteredTree.length === 0 && searchQuery ? (
|
|
235
|
-
<p className="text-
|
|
252
|
+
<p className="text-sm text-neutral-500 text-center py-4 px-2">
|
|
236
253
|
No settings match "{searchQuery}"
|
|
237
254
|
</p>
|
|
238
255
|
) : (
|
|
@@ -247,6 +264,7 @@ export function SettingsTreeNav({ tree, selectedPath, onSelectPath }: SettingsTr
|
|
|
247
264
|
onToggleExpand={handleToggleExpand}
|
|
248
265
|
depth={0}
|
|
249
266
|
searchQuery={searchQuery}
|
|
267
|
+
accentColor={accentColor}
|
|
250
268
|
/>
|
|
251
269
|
))
|
|
252
270
|
)}
|
|
@@ -211,11 +211,11 @@ export function ActionDialog({
|
|
|
211
211
|
/>
|
|
212
212
|
)}
|
|
213
213
|
<div className="flex flex-col">
|
|
214
|
-
<span className="text-
|
|
214
|
+
<span className="text-md font-semibold text-neutral-200">
|
|
215
215
|
{title}
|
|
216
216
|
</span>
|
|
217
217
|
{subtitle && (
|
|
218
|
-
<span className="text-
|
|
218
|
+
<span className="text-sm text-neutral-500">{subtitle}</span>
|
|
219
219
|
)}
|
|
220
220
|
</div>
|
|
221
221
|
<div className="flex-1" />
|
|
@@ -236,7 +236,7 @@ export function ActionDialog({
|
|
|
236
236
|
{hasSelection && (
|
|
237
237
|
<div>
|
|
238
238
|
{selectionLabel && (
|
|
239
|
-
<div className="text-
|
|
239
|
+
<div className="text-sm text-neutral-500 mb-2">{selectionLabel}</div>
|
|
240
240
|
)}
|
|
241
241
|
<SelectionGrid
|
|
242
242
|
items={items}
|
|
@@ -254,11 +254,11 @@ export function ActionDialog({
|
|
|
254
254
|
{hasScenarios && (
|
|
255
255
|
<div>
|
|
256
256
|
<div className="flex items-center justify-between mb-2">
|
|
257
|
-
<span className="text-
|
|
257
|
+
<span className="text-sm text-neutral-500">{scenarioLabel}</span>
|
|
258
258
|
<button
|
|
259
259
|
type="button"
|
|
260
260
|
onClick={handleSelectAllScenarios}
|
|
261
|
-
className="text-
|
|
261
|
+
className="text-sm text-blue-400 hover:text-blue-300 transition-colors cursor-pointer"
|
|
262
262
|
>
|
|
263
263
|
{allScenariosSelected ? 'Deselect All' : 'Select All'}
|
|
264
264
|
</button>
|
package/components/ui/badge.tsx
CHANGED
|
@@ -43,10 +43,10 @@ const colorClasses: Record<BadgeColor, string> = {
|
|
|
43
43
|
|
|
44
44
|
const sizeClasses = {
|
|
45
45
|
xss: 'min-w-[14px] h-[14px] px-0.5 text-xss',
|
|
46
|
-
xs: 'min-w-[16px] h-[16px] px-1 text-
|
|
47
|
-
sm: 'min-w-[18px] h-[18px] px-1 text-
|
|
48
|
-
md: 'min-w-[20px] h-[20px] px-1.5 text-
|
|
49
|
-
lg: 'min-w-[22px] h-[22px] px-1.5 text-
|
|
46
|
+
xs: 'min-w-[16px] h-[16px] px-1 text-xs',
|
|
47
|
+
sm: 'min-w-[18px] h-[18px] px-1 text-xs',
|
|
48
|
+
md: 'min-w-[20px] h-[20px] px-1.5 text-xs',
|
|
49
|
+
lg: 'min-w-[22px] h-[22px] px-1.5 text-sm',
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function Badge({
|