@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.
Files changed (68) 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 +7 -7
  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 +5 -5
  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 +3 -3
  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 +4 -4
  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 +11 -4
  65. package/dist/index.js +428 -336
  66. package/dist/tokens/primitives.css +9 -2
  67. package/package.json +13 -3
  68. package/tokens/primitives.css +9 -2
@@ -70,7 +70,7 @@ type LayoutMode = 'full' | 'compact-banner' | 'compact-all'
70
70
 
71
71
  // Width estimates for layout calculation
72
72
  const TAB_ICON_PADDING = 56 // icon(16) + gap(8) + px-4(32)
73
- const CHAR_WIDTH = 7.5 // approximate char width at text-sm
73
+ const CHAR_WIDTH = 7.5 // approximate char width at text-md
74
74
  const COUNT_BADGE_WIDTH = 40 // badge with count
75
75
  const BANNER_FULL_WIDTH = 200 // icon + text + padding
76
76
  const BANNER_COMPACT_WIDTH = 36 // icon only
@@ -163,7 +163,7 @@ export function BottomPanelHeader<T extends string = string>({
163
163
  key={tab.id}
164
164
  onClick={() => onTabChange(tab.id)}
165
165
  data-testid={tab.testId}
166
- className={`h-[41px] flex items-center justify-center gap-2 ${compactTabs ? 'px-3' : 'px-4'} text-sm border-b-2 transition-colors cursor-pointer ${baseClasses}`}
166
+ className={`h-[41px] flex items-center justify-center gap-2 ${compactTabs ? 'px-3' : 'px-4'} text-md border-b-2 transition-colors cursor-pointer ${baseClasses}`}
167
167
  >
168
168
  {compactTabs ? (
169
169
  <span className="relative flex items-center justify-center w-[18px] h-[18px] flex-shrink-0">
@@ -209,12 +209,12 @@ export function BottomPanelHeader<T extends string = string>({
209
209
  {statusBanner && (
210
210
  compactBanner ? (
211
211
  <Tooltip content={{ description: statusBanner.message }} position="bottom">
212
- <div className={`flex items-center px-2 py-1.5 ${bannerStyles} rounded text-xs`}>
212
+ <div className={`flex items-center px-2 py-1.5 ${bannerStyles} rounded text-sm`}>
213
213
  <RefreshCw className="w-3 h-3 flex-shrink-0" />
214
214
  </div>
215
215
  </Tooltip>
216
216
  ) : (
217
- <div className={`flex items-center gap-2 px-2.5 py-1.5 ${bannerStyles} rounded text-xs max-w-full`}>
217
+ <div className={`flex items-center gap-2 px-2.5 py-1.5 ${bannerStyles} rounded text-sm max-w-full`}>
218
218
  <RefreshCw className="w-3 h-3 flex-shrink-0" />
219
219
  <span className="truncate">{statusBanner.message}</span>
220
220
  </div>
@@ -67,8 +67,8 @@ export interface BreadcrumbProps {
67
67
 
68
68
  const sizeConfig = {
69
69
  xss: { text: 'text-xss', icon: 'w-2.5 h-2.5', px: 'px-1', py: 'py-0.5', gap: 'gap-0.5', sep: 'w-2 h-2' },
70
- xs: { text: 'text-xs', icon: 'w-3 h-3', px: 'px-1.5', py: 'py-0.5', gap: 'gap-1', sep: 'w-2.5 h-2.5' },
71
- sm: { text: 'text-sm', icon: 'w-3.5 h-3.5', px: 'px-2', py: 'py-1', gap: 'gap-1.5', sep: 'w-3 h-3' },
70
+ xs: { text: 'text-sm', icon: 'w-3 h-3', px: 'px-1.5', py: 'py-0.5', gap: 'gap-1', sep: 'w-2.5 h-2.5' },
71
+ sm: { text: 'text-md', icon: 'w-3.5 h-3.5', px: 'px-2', py: 'py-1', gap: 'gap-1.5', sep: 'w-3 h-3' },
72
72
  md: { text: 'text-base', icon: 'w-4 h-4', px: 'px-2.5', py: 'py-1', gap: 'gap-1.5', sep: 'w-3.5 h-3.5' },
73
73
  lg: { text: 'text-lg', icon: 'w-5 h-5', px: 'px-3', py: 'py-1.5', gap: 'gap-2', sep: 'w-4 h-4' },
74
74
  }
@@ -87,7 +87,7 @@ export function CollapsibleSection({
87
87
  <Icon className="w-3.5 h-3.5" />
88
88
  </span>
89
89
  )}
90
- <span className="text-sm font-medium text-neutral-200">{title}</span>
90
+ <span className="text-md font-medium text-neutral-200">{title}</span>
91
91
  {badge !== undefined && (
92
92
  <span className="ml-auto">
93
93
  <Badge value={badge} color={badgeColor} size="xss" />
@@ -42,26 +42,26 @@ export function CookieConsent({
42
42
  <div className="fixed bottom-0 left-0 right-0 z-50 p-4 bg-neutral-900/95 backdrop-blur-sm border-t border-neutral-700/50">
43
43
  <div className="max-w-6xl mx-auto flex flex-col sm:flex-row items-start sm:items-center gap-4">
44
44
  <div className="flex-grow">
45
- <p className="text-sm text-neutral-200 mb-1">{heading}</p>
46
- <p className="text-xs text-neutral-400">{description}</p>
45
+ <p className="text-md text-neutral-200 mb-1">{heading}</p>
46
+ <p className="text-sm text-neutral-400">{description}</p>
47
47
  </div>
48
48
 
49
49
  <div className="flex items-center gap-2 flex-shrink-0">
50
50
  <button
51
51
  onClick={() => handleConsent('declined')}
52
- className="px-3 py-1.5 text-sm h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-neutral-400 border border-transparent hover:text-neutral-200 hover:border-neutral-600 hover:bg-neutral-800 transition-colors"
52
+ className="px-3 py-1.5 text-md h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-neutral-400 border border-transparent hover:text-neutral-200 hover:border-neutral-600 hover:bg-neutral-800 transition-colors"
53
53
  >
54
54
  Decline
55
55
  </button>
56
56
  <button
57
57
  onClick={() => handleConsent('essential')}
58
- className="px-3 py-1.5 text-sm h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-neutral-400 border border-transparent hover:text-neutral-200 hover:border-neutral-600 hover:bg-neutral-800 transition-colors"
58
+ className="px-3 py-1.5 text-md h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-neutral-400 border border-transparent hover:text-neutral-200 hover:border-neutral-600 hover:bg-neutral-800 transition-colors"
59
59
  >
60
60
  Essential Only
61
61
  </button>
62
62
  <button
63
63
  onClick={() => handleConsent('accepted')}
64
- className={`px-3 py-1.5 text-sm h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-white border transition-colors bg-${accentColor}-600 border-${accentColor}-500 hover:bg-${accentColor}-500`}
64
+ className={`px-3 py-1.5 text-md h-[26px] inline-flex items-center justify-center font-medium rounded-md cursor-pointer text-white border transition-colors bg-${accentColor}-600 border-${accentColor}-500 hover:bg-${accentColor}-500`}
65
65
  >
66
66
  Accept All
67
67
  </button>
@@ -50,13 +50,13 @@ export function DetailSection({ title, icon, rows, className }: DetailSectionPro
50
50
  <div className={className}>
51
51
  <div className="flex items-center gap-2 mb-3">
52
52
  {Icon && <Icon className="w-4 h-4 text-neutral-500" />}
53
- <span className="text-sm font-medium text-neutral-400">{title}</span>
53
+ <span className="text-md font-medium text-neutral-400">{title}</span>
54
54
  </div>
55
55
  <div className="space-y-2">
56
56
  {rows.map((row) => (
57
57
  <div key={row.label} className="flex items-start gap-3">
58
- <span className="text-xs text-neutral-500 w-24 shrink-0">{row.label}:</span>
59
- <span className={cn('text-xs text-neutral-400', row.mono && 'font-mono')}>
58
+ <span className="text-sm text-neutral-500 w-24 shrink-0">{row.label}:</span>
59
+ <span className={cn('text-sm text-neutral-400', row.mono && 'font-mono')}>
60
60
  {row.value}
61
61
  </span>
62
62
  </div>
@@ -102,17 +102,17 @@ export function EditorPlaceholderCard({
102
102
  <div className="flex items-start justify-between gap-2">
103
103
  <div className="flex-1 min-w-0">
104
104
  {/* Placeholder name with {{ }} */}
105
- <code className={`text-xs font-mono px-1.5 py-0.5 rounded ${colors.name} ${colors.nameBg}`}>
105
+ <code className={`text-sm font-mono px-1.5 py-0.5 rounded ${colors.name} ${colors.nameBg}`}>
106
106
  {'{{' + name + '}}'}
107
107
  </code>
108
108
  {/* Required badge */}
109
109
  {required && (
110
- <span className="ml-2 inline-block px-1.5 py-0.5 text-xs font-semibold uppercase bg-red-500/15 text-red-400 border border-red-500/30 rounded">
110
+ <span className="ml-2 inline-block px-1.5 py-0.5 text-sm font-semibold uppercase bg-red-500/15 text-red-400 border border-red-500/30 rounded">
111
111
  Required
112
112
  </span>
113
113
  )}
114
114
  {/* Description */}
115
- <p className="text-xs text-neutral-500 mt-1.5 line-clamp-2">{description}</p>
115
+ <p className="text-sm text-neutral-500 mt-1.5 line-clamp-2">{description}</p>
116
116
  </div>
117
117
 
118
118
  {/* Actions (copy for templates, edit/delete for settings) */}
@@ -146,7 +146,7 @@ export function EditorPlaceholderCard({
146
146
  <div className="mt-2">
147
147
  {hideValue ? (
148
148
  <>
149
- <span className="text-xs text-neutral-500 font-medium">{valueLabel}</span>
149
+ <span className="text-sm text-neutral-500 font-medium">{valueLabel}</span>
150
150
  <div className="mt-1.5">
151
151
  <Input
152
152
  type="password"
@@ -163,7 +163,7 @@ export function EditorPlaceholderCard({
163
163
  ) : (
164
164
  <>
165
165
  <div className="flex items-center justify-between">
166
- <span className="text-xs text-neutral-500 font-medium">{valueLabel}</span>
166
+ <span className="text-sm text-neutral-500 font-medium">{valueLabel}</span>
167
167
  {(isOverflowing || isExpanded) && (
168
168
  <IconButton
169
169
  icon={isExpanded ? 'chevron-up' : 'chevron-down'}
@@ -175,7 +175,7 @@ export function EditorPlaceholderCard({
175
175
  </div>
176
176
  <div
177
177
  ref={valueRef}
178
- className={`mt-1.5 px-2 py-1.5 bg-neutral-800/50 rounded text-xs text-neutral-400 font-mono ${
178
+ className={`mt-1.5 px-2 py-1.5 bg-neutral-800/50 rounded text-sm text-neutral-400 font-mono ${
179
179
  isExpanded
180
180
  ? 'whitespace-pre-wrap break-all max-h-[190px] overflow-y-auto'
181
181
  : 'truncate'
@@ -190,7 +190,7 @@ export function EditorPlaceholderCard({
190
190
 
191
191
  {/* No value hint */}
192
192
  {!hasValue && (
193
- <p className="mt-1.5 text-xs text-neutral-600 italic">No value set - add one in Settings</p>
193
+ <p className="mt-1.5 text-sm text-neutral-600 italic">No value set - add one in Settings</p>
194
194
  )}
195
195
  </div>
196
196
  )
@@ -4,6 +4,10 @@ import { Label } from './label.tsx'
4
4
  import { ConfirmModal } from './modal.tsx'
5
5
 
6
6
  export interface EditorToolbarProps {
7
+ /** Optional title displayed in the toolbar */
8
+ title?: string
9
+ /** Optional description displayed below the title */
10
+ description?: string
7
11
  /** Whether content has unsaved changes */
8
12
  isDirty: boolean
9
13
  /** Whether save operation is in progress */
@@ -30,6 +34,8 @@ export interface EditorToolbarProps {
30
34
  }
31
35
 
32
36
  export function EditorToolbar({
37
+ title,
38
+ description,
33
39
  isDirty,
34
40
  isSaving = false,
35
41
  onSave,
@@ -66,6 +72,12 @@ export function EditorToolbar({
66
72
  <div className="flex items-center justify-between px-4 py-1.5 bg-neutral-900 border-b border-neutral-800">
67
73
  {/* Left side */}
68
74
  <div className="flex items-center gap-2">
75
+ {(title || description) && (
76
+ <div className="flex flex-col mr-2">
77
+ {title && <span className="text-sm font-medium text-neutral-200">{title}</span>}
78
+ {description && <span className="text-xs text-neutral-500">{description}</span>}
79
+ </div>
80
+ )}
69
81
  {leftActions?.map((a, i) => <IconButton key={i} {...a} />)}
70
82
  </div>
71
83
 
@@ -40,7 +40,7 @@ export function ExecutionDetailsPanel({
40
40
  {/* Header */}
41
41
  <div className="flex items-center gap-2">
42
42
  <Info className="w-4 h-4 text-neutral-500" />
43
- <span className="font-medium text-neutral-400 text-sm">Execution Details</span>
43
+ <span className="font-medium text-neutral-400 text-md">Execution Details</span>
44
44
  </div>
45
45
 
46
46
  {/* Direct edits toggle */}
@@ -57,8 +57,8 @@ export function ExecutionDetailsPanel({
57
57
  />
58
58
  </div>
59
59
  <div>
60
- <span className="text-neutral-300 text-sm">Allow direct file edits</span>
61
- <p className="text-neutral-500 text-xs mt-0.5">
60
+ <span className="text-neutral-300 text-md">Allow direct file edits</span>
61
+ <p className="text-neutral-500 text-sm mt-0.5">
62
62
  {allowDirectEdits
63
63
  ? 'AI will modify files directly. Changes saved immediately.'
64
64
  : 'Changes will be shown in editor for review.'}
@@ -72,7 +72,7 @@ export function ExecutionDetailsPanel({
72
72
  <div className="rounded border border-red-500/50 bg-red-500/10 p-2">
73
73
  <div className="flex items-start gap-2">
74
74
  <AlertTriangle className="h-4 w-4 text-red-400 shrink-0 mt-0.5" />
75
- <p className="text-red-300 text-xs">{warningMessage}</p>
75
+ <p className="text-red-300 text-sm">{warningMessage}</p>
76
76
  </div>
77
77
  </div>
78
78
  )}
@@ -82,8 +82,8 @@ export function ExecutionDetailsPanel({
82
82
  <div className="space-y-2">
83
83
  {details.map((row) => (
84
84
  <div key={row.label} className="flex items-start gap-3">
85
- <span className="text-neutral-500 text-xs w-24 shrink-0">{row.label}:</span>
86
- <span className={cn('text-neutral-300 text-xs', row.mono && 'font-mono')}>{row.value}</span>
85
+ <span className="text-neutral-500 text-sm w-24 shrink-0">{row.label}:</span>
86
+ <span className={cn('text-neutral-300 text-sm', row.mono && 'font-mono')}>{row.value}</span>
87
87
  </div>
88
88
  ))}
89
89
  </div>
@@ -81,11 +81,11 @@ export const ExtensionListCard = memo(function ExtensionListCard({
81
81
  <Icon className={cn('w-5 h-5 shrink-0', iconColor)} />
82
82
  <div className="min-w-0 flex-1">
83
83
  <div className="flex items-center gap-2 flex-wrap">
84
- <span className={cn('text-sm font-medium', titleClassName)}>{title}</span>
84
+ <span className={cn('text-md font-medium', titleClassName)}>{title}</span>
85
85
  {badges}
86
86
  </div>
87
87
  {description && (
88
- <div className={cn('text-xs text-neutral-500 mt-1', !isHovered && 'line-clamp-2')}>{description}</div>
88
+ <div className={cn('text-sm text-neutral-500 mt-1', !isHovered && 'line-clamp-2')}>{description}</div>
89
89
  )}
90
90
  </div>
91
91
  </div>
@@ -96,7 +96,7 @@ export const ExtensionListCard = memo(function ExtensionListCard({
96
96
  )}
97
97
  </div>
98
98
  {metadata != null && (
99
- <div className="flex items-center justify-between mt-2 ml-8 mr-2 text-xs text-neutral-500">
99
+ <div className="flex items-center justify-between mt-2 ml-8 mr-2 text-sm text-neutral-500">
100
100
  {typeof metadata === 'function' ? metadata(isHovered) : metadata}
101
101
  </div>
102
102
  )}
@@ -89,7 +89,7 @@ function renderMarkdownContent(content: string) {
89
89
  while (i < lines.length && lines[i] !== '---') { fmLines.push(lines[i]); i++ }
90
90
  i++ // skip closing ---
91
91
  nodes.push(
92
- <div key="fm" className="mb-3 font-mono text-xss text-neutral-500 border-l-2 border-neutral-700 pl-2 py-0.5">
92
+ <div key="fm" className="mb-3 font-mono text-xs text-neutral-500 border-l-2 border-neutral-700 pl-2 py-0.5">
93
93
  <div className="text-neutral-600">---</div>
94
94
  {fmLines.map((l, j) => <div key={j}>{l}</div>)}
95
95
  <div className="text-neutral-600">---</div>
@@ -104,20 +104,20 @@ function renderMarkdownContent(content: string) {
104
104
  i++
105
105
  while (i < lines.length && !lines[i].startsWith('```')) { codeLines.push(lines[i]); i++ }
106
106
  nodes.push(
107
- <pre key={i} className="mb-2 p-2 bg-[var(--background)]/30 rounded text-xss font-mono text-neutral-300 overflow-x-auto">
107
+ <pre key={i} className="mb-2 p-2 bg-[var(--background)]/30 rounded text-xs font-mono text-neutral-300 overflow-x-auto">
108
108
  {codeLines.join('\n')}
109
109
  </pre>
110
110
  )
111
111
  } else if (line.startsWith('### ')) {
112
- nodes.push(<h3 key={i} className="text-xss font-semibold text-neutral-300 mt-2 mb-0.5">{line.slice(4)}</h3>)
112
+ nodes.push(<h3 key={i} className="text-xs font-semibold text-neutral-300 mt-2 mb-0.5">{line.slice(4)}</h3>)
113
113
  } else if (line.startsWith('## ')) {
114
- nodes.push(<h2 key={i} className="text-xs font-semibold text-neutral-200 mt-2.5 mb-1">{line.slice(3)}</h2>)
114
+ nodes.push(<h2 key={i} className="text-sm font-semibold text-neutral-200 mt-2.5 mb-1">{line.slice(3)}</h2>)
115
115
  } else if (line.startsWith('# ')) {
116
- nodes.push(<h1 key={i} className="text-sm font-semibold text-neutral-100 mb-1.5">{line.slice(2)}</h1>)
116
+ nodes.push(<h1 key={i} className="text-md font-semibold text-neutral-100 mb-1.5">{line.slice(2)}</h1>)
117
117
  } else if (line === '' || line === '\r') {
118
118
  nodes.push(<div key={i} className="h-1.5" />)
119
119
  } else {
120
- nodes.push(<p key={i} className="text-xss text-neutral-400 leading-relaxed">{line}</p>)
120
+ nodes.push(<p key={i} className="text-xs text-neutral-400 leading-relaxed">{line}</p>)
121
121
  }
122
122
  i++
123
123
  }
@@ -302,8 +302,8 @@ export function FileStructureSection({
302
302
  if (isLoading) {
303
303
  return (
304
304
  <div>
305
- <h3 className="text-xs font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
306
- <div className="flex items-center gap-2 text-xs text-neutral-500 py-4">
305
+ <h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
306
+ <div className="flex items-center gap-2 text-sm text-neutral-500 py-4">
307
307
  <Loader2 className="w-3.5 h-3.5 animate-spin" />
308
308
  Loading file tree...
309
309
  </div>
@@ -318,8 +318,8 @@ export function FileStructureSection({
318
318
  if (error) {
319
319
  return (
320
320
  <div>
321
- <h3 className="text-xs font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
322
- <div className="flex items-center gap-2 text-xs text-red-400 py-4">
321
+ <h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
322
+ <div className="flex items-center gap-2 text-sm text-red-400 py-4">
323
323
  <AlertCircle className="w-3.5 h-3.5 shrink-0" />
324
324
  {error}
325
325
  </div>
@@ -336,7 +336,7 @@ export function FileStructureSection({
336
336
  if (mode === 'format') return renderMarkdownContent(content)
337
337
  if (mode === 'language' && renderPreview) return renderPreview(content, filePath, resolvedLanguage)
338
338
  return (
339
- <pre className="p-3 text-xs font-mono text-white leading-relaxed whitespace-pre-wrap">
339
+ <pre className="p-3 text-sm font-mono text-white leading-relaxed whitespace-pre-wrap">
340
340
  <code>{content}</code>
341
341
  </pre>
342
342
  )
@@ -346,7 +346,7 @@ export function FileStructureSection({
346
346
  <div className={`flex flex-col bg-neutral-900 border ${ACCENT_BORDER[accentColor]} rounded-lg overflow-hidden ${variant === 'split' && effectiveFilePath ? 'w-1/3 shrink-0' : 'flex-1'}`}>
347
347
  <div className={`flex items-center px-3 py-2 border-b ${ACCENT_BORDER[accentColor]} shrink-0 gap-2 min-w-0`}>
348
348
  <FolderTree className={`w-3.5 h-3.5 shrink-0 ${ACCENT_ICON[accentColor]}`} />
349
- <span className="text-xs text-neutral-200 truncate flex-1">Files</span>
349
+ <span className="text-sm text-neutral-200 truncate flex-1">Files</span>
350
350
  <CollapseButton
351
351
  collapsed={allCollapsed}
352
352
  onToggle={() => setExpandedPaths(allCollapsed ? new Set(allDirPaths) : new Set())}
@@ -371,7 +371,7 @@ export function FileStructureSection({
371
371
  <div className={`flex-1 flex flex-col bg-neutral-900 border ${ACCENT_BORDER[accentColor]} rounded-lg overflow-hidden`}>
372
372
  <div className={`flex items-center px-3 py-2 border-b ${ACCENT_BORDER[accentColor]} shrink-0 gap-2 min-w-0`}>
373
373
  <FileCode className={`w-3.5 h-3.5 shrink-0 ${ACCENT_ICON[accentColor]}`} />
374
- <span className="text-xs text-neutral-200 truncate flex-1">{selectedFileName}</span>
374
+ <span className="text-sm text-neutral-200 truncate flex-1">{selectedFileName}</span>
375
375
  {showToggle && (
376
376
  <SegmentedToggle
377
377
  options={toggleOptions}
@@ -384,12 +384,12 @@ export function FileStructureSection({
384
384
  </div>
385
385
  <div className="flex-1 overflow-auto">
386
386
  {fileIsLoading ? (
387
- <div className="flex items-center gap-2 text-xs text-neutral-500 p-3">
387
+ <div className="flex items-center gap-2 text-sm text-neutral-500 p-3">
388
388
  <Loader2 className="w-3.5 h-3.5 animate-spin" />
389
389
  Loading...
390
390
  </div>
391
391
  ) : fileError ? (
392
- <p className="text-xs text-red-400 p-3">{fileError}</p>
392
+ <p className="text-sm text-red-400 p-3">{fileError}</p>
393
393
  ) : fileContent !== null ? (
394
394
  renderContent(fileContent, effectiveFilePath)
395
395
  ) : null}
@@ -409,7 +409,7 @@ export function FileStructureSection({
409
409
  if (variant === 'list') {
410
410
  return (
411
411
  <div ref={sectionRef}>
412
- <h3 className="text-xs font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
412
+ <h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
413
413
  <div className="space-y-3">
414
414
  {treePanel}
415
415
  {previewPanel && (
@@ -427,7 +427,7 @@ export function FileStructureSection({
427
427
 
428
428
  return (
429
429
  <div ref={sectionRef}>
430
- <h3 className="text-xs font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
430
+ <h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-2">File Structure</h3>
431
431
  <div className="flex gap-3" style={{ height: `${effectiveHeight}px` }}>
432
432
  {treePanel}
433
433
  {previewPanel}
@@ -27,6 +27,7 @@ const ACCENT_SELECTED: Record<string, string> = {
27
27
  emerald: 'bg-emerald-400/20 text-neutral-200',
28
28
  teal: 'bg-teal-400/20 text-neutral-200',
29
29
  sky: 'bg-sky-400/20 text-neutral-200',
30
+ violet: 'bg-violet-400/20 text-neutral-200',
30
31
  }
31
32
 
32
33
  const ACCENT_ICON: Record<string, string> = {
@@ -39,6 +40,7 @@ const ACCENT_ICON: Record<string, string> = {
39
40
  emerald: 'text-emerald-400',
40
41
  teal: 'text-teal-400',
41
42
  sky: 'text-sky-400',
43
+ violet: 'text-violet-400',
42
44
  }
43
45
 
44
46
  function nodeHasFiles(node: FileTreeNode): boolean {
@@ -120,7 +122,7 @@ function FileTreeNodeItem({ node, path, selectedPath, onSelectFile, expandedPath
120
122
  const isDir = node.type === 'directory'
121
123
  const isSelected = !isDir && selectedPath === path
122
124
  const expanded = isDir && expandedPaths.has(path)
123
- const base = 'flex items-center gap-1.5 py-0.5 px-1 rounded text-xs transition-colors overflow-hidden whitespace-nowrap'
125
+ const base = 'flex items-center gap-1.5 py-0.5 px-1 rounded text-sm transition-colors overflow-hidden whitespace-nowrap'
124
126
  const selectedClass = ACCENT_SELECTED[accentColor] ?? ACCENT_SELECTED.blue
125
127
  const iconColorClass = ACCENT_ICON[accentColor] ?? ACCENT_ICON.blue
126
128
  const rowClass = isSelected
@@ -6,6 +6,19 @@ import type { LucideIcon } from 'lucide-react'
6
6
  import type { IconName } from './icon-button.tsx'
7
7
  import { cn } from '../lib/cn.ts'
8
8
 
9
+ const ACCENT_SELECTED: Record<string, string> = {
10
+ blue: 'bg-blue-400/15 text-blue-400',
11
+ purple: 'bg-purple-400/15 text-purple-400',
12
+ orange: 'bg-orange-400/15 text-orange-400',
13
+ green: 'bg-green-400/15 text-green-400',
14
+ pink: 'bg-pink-400/15 text-pink-400',
15
+ amber: 'bg-amber-400/15 text-amber-400',
16
+ emerald: 'bg-emerald-400/15 text-emerald-400',
17
+ teal: 'bg-teal-400/15 text-teal-400',
18
+ sky: 'bg-sky-400/15 text-sky-400',
19
+ violet: 'bg-violet-400/15 text-violet-400',
20
+ }
21
+
9
22
  const iconSubset: Partial<Record<IconName, LucideIcon>> = {
10
23
  folder: Folder,
11
24
  file: File,
@@ -48,6 +61,7 @@ export interface FilesPanelProps {
48
61
  onAction?: (action: string, path: string) => void
49
62
  showSearch?: boolean
50
63
  className?: string
64
+ accentColor?: string
51
65
  }
52
66
 
53
67
  function collectAllFolderPaths(entries: FileEntry[]): Set<string> {
@@ -110,9 +124,10 @@ interface FileNodeProps {
110
124
  onToggleExpand: (path: string) => void
111
125
  onSelect?: (path: string) => void
112
126
  onAction?: (action: string, path: string) => void
127
+ accentColor: string
113
128
  }
114
129
 
115
- function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, onSelect, onAction }: FileNodeProps) {
130
+ function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, onSelect, onAction, accentColor }: FileNodeProps) {
116
131
  const isFolder = entry.type === 'folder'
117
132
  const isExpanded = isFolder && expandedPaths.has(entry.path)
118
133
  const isSelected = !isFolder && selectedPath === entry.path
@@ -124,9 +139,9 @@ function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, o
124
139
  type="button"
125
140
  onClick={isFolder ? () => onToggleExpand(entry.path) : () => onSelect?.(entry.path)}
126
141
  className={cn(
127
- 'group flex items-center gap-1.5 w-full py-1 px-2 rounded text-xs transition-colors cursor-pointer',
142
+ 'group flex items-center gap-1.5 w-full py-1 px-2 rounded text-sm transition-colors cursor-pointer',
128
143
  isSelected
129
- ? 'bg-blue-400/15 text-blue-400'
144
+ ? ACCENT_SELECTED[accentColor] ?? ACCENT_SELECTED.blue
130
145
  : 'text-neutral-400 hover:bg-neutral-700/40 hover:text-neutral-200',
131
146
  )}
132
147
  style={{ paddingLeft: `${depth * 16 + 8}px` }}
@@ -144,7 +159,7 @@ function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, o
144
159
  />
145
160
  <span className="truncate">{entry.name}</span>
146
161
  {entry.badge && (
147
- <span className="ml-auto shrink-0 px-1.5 py-0.5 text-xss rounded bg-neutral-700 text-neutral-500">
162
+ <span className="ml-auto shrink-0 px-1.5 py-0.5 text-xs rounded bg-neutral-700 text-neutral-500">
148
163
  {entry.badge}
149
164
  </span>
150
165
  )}
@@ -172,6 +187,7 @@ function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, o
172
187
  onToggleExpand={onToggleExpand}
173
188
  onSelect={onSelect}
174
189
  onAction={onAction}
190
+ accentColor={accentColor}
175
191
  />
176
192
  ))}
177
193
  </ul>
@@ -187,6 +203,7 @@ export function FilesPanel({
187
203
  onAction,
188
204
  showSearch = false,
189
205
  className,
206
+ accentColor = 'blue',
190
207
  }: FilesPanelProps) {
191
208
  const [expandedPaths, setExpandedPaths] = useState<Set<string>>(() => collectAllFolderPaths(files))
192
209
  const [searchQuery, setSearchQuery] = useState('')
@@ -210,19 +227,19 @@ export function FilesPanel({
210
227
  return (
211
228
  <div className={cn('flex flex-col bg-neutral-800 rounded-lg overflow-hidden', className)}>
212
229
  <div className="flex items-center justify-between px-3 py-2 border-b border-neutral-700">
213
- <span className="text-xss font-semibold uppercase tracking-wider text-neutral-500">Files</span>
214
- <span className="text-xss text-neutral-500">{fileCount} files</span>
230
+ <span className="text-xs font-semibold uppercase tracking-wider text-neutral-500">Files</span>
231
+ <span className="text-xs text-neutral-500">{fileCount} files</span>
215
232
  </div>
216
233
  {showSearch && (
217
234
  <div className="px-2 py-2 border-b border-neutral-700">
218
- <div className="flex items-center gap-1.5 px-2 py-1 bg-[var(--background)] border border-neutral-700 rounded text-xs">
235
+ <div className="flex items-center gap-1.5 px-2 py-1 bg-[var(--background)] border border-neutral-700 rounded text-sm">
219
236
  <Search className="w-3 h-3 text-neutral-500 shrink-0" />
220
237
  <input
221
238
  type="text"
222
239
  placeholder="Search files..."
223
240
  value={searchQuery}
224
241
  onChange={(e) => setSearchQuery(e.target.value)}
225
- className="flex-1 bg-transparent text-neutral-200 placeholder-neutral-500 outline-none text-xs"
242
+ className="flex-1 bg-transparent text-neutral-200 placeholder-neutral-500 outline-none text-sm"
226
243
  />
227
244
  </div>
228
245
  </div>
@@ -239,11 +256,12 @@ export function FilesPanel({
239
256
  onToggleExpand={handleToggleExpand}
240
257
  onSelect={onSelect}
241
258
  onAction={onAction}
259
+ accentColor={accentColor}
242
260
  />
243
261
  ))}
244
262
  </ul>
245
263
  {displayedFiles.length === 0 && (
246
- <p className="text-xss text-neutral-500 text-center py-4">No files found</p>
264
+ <p className="text-xs text-neutral-500 text-center py-4">No files found</p>
247
265
  )}
248
266
  </div>
249
267
  </div>
@@ -89,7 +89,7 @@ export function FilterDropdown({
89
89
  <div className="relative flex items-center" ref={ref} onKeyDown={handleKeyDown}>
90
90
  <button
91
91
  onClick={() => setIsOpen(!isOpen)}
92
- className={`flex items-center gap-1.5 h-7 px-2 rounded-md border ${v.bg} text-xs transition-colors cursor-pointer ${
92
+ className={`flex items-center gap-1.5 h-7 px-2 rounded-md border ${v.bg} text-sm transition-colors cursor-pointer ${
93
93
  isActive
94
94
  ? `${clearable ? 'rounded-r-none border-r-0' : ''} ${FORM_COLORS[color].border} text-neutral-200 ${FORM_COLORS[color].hover}`
95
95
  : isOpen
@@ -124,7 +124,7 @@ export function FilterDropdown({
124
124
  onChange={(e) => setSearch(e.target.value)}
125
125
  onKeyDown={handleKeyDown}
126
126
  placeholder="Search..."
127
- className={`w-full pl-6 pr-2 py-1 text-xs bg-[var(--popover)] border border-neutral-600 rounded text-neutral-200 placeholder-neutral-500 outline-none ${FORM_COLORS[color].focus}`}
127
+ className={`w-full pl-6 pr-2 py-1 text-sm bg-[var(--popover)] border border-neutral-600 rounded text-neutral-200 placeholder-neutral-500 outline-none ${FORM_COLORS[color].focus}`}
128
128
  />
129
129
  </div>
130
130
  </div>
@@ -133,7 +133,7 @@ export function FilterDropdown({
133
133
  <button
134
134
  data-idx={0}
135
135
  onClick={() => handleSelect('all')}
136
- className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs text-left transition-colors cursor-pointer ${
136
+ className={`w-full flex items-center gap-2 px-3 py-1.5 text-sm text-left transition-colors cursor-pointer ${
137
137
  highlightIdx === 0
138
138
  ? `${FORM_COLORS[color].selectedBg} text-neutral-200`
139
139
  : !isActive ? `${FORM_COLORS[color].selectedBg} text-neutral-200` : `text-neutral-400 ${v.hoverBg}`
@@ -152,7 +152,7 @@ export function FilterDropdown({
152
152
  key={opt.value}
153
153
  data-idx={idx}
154
154
  onClick={() => handleSelect(opt.value)}
155
- className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs text-left transition-colors cursor-pointer ${
155
+ className={`w-full flex items-center gap-2 px-3 py-1.5 text-sm text-left transition-colors cursor-pointer ${
156
156
  isHighlighted
157
157
  ? `${FORM_COLORS[color].selectedBg} text-neutral-200`
158
158
  : isSelected ? `${FORM_COLORS[color].selectedBg} text-neutral-200` : `text-neutral-400 ${v.hoverBg}`
@@ -164,7 +164,7 @@ export function FilterDropdown({
164
164
  )
165
165
  })}
166
166
  {showSearch && search && filtered.length === 0 && (
167
- <div className="px-3 py-2 text-xs text-neutral-500">No matches</div>
167
+ <div className="px-3 py-2 text-sm text-neutral-500">No matches</div>
168
168
  )}
169
169
  </div>
170
170
  )}
@@ -83,7 +83,7 @@ export function FormActions({
83
83
  tooltip={{ description: backTooltip }}
84
84
  />
85
85
  )}
86
- {statusText && <span className="text-xs text-neutral-500">{statusText}</span>}
86
+ {statusText && <span className="text-sm text-neutral-500">{statusText}</span>}
87
87
  </div>
88
88
  )}
89
89
  <div className="flex items-center gap-2">
@@ -39,16 +39,16 @@ export function FrontmatterFormHeader({
39
39
  collapsed ? '' : 'rotate-90'
40
40
  }`}
41
41
  />
42
- <span className="text-xs font-medium text-neutral-400 uppercase tracking-wide">
42
+ <span className="text-sm font-medium text-neutral-400 uppercase tracking-wide">
43
43
  Configuration
44
44
  </span>
45
45
  {collapsed && hasFm && (
46
- <span className="text-xss text-neutral-500 font-mono ml-2 truncate">
46
+ <span className="text-xs text-neutral-500 font-mono ml-2 truncate">
47
47
  {renderSummary()}
48
48
  </span>
49
49
  )}
50
50
  {collapsed && !hasFm && (
51
- <span className="text-xss text-neutral-600 ml-2">No frontmatter</span>
51
+ <span className="text-xs text-neutral-600 ml-2">No frontmatter</span>
52
52
  )}
53
53
  </button>
54
54
 
@@ -64,7 +64,7 @@ export function FrontmatterFormHeader({
64
64
  disabled={readOnly}
65
65
  />
66
66
  <span
67
- className="text-xs text-neutral-400 cursor-pointer"
67
+ className="text-sm text-neutral-400 cursor-pointer"
68
68
  onClick={() => !readOnly && onFrontmatterToggle(!hasFm)}
69
69
  >
70
70
  Add YAML frontmatter to file
@@ -323,7 +323,7 @@ export function IconButton({
323
323
  </span>
324
324
  {badge !== undefined && (
325
325
  <span
326
- className={`absolute -top-1 -right-1 min-w-[18px] h-[18px] flex items-center justify-center px-1 text-xs font-bold text-white rounded-full ${badgeColorClasses[badgeColor]}`}
326
+ className={`absolute -top-1 -right-1 min-w-[18px] h-[18px] flex items-center justify-center px-1 text-sm font-bold text-white rounded-full ${badgeColorClasses[badgeColor]}`}
327
327
  >
328
328
  {typeof badge === 'number' && badge > 99 ? '99+' : badge}
329
329
  </span>
@@ -39,10 +39,10 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
39
39
 
40
40
  const sizeClasses = {
41
41
  xss: 'px-1 py-0.5 text-xss',
42
- xs: 'px-1.5 py-0.5 text-xs',
43
- sm: 'px-2 py-1 text-xs',
44
- md: 'px-3 py-1.5 text-sm',
45
- lg: 'px-3 py-2 text-sm',
42
+ xs: 'px-1.5 py-0.5 text-sm',
43
+ sm: 'px-2 py-1 text-sm',
44
+ md: 'px-3 py-1.5 text-md',
45
+ lg: 'px-3 py-2 text-md',
46
46
  }
47
47
 
48
48
  const variantClasses = {
@@ -204,7 +204,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input({
204
204
  )}
205
205
  </div>
206
206
  {typeof error === 'string' && error && (
207
- <p className="text-xs text-red-400 mt-1 text-right">{error}</p>
207
+ <p className="text-sm text-red-400 mt-1 text-right">{error}</p>
208
208
  )}
209
209
  </div>
210
210
  )