@toolr/ui-design 0.1.4 → 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.
Files changed (70) hide show
  1. package/agent-rules.json +91 -0
  2. package/ai-manifest.json +190 -0
  3. package/components/content/info-panel-primitives.tsx +14 -14
  4. package/components/lib/ai-tools.tsx +1 -1
  5. package/components/sections/ai-tools-paths/tools-paths-panel.tsx +7 -7
  6. package/components/sections/captured-issues/captured-issues-panel.tsx +11 -11
  7. package/components/sections/golden-snapshots/file-diff-viewer.tsx +13 -13
  8. package/components/sections/golden-snapshots/golden-sync-panel.tsx +5 -5
  9. package/components/sections/golden-snapshots/snapshot-manager.tsx +11 -11
  10. package/components/sections/golden-snapshots/status-overview.tsx +20 -20
  11. package/components/sections/golden-snapshots/version-manager.tsx +8 -8
  12. package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +4 -4
  13. package/components/sections/prompt-editor/simulator-prompt-editor.tsx +5 -5
  14. package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +10 -10
  15. package/components/sections/report-bug/report-bug-form.tsx +14 -14
  16. package/components/sections/report-bug/screenshot-uploader.tsx +6 -6
  17. package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +3 -3
  18. package/components/sections/snapshot-browser/snapshot-tree.tsx +8 -8
  19. package/components/sections/snippets-editor/snippets-editor.tsx +81 -22
  20. package/components/settings/SettingsHeader.tsx +1 -1
  21. package/components/settings/SettingsTreeNav.tsx +22 -4
  22. package/components/ui/action-dialog.tsx +5 -5
  23. package/components/ui/badge.tsx +4 -4
  24. package/components/ui/bottom-panel-header.tsx +4 -4
  25. package/components/ui/breadcrumb.tsx +2 -2
  26. package/components/ui/collapsible-section.tsx +1 -1
  27. package/components/ui/cookie-consent.tsx +5 -5
  28. package/components/ui/detail-section.tsx +3 -3
  29. package/components/ui/editor-placeholder-card.tsx +7 -7
  30. package/components/ui/editor-toolbar.tsx +12 -0
  31. package/components/ui/execution-details-panel.tsx +6 -6
  32. package/components/ui/extension-list-card.tsx +3 -3
  33. package/components/ui/file-structure-section.tsx +17 -17
  34. package/components/ui/file-tree.tsx +3 -1
  35. package/components/ui/files-panel.tsx +27 -9
  36. package/components/ui/filter-dropdown.tsx +5 -5
  37. package/components/ui/form-actions.tsx +1 -1
  38. package/components/ui/frontmatter-form-header.tsx +4 -4
  39. package/components/ui/icon-button.tsx +1 -1
  40. package/components/ui/input.tsx +7 -7
  41. package/components/ui/label.tsx +4 -4
  42. package/components/ui/layout-tab-bar.tsx +4 -4
  43. package/components/ui/modal.tsx +2 -2
  44. package/components/ui/nav-card.tsx +18 -11
  45. package/components/ui/navigation-bar.tsx +5 -5
  46. package/components/ui/number-input.tsx +4 -4
  47. package/components/ui/registry-browser.tsx +6 -6
  48. package/components/ui/registry-card.tsx +13 -13
  49. package/components/ui/registry-detail.tsx +6 -6
  50. package/components/ui/segmented-toggle.tsx +4 -4
  51. package/components/ui/select.tsx +5 -5
  52. package/components/ui/selection-grid.tsx +4 -4
  53. package/components/ui/setting-row.tsx +1 -1
  54. package/components/ui/settings-card.tsx +3 -3
  55. package/components/ui/settings-info-box.tsx +1 -1
  56. package/components/ui/settings-section-title.tsx +1 -1
  57. package/components/ui/snapshot-card.tsx +7 -7
  58. package/components/ui/snippets-panel.tsx +10 -10
  59. package/components/ui/sort-dropdown.tsx +2 -2
  60. package/components/ui/status-card.tsx +4 -4
  61. package/components/ui/tab-bar.tsx +2 -2
  62. package/components/ui/tooltip.tsx +3 -3
  63. package/dist/content.js +14 -14
  64. package/dist/index.d.ts +24 -7
  65. package/dist/index.js +440 -346
  66. package/dist/tokens/primitives.css +9 -2
  67. package/dist/tokens/semantic.css +1 -1
  68. package/package.json +13 -3
  69. package/tokens/primitives.css +9 -2
  70. package/tokens/semantic.css +1 -1
@@ -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-sm font-medium text-neutral-200">Report a Bug</h3>
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-xs text-neutral-400">Issue Type</label>
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-xs font-medium rounded-md transition-all',
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-xs text-neutral-400">
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-xs text-neutral-400">
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-sm text-neutral-200 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none min-h-[120px]"
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-xs text-neutral-400">Email (optional)</label>
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-xs text-neutral-400">
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-sm text-neutral-400 cursor-pointer select-none"
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-xs font-medium text-neutral-400">Captured Errors</span>
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-xs">
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-xs text-neutral-400 mr-auto">{submissionStatus}</span>
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-sm text-neutral-400 transition-colors hover:bg-neutral-700 hover:text-neutral-200 disabled:opacity-50"
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-sm text-white transition-colors hover:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50"
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-sm text-neutral-400">
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-xs text-neutral-500 mt-1">
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-sm text-red-400">
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-xs text-white truncate">{s.filename}</span>
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-xs text-neutral-400">
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-xs text-neutral-500">
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-sm text-neutral-500">
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-sm text-neutral-500">
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-sm text-neutral-500 space-y-2">
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-sm rounded-md group transition-colors hover:bg-neutral-700/50 text-neutral-400"
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-xs flex-1 truncate">
201
+ <span className="text-sm flex-1 truncate">
202
202
  {searchQuery ? highlightMatch(displayName, searchQuery) : displayName}
203
203
  </span>
204
- <span className="text-xss text-neutral-500 shrink-0" title={formatFullDate(entry.savedAt)}>
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-sm rounded-md transition-colors cursor-pointer text-neutral-400 hover:bg-neutral-700/50 hover:text-neutral-300"
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-xs text-neutral-500 bg-neutral-700 px-1.5 py-0.5 rounded shrink-0">
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-sm text-neutral-500 py-8 text-center', className)}>
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-xs">Use the camera button in editors to save snapshots.</span>
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-xs text-neutral-500 text-center py-4">
380
+ <p className="text-sm text-neutral-500 text-center py-4">
381
381
  No snapshots match &ldquo;{searchQuery}&rdquo;
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-sm font-medium text-neutral-300">{title}</h3>
107
- <span className="px-2 py-0.5 text-xs rounded-full bg-neutral-700 text-neutral-400">
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-xs text-neutral-500 hidden sm:block">{description}</p>
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-xs text-neutral-500 mb-1">
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-xss text-neutral-600">
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="w-1 cursor-col-resize bg-transparent hover:bg-blue-500/30 transition-colors flex-shrink-0"
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-sm text-neutral-500 mb-2">Select a snippet to edit</p>
190
- <p className="text-xs text-neutral-600 leading-relaxed">
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="text-blue-400">+</span> to create a new one.
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
- ? 'bg-neutral-850 border-l-blue-400'
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-xs font-mono font-medium text-neutral-300 truncate">
285
+ <p className="text-sm font-mono font-medium text-neutral-300 truncate">
229
286
  {snippet.name}
230
287
  </p>
231
- <p className="text-xss text-neutral-500 truncate mt-0.5">
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-xss text-neutral-600 truncate mt-0.5 font-mono">
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-xs text-neutral-500 mb-1.5">
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-xss text-neutral-600">
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-xs text-neutral-500 mb-1.5">
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-xs text-neutral-500 mb-1.5">Value</label>
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-xss text-neutral-600">
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-xs text-red-400">{formError}</p>
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-xs text-neutral-400 transition-colors hover:bg-neutral-700 hover:text-neutral-300 disabled:opacity-50"
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="flex items-center gap-1.5 rounded-md bg-blue-600 px-3 py-1.5 text-xs text-white transition-colors hover:bg-blue-500 disabled:cursor-not-allowed disabled:opacity-50"
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-sm text-neutral-400 leading-relaxed">{description}</p>
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-sm rounded-md transition-colors cursor-pointer
76
- ${isSelected ? 'bg-blue-500/20 text-blue-400' : isInSelectedPath ? 'text-neutral-300' : 'text-neutral-400'}
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-xs text-neutral-500 text-center py-4 px-2">
252
+ <p className="text-sm text-neutral-500 text-center py-4 px-2">
236
253
  No settings match &quot;{searchQuery}&quot;
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-sm font-semibold text-neutral-200">
214
+ <span className="text-md font-semibold text-neutral-200">
215
215
  {title}
216
216
  </span>
217
217
  {subtitle && (
218
- <span className="text-xs text-neutral-500">{subtitle}</span>
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-xs text-neutral-500 mb-2">{selectionLabel}</div>
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-xs text-neutral-500">{scenarioLabel}</span>
257
+ <span className="text-sm text-neutral-500">{scenarioLabel}</span>
258
258
  <button
259
259
  type="button"
260
260
  onClick={handleSelectAllScenarios}
261
- className="text-xs text-blue-400 hover:text-blue-300 transition-colors cursor-pointer"
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>
@@ -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-xss',
47
- sm: 'min-w-[18px] h-[18px] px-1 text-xss',
48
- md: 'min-w-[20px] h-[20px] px-1.5 text-xss',
49
- lg: 'min-w-[22px] h-[22px] px-1.5 text-xs',
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({