@toolr/ui-design 0.1.5 → 0.1.7
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/hooks/use-click-outside.ts +10 -3
- package/components/hooks/use-modal-behavior.ts +24 -0
- package/components/hooks/use-navigation-history.ts +7 -2
- package/components/hooks/use-resizable-sidebar.ts +38 -0
- package/components/lib/ai-tools.tsx +1 -1
- package/components/lib/form-colors.ts +40 -0
- package/components/sections/ai-tools-paths/tools-paths-panel.tsx +7 -7
- package/components/sections/captured-issues/captured-issues-panel.tsx +13 -13
- package/components/sections/captured-issues/use-captured-issues.ts +9 -3
- 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 +8 -44
- package/components/sections/prompt-editor/index.ts +0 -7
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +9 -45
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +11 -43
- 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 +74 -48
- package/components/settings/SettingsHeader.tsx +1 -2
- package/components/settings/SettingsTreeNav.tsx +31 -16
- package/components/ui/action-dialog.tsx +12 -56
- package/components/ui/badge.tsx +8 -24
- package/components/ui/bottom-panel-header.tsx +4 -4
- package/components/ui/breadcrumb.tsx +8 -68
- package/components/ui/checkbox.tsx +2 -16
- package/components/ui/collapsible-section.tsx +4 -42
- package/components/ui/confirm-badge.tsx +3 -20
- package/components/ui/cookie-consent.tsx +21 -5
- package/components/ui/debounce-border-overlay.tsx +31 -0
- package/components/ui/detail-section.tsx +5 -22
- package/components/ui/editor-placeholder-card.tsx +17 -16
- package/components/ui/editor-toolbar.tsx +12 -0
- package/components/ui/execution-details-panel.tsx +8 -13
- package/components/ui/extension-list-card.tsx +3 -3
- package/components/ui/file-structure-section.tsx +20 -35
- package/components/ui/file-tree.tsx +4 -14
- package/components/ui/files-panel.tsx +28 -18
- package/components/ui/filter-dropdown.tsx +5 -5
- package/components/ui/form-actions.tsx +7 -6
- package/components/ui/frontmatter-form-header.tsx +4 -4
- package/components/ui/icon-button.tsx +3 -2
- package/components/ui/input.tsx +15 -31
- package/components/ui/label.tsx +7 -21
- package/components/ui/layout-tab-bar.tsx +4 -4
- package/components/ui/modal.tsx +5 -17
- package/components/ui/nav-card.tsx +5 -20
- package/components/ui/navigation-bar.tsx +13 -74
- package/components/ui/number-input.tsx +4 -4
- package/components/ui/registry-browser.tsx +10 -24
- package/components/ui/registry-card.tsx +16 -20
- package/components/ui/registry-detail.tsx +6 -6
- package/components/ui/resizable-textarea.tsx +13 -35
- package/components/ui/segmented-toggle.tsx +6 -5
- package/components/ui/select.tsx +7 -16
- package/components/ui/selection-grid.tsx +6 -54
- package/components/ui/setting-row.tsx +2 -4
- package/components/ui/settings-card.tsx +3 -3
- package/components/ui/settings-info-box.tsx +6 -23
- 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 +6 -17
- package/components/ui/tab-bar.tsx +5 -31
- package/components/ui/toggle.tsx +3 -19
- package/components/ui/tooltip.tsx +9 -21
- package/dist/content.js +14 -14
- package/dist/index.d.ts +71 -141
- package/dist/index.js +1634 -2450
- package/dist/tokens/primitives.css +9 -2
- package/index.ts +8 -7
- package/package.json +13 -3
- package/tokens/primitives.css +9 -2
- package/components/sections/prompt-editor/use-prompt-editor.ts +0 -131
|
@@ -66,7 +66,7 @@ export function ToolsPathsPanel({
|
|
|
66
66
|
<div className={cn('w-full', className)}>
|
|
67
67
|
{/* Header */}
|
|
68
68
|
<div className="flex items-center justify-between mb-4">
|
|
69
|
-
<p className="text-
|
|
69
|
+
<p className="text-sm text-neutral-500 leading-relaxed max-w-xl">
|
|
70
70
|
Configure CLI paths for AI coding assistants. Specify executable locations
|
|
71
71
|
to enable integration with your development workflow.
|
|
72
72
|
</p>
|
|
@@ -127,12 +127,12 @@ export function ToolsPathsPanel({
|
|
|
127
127
|
</div>
|
|
128
128
|
<div className="flex items-center gap-3">
|
|
129
129
|
{tool.detected ? (
|
|
130
|
-
<span className="flex items-center gap-1 text-
|
|
130
|
+
<span className="flex items-center gap-1 text-sm text-green-400">
|
|
131
131
|
<Check className="w-3.5 h-3.5" />
|
|
132
132
|
Installed
|
|
133
133
|
</span>
|
|
134
134
|
) : (
|
|
135
|
-
<span className="flex items-center gap-1 text-
|
|
135
|
+
<span className="flex items-center gap-1 text-sm text-neutral-500">
|
|
136
136
|
<X className="w-3.5 h-3.5" />
|
|
137
137
|
Not Found
|
|
138
138
|
</span>
|
|
@@ -183,15 +183,15 @@ export function ToolsPathsPanel({
|
|
|
183
183
|
|
|
184
184
|
{/* Helper text */}
|
|
185
185
|
{isEnabled && !displayPath?.includes('/') && !tool.detected && (
|
|
186
|
-
<p className="text-
|
|
186
|
+
<p className="text-sm text-red-400 pl-5">
|
|
187
187
|
Path required when enabled. Enter full path to binary.
|
|
188
188
|
</p>
|
|
189
189
|
)}
|
|
190
190
|
{tool.detected && !tool.binaryPath && (
|
|
191
|
-
<p className="text-
|
|
191
|
+
<p className="text-sm text-neutral-500 pl-5">Using auto-detected path</p>
|
|
192
192
|
)}
|
|
193
193
|
{!isEnabled && !displayPath?.includes('/') && !tool.detected && (
|
|
194
|
-
<p className="text-
|
|
194
|
+
<p className="text-sm text-neutral-500 pl-5">
|
|
195
195
|
Tool disabled. Enter path to enable.
|
|
196
196
|
</p>
|
|
197
197
|
)}
|
|
@@ -199,7 +199,7 @@ export function ToolsPathsPanel({
|
|
|
199
199
|
|
|
200
200
|
{/* Disabled warning */}
|
|
201
201
|
{tool.detected && !isEnabled && (
|
|
202
|
-
<p className="text-
|
|
202
|
+
<p className="text-sm text-yellow-500">
|
|
203
203
|
Tool disabled — enable to use in your workflow
|
|
204
204
|
</p>
|
|
205
205
|
)}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* - Dark theme with Catppuccin-like colors matching configr
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { AlertTriangle, Check, X, Send, ChevronDown,
|
|
26
|
+
import { AlertTriangle, Check, X, Send, ChevronDown, Loader2 } from 'lucide-react'
|
|
27
27
|
import { cn } from '../../lib/cn.ts'
|
|
28
28
|
import { Input } from '../../ui/input.tsx'
|
|
29
29
|
import { ResizableTextarea } from '../../ui/resizable-textarea.tsx'
|
|
@@ -75,7 +75,7 @@ export function CapturedIssuesPanel({
|
|
|
75
75
|
<div className="flex items-center justify-between">
|
|
76
76
|
<div className="flex items-center gap-2">
|
|
77
77
|
<AlertTriangle className="w-4 h-4 text-red-400" />
|
|
78
|
-
<span className="text-
|
|
78
|
+
<span className="text-md text-neutral-300">
|
|
79
79
|
{errorCount > 0 && (
|
|
80
80
|
<span className="text-red-400">
|
|
81
81
|
{errorCount} error{errorCount !== 1 ? 's' : ''}
|
|
@@ -93,10 +93,10 @@ export function CapturedIssuesPanel({
|
|
|
93
93
|
|
|
94
94
|
{/* Error List */}
|
|
95
95
|
<div className="space-y-2">
|
|
96
|
-
<p className="text-
|
|
96
|
+
<p className="text-md text-neutral-400">Captured Errors</p>
|
|
97
97
|
<div className="max-h-48 overflow-y-auto bg-neutral-950 border border-neutral-700 rounded-lg p-3 space-y-1">
|
|
98
98
|
{errors.map((error) => (
|
|
99
|
-
<div key={error.fingerprint} className="text-
|
|
99
|
+
<div key={error.fingerprint} className="text-sm font-mono break-words">
|
|
100
100
|
<span className={cn('mr-2 shrink-0', error.level === 'warning' ? 'text-yellow-400' : 'text-red-400')}>
|
|
101
101
|
{error.count > 1 ? `\u00d7${error.count}` : '\u2022'}
|
|
102
102
|
</span>
|
|
@@ -108,7 +108,7 @@ export function CapturedIssuesPanel({
|
|
|
108
108
|
|
|
109
109
|
{/* Optional Details */}
|
|
110
110
|
<div className="space-y-3">
|
|
111
|
-
<p className="text-
|
|
111
|
+
<p className="text-md text-neutral-400">Add context (optional)</p>
|
|
112
112
|
<Input
|
|
113
113
|
value={title}
|
|
114
114
|
onChange={setTitle}
|
|
@@ -119,7 +119,7 @@ export function CapturedIssuesPanel({
|
|
|
119
119
|
onChange={(e) => setDescription(e.target.value)}
|
|
120
120
|
placeholder="What were you doing when this happened?"
|
|
121
121
|
rows={3}
|
|
122
|
-
className="w-full px-3 py-1.5 bg-neutral-
|
|
122
|
+
className="w-full px-3 py-1.5 bg-neutral-800 border border-neutral-600 rounded-lg text-neutral-300 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none text-md"
|
|
123
123
|
/>
|
|
124
124
|
<Input
|
|
125
125
|
type="text"
|
|
@@ -163,8 +163,8 @@ export function CapturedIssuesPanel({
|
|
|
163
163
|
<Check className="w-5 h-5 text-green-400" />
|
|
164
164
|
</div>
|
|
165
165
|
<div>
|
|
166
|
-
<h3 className="text-
|
|
167
|
-
<p className="text-
|
|
166
|
+
<h3 className="text-md text-neutral-300 font-medium">No Issues Captured</h3>
|
|
167
|
+
<p className="text-md text-neutral-500">Everything is running smoothly.</p>
|
|
168
168
|
</div>
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
|
@@ -174,11 +174,11 @@ export function CapturedIssuesPanel({
|
|
|
174
174
|
{submittedErrors.length > 0 && (
|
|
175
175
|
<div className="bg-neutral-900 border border-neutral-700 rounded-lg overflow-hidden">
|
|
176
176
|
<details className="group">
|
|
177
|
-
<summary className="flex items-center justify-between p-4 cursor-pointer hover:bg-neutral-
|
|
177
|
+
<summary className="flex items-center justify-between p-4 cursor-pointer hover:bg-neutral-800 transition-colors">
|
|
178
178
|
<div className="flex items-center gap-2">
|
|
179
179
|
<Check className="w-4 h-4 text-green-400" />
|
|
180
|
-
<span className="text-
|
|
181
|
-
<span className="text-
|
|
180
|
+
<span className="text-md text-neutral-300">Previously Reported</span>
|
|
181
|
+
<span className="text-sm text-neutral-500">({submittedErrors.length})</span>
|
|
182
182
|
</div>
|
|
183
183
|
<ChevronDown className="w-4 h-4 text-neutral-500 transition-transform group-open:rotate-180" />
|
|
184
184
|
</summary>
|
|
@@ -191,12 +191,12 @@ export function CapturedIssuesPanel({
|
|
|
191
191
|
<Check className="w-4 h-4 text-green-400 mt-0.5 shrink-0" />
|
|
192
192
|
<div className="flex-1 min-w-0">
|
|
193
193
|
<p
|
|
194
|
-
className="text-
|
|
194
|
+
className="text-md text-neutral-300 font-mono truncate"
|
|
195
195
|
title={error.message}
|
|
196
196
|
>
|
|
197
197
|
{error.message}
|
|
198
198
|
</p>
|
|
199
|
-
<div className="flex items-center gap-3 mt-1 text-
|
|
199
|
+
<div className="flex items-center gap-3 mt-1 text-sm text-neutral-500">
|
|
200
200
|
{error.count > 0 && (
|
|
201
201
|
<span className="text-yellow-400/80">+{error.count} since</span>
|
|
202
202
|
)}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - Previously reported errors are loaded once on mount
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { useState, useCallback, useEffect } from 'react'
|
|
17
|
+
import { useState, useCallback, useEffect, useMemo } from 'react'
|
|
18
18
|
import type { CapturedError, CapturedIssuesApi, SubmittedError } from './types.ts'
|
|
19
19
|
|
|
20
20
|
export interface UseCapturedIssuesOptions {
|
|
@@ -50,8 +50,14 @@ export function useCapturedIssues(options: UseCapturedIssuesOptions): UseCapture
|
|
|
50
50
|
const [submitError, setSubmitError] = useState<string | null>(null)
|
|
51
51
|
const [submittedErrors, setSubmittedErrors] = useState<SubmittedError[]>([])
|
|
52
52
|
|
|
53
|
-
const errorCount =
|
|
54
|
-
|
|
53
|
+
const { errorCount, warnCount } = useMemo(() => {
|
|
54
|
+
let err = 0, warn = 0
|
|
55
|
+
for (const e of errors) {
|
|
56
|
+
if (e.level === 'error') err++
|
|
57
|
+
else if (e.level === 'warning') warn++
|
|
58
|
+
}
|
|
59
|
+
return { errorCount: err, warnCount: warn }
|
|
60
|
+
}, [errors])
|
|
55
61
|
|
|
56
62
|
useEffect(() => {
|
|
57
63
|
api.getSubmittedErrors().then(setSubmittedErrors).catch(() => {})
|
|
@@ -86,14 +86,14 @@ function DiffFileItem({ file, isSelected, onSelect, onReset, resettingFile, anyR
|
|
|
86
86
|
>
|
|
87
87
|
<button
|
|
88
88
|
onClick={() => onSelect(file)}
|
|
89
|
-
className={`flex-1 flex items-center gap-2 px-3 py-1 text-
|
|
89
|
+
className={`flex-1 flex items-center gap-2 px-3 py-1 text-sm ${
|
|
90
90
|
isSelected ? 'text-neutral-300' : 'text-neutral-400'
|
|
91
91
|
}`}
|
|
92
92
|
>
|
|
93
93
|
{icon}
|
|
94
94
|
<span className="truncate">{filename}</span>
|
|
95
95
|
{statusLabel && (
|
|
96
|
-
<span className={`text-
|
|
96
|
+
<span className={`text-xs font-medium ml-auto flex-shrink-0 ${statusColor}`}>
|
|
97
97
|
{statusLabel}
|
|
98
98
|
</span>
|
|
99
99
|
)}
|
|
@@ -165,13 +165,13 @@ function DiffFileTreePanel({ sync, componentLabels, renderFileIcon }: DiffFileTr
|
|
|
165
165
|
|
|
166
166
|
// Root-level nodes get colored styling, nested folders get muted styling
|
|
167
167
|
const headerClasses = isRoot
|
|
168
|
-
? `${color.text} ${color.hoverBg} border-l-2 ${color.border} ${color.bg} px-3 py-2 text-
|
|
168
|
+
? `${color.text} ${color.hoverBg} border-l-2 ${color.border} ${color.bg} px-3 py-2 text-md font-medium`
|
|
169
169
|
: 'text-neutral-500 hover:bg-neutral-850 px-3 py-1.5'
|
|
170
170
|
|
|
171
171
|
const chevronSize = isRoot ? 'w-4 h-4' : 'w-3 h-3'
|
|
172
172
|
|
|
173
173
|
const countElement = isRoot ? (
|
|
174
|
-
<span className={`ml-auto px-1.5 py-0.5 rounded-full text-
|
|
174
|
+
<span className={`ml-auto px-1.5 py-0.5 rounded-full text-xs font-medium ${color.pillBg} ${color.text}`}>
|
|
175
175
|
{fileCount}
|
|
176
176
|
</span>
|
|
177
177
|
) : (
|
|
@@ -222,7 +222,7 @@ function DiffFileTreePanel({ sync, componentLabels, renderFileIcon }: DiffFileTr
|
|
|
222
222
|
<div className="w-72 flex-shrink-0 bg-neutral-900 rounded-lg border border-neutral-700 overflow-hidden flex flex-col">
|
|
223
223
|
{/* Summary Header */}
|
|
224
224
|
<div className="p-3 border-b border-neutral-700 flex-shrink-0">
|
|
225
|
-
<div className="flex gap-3 text-
|
|
225
|
+
<div className="flex gap-3 text-sm">
|
|
226
226
|
<span className="text-green-400">+{diff!.summary.added}</span>
|
|
227
227
|
<span className="text-red-400">-{diff!.summary.removed}</span>
|
|
228
228
|
<span className="text-yellow-400">~{diff!.summary.modified}</span>
|
|
@@ -237,7 +237,7 @@ function DiffFileTreePanel({ sync, componentLabels, renderFileIcon }: DiffFileTr
|
|
|
237
237
|
<button
|
|
238
238
|
key={filter}
|
|
239
239
|
onClick={() => setDiffFilter(filter)}
|
|
240
|
-
className={`px-2 py-1 rounded text-
|
|
240
|
+
className={`px-2 py-1 rounded text-sm transition-colors cursor-pointer ${
|
|
241
241
|
diffFilter === filter
|
|
242
242
|
? 'bg-neutral-700 text-neutral-300'
|
|
243
243
|
: 'text-neutral-500 hover:text-neutral-400'
|
|
@@ -295,7 +295,7 @@ function DiffEditorPanel({ sync, componentLabels, monacoTheme }: DiffEditorPanel
|
|
|
295
295
|
if (!selectedDiffFile) {
|
|
296
296
|
return (
|
|
297
297
|
<div className="flex-1 min-w-0 bg-neutral-900 rounded-lg border border-neutral-700 overflow-hidden flex flex-col">
|
|
298
|
-
<div className="flex items-center justify-center h-full text-
|
|
298
|
+
<div className="flex items-center justify-center h-full text-md text-neutral-500">
|
|
299
299
|
Select a file from the tree to view differences
|
|
300
300
|
</div>
|
|
301
301
|
</div>
|
|
@@ -310,16 +310,16 @@ function DiffEditorPanel({ sync, componentLabels, monacoTheme }: DiffEditorPanel
|
|
|
310
310
|
<div className="flex items-center justify-between px-4 py-2 border-b border-neutral-700 flex-shrink-0">
|
|
311
311
|
<div className="flex items-center gap-2">
|
|
312
312
|
<FileCode className="w-4 h-4 flex-shrink-0 text-blue-400/50" />
|
|
313
|
-
<span className="text-
|
|
313
|
+
<span className="text-md text-neutral-300 font-medium">
|
|
314
314
|
{selectedDiffFile.component}/{selectedDiffFile.path}
|
|
315
315
|
</span>
|
|
316
316
|
{devtools && hasUnsavedChanges && (
|
|
317
|
-
<span className="px-2 py-0.5 bg-amber-500/20 text-amber-400 text-
|
|
317
|
+
<span className="px-2 py-0.5 bg-amber-500/20 text-amber-400 text-sm rounded">
|
|
318
318
|
Modified
|
|
319
319
|
</span>
|
|
320
320
|
)}
|
|
321
321
|
</div>
|
|
322
|
-
<span className="text-
|
|
322
|
+
<span className="text-sm text-neutral-500">{compLabel}</span>
|
|
323
323
|
</div>
|
|
324
324
|
|
|
325
325
|
{/* Diff Editor */}
|
|
@@ -355,7 +355,7 @@ function DiffEditorPanel({ sync, componentLabels, monacoTheme }: DiffEditorPanel
|
|
|
355
355
|
}}
|
|
356
356
|
/>
|
|
357
357
|
) : (
|
|
358
|
-
<div className="flex items-center justify-center h-full text-
|
|
358
|
+
<div className="flex items-center justify-center h-full text-md text-neutral-500">
|
|
359
359
|
Loading file content...
|
|
360
360
|
</div>
|
|
361
361
|
)}
|
|
@@ -404,14 +404,14 @@ export function FileDiffViewer({ sync, componentLabels, monacoTheme, renderFileI
|
|
|
404
404
|
</div>
|
|
405
405
|
|
|
406
406
|
{diffLoading ? (
|
|
407
|
-
<div className="text-
|
|
407
|
+
<div className="text-md text-neutral-500 text-center py-8">Loading diff...</div>
|
|
408
408
|
) : diff ? (
|
|
409
409
|
<div className="flex gap-4 flex-1 min-h-[400px]">
|
|
410
410
|
<DiffFileTreePanel sync={sync} componentLabels={componentLabels} renderFileIcon={renderFileIcon} />
|
|
411
411
|
<DiffEditorPanel sync={sync} componentLabels={componentLabels} monacoTheme={monacoTheme} />
|
|
412
412
|
</div>
|
|
413
413
|
) : (
|
|
414
|
-
<div className="text-
|
|
414
|
+
<div className="text-md text-neutral-500 text-center py-8">
|
|
415
415
|
No diff data available. Click refresh to load.
|
|
416
416
|
</div>
|
|
417
417
|
)}
|
|
@@ -118,7 +118,7 @@ export function GoldenSyncPanel({
|
|
|
118
118
|
<h3 className="text-base font-semibold text-neutral-300">
|
|
119
119
|
{TAB_DESCRIPTIONS[activeTab].title}
|
|
120
120
|
</h3>
|
|
121
|
-
<p className="text-
|
|
121
|
+
<p className="text-md text-neutral-400">
|
|
122
122
|
{TAB_DESCRIPTIONS[activeTab].description}
|
|
123
123
|
</p>
|
|
124
124
|
</div>
|
|
@@ -138,7 +138,7 @@ export function GoldenSyncPanel({
|
|
|
138
138
|
<button
|
|
139
139
|
key={tab.id}
|
|
140
140
|
onClick={() => handleTabChange(tab.id)}
|
|
141
|
-
className={`h-[41px] flex items-center gap-2 px-4 text-
|
|
141
|
+
className={`h-[41px] flex items-center gap-2 px-4 text-md border-b-2 transition-colors cursor-pointer ${
|
|
142
142
|
activeTab === tab.id
|
|
143
143
|
? `${tab.color} border-current bg-neutral-800/50`
|
|
144
144
|
: 'border-transparent text-neutral-500 hover:text-neutral-300 hover:bg-neutral-800/30'
|
|
@@ -155,7 +155,7 @@ export function GoldenSyncPanel({
|
|
|
155
155
|
<div className="bg-red-500/10 border border-red-500/30 rounded-lg p-4 mt-4">
|
|
156
156
|
<div className="flex items-center gap-3">
|
|
157
157
|
<AlertCircle className="w-5 h-5 text-red-400 flex-shrink-0" />
|
|
158
|
-
<p className="text-red-400 text-
|
|
158
|
+
<p className="text-red-400 text-md">{error}</p>
|
|
159
159
|
</div>
|
|
160
160
|
</div>
|
|
161
161
|
)}
|
|
@@ -165,7 +165,7 @@ export function GoldenSyncPanel({
|
|
|
165
165
|
<div className="bg-green-500/10 border border-green-500/30 rounded-lg p-4 mt-4">
|
|
166
166
|
<div className="flex items-center gap-3">
|
|
167
167
|
<Check className="w-5 h-5 text-green-400 flex-shrink-0" />
|
|
168
|
-
<p className="text-green-400 text-
|
|
168
|
+
<p className="text-green-400 text-md">{lastAction}</p>
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
|
171
171
|
)}
|
|
@@ -174,7 +174,7 @@ export function GoldenSyncPanel({
|
|
|
174
174
|
{/* Content */}
|
|
175
175
|
<div className={activeTab === 'diff' ? 'flex-1 min-h-0 mt-4' : 'space-y-6 mt-4'}>
|
|
176
176
|
{loading && activeTab === 'status' ? (
|
|
177
|
-
<div className="text-
|
|
177
|
+
<div className="text-md text-neutral-500 text-center py-8">Loading...</div>
|
|
178
178
|
) : activeTab === 'status' ? (
|
|
179
179
|
<StatusOverview
|
|
180
180
|
status={status}
|
|
@@ -45,7 +45,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
if (manifestLoading && !manifest) {
|
|
48
|
-
return <div className="text-
|
|
48
|
+
return <div className="text-md text-neutral-500 text-center py-8">Loading snapshots...</div>
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
return (
|
|
@@ -54,9 +54,9 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
54
54
|
<div className="bg-neutral-900 rounded-lg p-4 border border-neutral-700">
|
|
55
55
|
<div className="flex items-center gap-3 mb-3">
|
|
56
56
|
<Plus className="w-5 h-5 text-green-400" />
|
|
57
|
-
<h4 className="text-
|
|
57
|
+
<h4 className="text-md text-neutral-300 font-medium">Create Snapshot</h4>
|
|
58
58
|
</div>
|
|
59
|
-
<p className="text-
|
|
59
|
+
<p className="text-sm text-neutral-600 mb-3">
|
|
60
60
|
Archives the current live state. If components differ from golden, their patch version is auto-bumped.
|
|
61
61
|
</p>
|
|
62
62
|
<div className="flex gap-2">
|
|
@@ -85,8 +85,8 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
85
85
|
<div className="flex items-center justify-between px-4 py-3 border-b border-neutral-700">
|
|
86
86
|
<div className="flex items-center gap-2">
|
|
87
87
|
<Archive className="w-4 h-4 text-neutral-500" />
|
|
88
|
-
<h4 className="text-
|
|
89
|
-
<span className="text-
|
|
88
|
+
<h4 className="text-md text-neutral-300 font-medium">Snapshots</h4>
|
|
89
|
+
<span className="text-sm text-neutral-500">({manifest?.snapshots.length ?? 0})</span>
|
|
90
90
|
</div>
|
|
91
91
|
<IconButton
|
|
92
92
|
icon={manifestLoading ? <Loader2 className="animate-spin" /> : <RotateCcw />}
|
|
@@ -99,7 +99,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
99
99
|
</div>
|
|
100
100
|
|
|
101
101
|
{!manifest || manifest.snapshots.length === 0 ? (
|
|
102
|
-
<div className="text-
|
|
102
|
+
<div className="text-md text-neutral-500 text-center py-8">No snapshots yet</div>
|
|
103
103
|
) : (
|
|
104
104
|
<div className="divide-y divide-neutral-700">
|
|
105
105
|
{[...manifest.snapshots].reverse().map((snap) => (
|
|
@@ -112,9 +112,9 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
112
112
|
{/* Version + info */}
|
|
113
113
|
<div className="flex-1 min-w-0">
|
|
114
114
|
<div className="flex items-center gap-2">
|
|
115
|
-
<span className="text-
|
|
115
|
+
<span className="text-md font-mono text-neutral-300">v{snap.version}</span>
|
|
116
116
|
{snap.version === manifest.activeVersion && (
|
|
117
|
-
<span className="px-1.5 py-0.5 bg-green-500/20 text-green-400 text-
|
|
117
|
+
<span className="px-1.5 py-0.5 bg-green-500/20 text-green-400 text-xs rounded font-medium">
|
|
118
118
|
active
|
|
119
119
|
</span>
|
|
120
120
|
)}
|
|
@@ -122,13 +122,13 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
122
122
|
<Pin className="w-3 h-3 text-amber-400" />
|
|
123
123
|
)}
|
|
124
124
|
{snap.metaVersion && (
|
|
125
|
-
<span className="text-
|
|
125
|
+
<span className="text-sm text-neutral-600 font-mono">{snap.metaVersion}</span>
|
|
126
126
|
)}
|
|
127
127
|
</div>
|
|
128
128
|
<div className="flex items-center gap-2 mt-0.5">
|
|
129
|
-
<span className="text-
|
|
129
|
+
<span className="text-sm text-neutral-600">{formatDate(snap.createdAt)}</span>
|
|
130
130
|
{snap.description && (
|
|
131
|
-
<span className="text-
|
|
131
|
+
<span className="text-sm text-neutral-500 truncate">{snap.description}</span>
|
|
132
132
|
)}
|
|
133
133
|
</div>
|
|
134
134
|
</div>
|
|
@@ -26,7 +26,7 @@ function getComponentVersion(meta: GoldenMeta | undefined, component: string): s
|
|
|
26
26
|
function renderVersionBadge(meta: GoldenMeta | undefined, color: string) {
|
|
27
27
|
if (!meta) return null
|
|
28
28
|
return (
|
|
29
|
-
<span className={`px-2 py-0.5 ${color} text-
|
|
29
|
+
<span className={`px-2 py-0.5 ${color} text-sm rounded font-mono`}>
|
|
30
30
|
{meta.version}
|
|
31
31
|
</span>
|
|
32
32
|
)
|
|
@@ -35,7 +35,7 @@ function renderVersionBadge(meta: GoldenMeta | undefined, color: string) {
|
|
|
35
35
|
function VersionStatus({ exists, version, mismatch, defaultColor = 'text-green-400/70' }: { exists: boolean; version?: string; mismatch: boolean; defaultColor?: string }) {
|
|
36
36
|
if (!exists) return <span className="text-red-400">Missing</span>
|
|
37
37
|
if (!version) return <span className="text-green-400">Found</span>
|
|
38
|
-
return <span className={`text-
|
|
38
|
+
return <span className={`text-sm font-mono ${mismatch ? 'text-yellow-400' : defaultColor}`}>v{version}</span>
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function SyncStatusBanner({ goldenMeta, liveMeta, components }: { goldenMeta: GoldenMeta; liveMeta: GoldenMeta; components: string[] }) {
|
|
@@ -48,12 +48,12 @@ function SyncStatusBanner({ goldenMeta, liveMeta, components }: { goldenMeta: Go
|
|
|
48
48
|
return mismatches === 0 ? (
|
|
49
49
|
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-green-500/5 border border-green-500/20">
|
|
50
50
|
<Check className="w-4 h-4 text-green-400" />
|
|
51
|
-
<span className="text-
|
|
51
|
+
<span className="text-md text-green-400">Golden and Live versions are in sync</span>
|
|
52
52
|
</div>
|
|
53
53
|
) : (
|
|
54
54
|
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-yellow-500/5 border border-yellow-500/20">
|
|
55
55
|
<AlertTriangle className="w-4 h-4 text-yellow-400" />
|
|
56
|
-
<span className="text-
|
|
56
|
+
<span className="text-md text-yellow-400">Version mismatch — {mismatches} component{mismatches > 1 ? 's' : ''} differ</span>
|
|
57
57
|
</div>
|
|
58
58
|
)
|
|
59
59
|
}
|
|
@@ -84,10 +84,10 @@ export function StatusOverview({
|
|
|
84
84
|
<div className="bg-neutral-900 rounded-lg p-4 border border-amber-500/30">
|
|
85
85
|
<div className="flex items-center gap-3 mb-3">
|
|
86
86
|
<Archive className="w-5 h-5 text-amber-400" />
|
|
87
|
-
<h3 className="text-
|
|
87
|
+
<h3 className="text-md text-neutral-300 font-medium">Bundled Seed (App Distribution)</h3>
|
|
88
88
|
{status?.seed.meta && renderVersionBadge(status.seed.meta, 'bg-amber-500/20 text-amber-400')}
|
|
89
89
|
</div>
|
|
90
|
-
<div className="grid grid-cols-2 gap-4 text-
|
|
90
|
+
<div className="grid grid-cols-2 gap-4 text-md">
|
|
91
91
|
<div>
|
|
92
92
|
<p className="text-neutral-500">Status</p>
|
|
93
93
|
<p className={status?.seed.exists ? 'text-green-400' : 'text-red-400'}>
|
|
@@ -104,7 +104,7 @@ export function StatusOverview({
|
|
|
104
104
|
</div>
|
|
105
105
|
</div>
|
|
106
106
|
{!devtools && (
|
|
107
|
-
<p className="text-
|
|
107
|
+
<p className="text-sm text-neutral-600 mt-3">
|
|
108
108
|
A compressed archive shipped with every release containing default configuration and templates. On first launch, the seed is extracted to initialize your local files.
|
|
109
109
|
</p>
|
|
110
110
|
)}
|
|
@@ -121,10 +121,10 @@ export function StatusOverview({
|
|
|
121
121
|
<div className="bg-neutral-900 rounded-lg p-4 border border-blue-500/30">
|
|
122
122
|
<div className="flex items-center gap-2 mb-3">
|
|
123
123
|
<div className="w-3 h-3 rounded-full bg-blue-400" />
|
|
124
|
-
<h4 className="text-
|
|
124
|
+
<h4 className="text-md text-neutral-300 font-medium">Golden (Reference)</h4>
|
|
125
125
|
{renderVersionBadge(status?.goldenMeta, 'bg-blue-500/20 text-blue-400')}
|
|
126
126
|
</div>
|
|
127
|
-
<div className="space-y-2 text-
|
|
127
|
+
<div className="space-y-2 text-md">
|
|
128
128
|
{components.map((comp) => {
|
|
129
129
|
const version = getComponentVersion(status?.goldenMeta, comp)
|
|
130
130
|
const dirKey = `${comp}Golden`
|
|
@@ -143,7 +143,7 @@ export function StatusOverview({
|
|
|
143
143
|
})}
|
|
144
144
|
</div>
|
|
145
145
|
{!devtools && (
|
|
146
|
-
<p className="text-
|
|
146
|
+
<p className="text-sm text-neutral-600 mt-3">
|
|
147
147
|
Reference copy extracted from the bundled seed. Always overwritten during app updates to match the latest release. Do not edit directly.
|
|
148
148
|
</p>
|
|
149
149
|
)}
|
|
@@ -153,7 +153,7 @@ export function StatusOverview({
|
|
|
153
153
|
<div className="bg-neutral-900 rounded-lg p-4 border border-green-500/30">
|
|
154
154
|
<div className="flex items-center gap-2 mb-3">
|
|
155
155
|
<div className="w-3 h-3 rounded-full bg-green-400" />
|
|
156
|
-
<h4 className="text-
|
|
156
|
+
<h4 className="text-md text-neutral-300 font-medium">Live (Working Copy)</h4>
|
|
157
157
|
{renderVersionBadge(status?.liveMeta, 'bg-green-500/20 text-green-400')}
|
|
158
158
|
<div className="ml-auto relative" ref={resetMenuRef}>
|
|
159
159
|
<IconButton
|
|
@@ -168,7 +168,7 @@ export function StatusOverview({
|
|
|
168
168
|
<div ref={resetMenuDropdownRef} className="absolute right-0 top-full mt-1 w-56 bg-neutral-850 border border-neutral-700 rounded-lg shadow-xl z-50 py-1 overflow-hidden">
|
|
169
169
|
<button
|
|
170
170
|
onClick={() => { onResetAll(); setShowResetMenu(false) }}
|
|
171
|
-
className="w-full text-left px-3 py-2 text-
|
|
171
|
+
className="w-full text-left px-3 py-2 text-md text-neutral-300 hover:bg-neutral-700 transition-colors"
|
|
172
172
|
>
|
|
173
173
|
Reset All to Golden
|
|
174
174
|
</button>
|
|
@@ -177,7 +177,7 @@ export function StatusOverview({
|
|
|
177
177
|
<button
|
|
178
178
|
key={comp}
|
|
179
179
|
onClick={() => { onResetComponent(comp); setShowResetMenu(false) }}
|
|
180
|
-
className="w-full text-left px-3 py-2 text-
|
|
180
|
+
className="w-full text-left px-3 py-2 text-md text-neutral-400 hover:bg-neutral-700 transition-colors"
|
|
181
181
|
>
|
|
182
182
|
Reset {getLabel(comp)}
|
|
183
183
|
</button>
|
|
@@ -186,7 +186,7 @@ export function StatusOverview({
|
|
|
186
186
|
)}
|
|
187
187
|
</div>
|
|
188
188
|
</div>
|
|
189
|
-
<div className="space-y-2 text-
|
|
189
|
+
<div className="space-y-2 text-md">
|
|
190
190
|
{components.map((comp) => {
|
|
191
191
|
const liveV = getComponentVersion(status?.liveMeta, comp)
|
|
192
192
|
const goldenV = getComponentVersion(status?.goldenMeta, comp)
|
|
@@ -212,7 +212,7 @@ export function StatusOverview({
|
|
|
212
212
|
})}
|
|
213
213
|
</div>
|
|
214
214
|
{!devtools && (
|
|
215
|
-
<p className="text-
|
|
215
|
+
<p className="text-sm text-neutral-600 mt-3">
|
|
216
216
|
Your active working copy — what the app uses at runtime. Customizations are made here and preserved across app updates.
|
|
217
217
|
</p>
|
|
218
218
|
)}
|
|
@@ -222,10 +222,10 @@ export function StatusOverview({
|
|
|
222
222
|
{/* Update Flow — settings only */}
|
|
223
223
|
{!devtools && (
|
|
224
224
|
<div className="bg-neutral-900/50 border border-neutral-700 rounded-lg p-4">
|
|
225
|
-
<p className="text-
|
|
225
|
+
<p className="text-sm font-medium text-neutral-400 mb-4">
|
|
226
226
|
How updates work <span className="font-normal text-neutral-600">— checked per component ({components.map(getLabel).join(', ')})</span>
|
|
227
227
|
</p>
|
|
228
|
-
<div className="grid grid-cols-[auto_auto_auto_auto_auto_auto_auto] items-center gap-x-2 text-
|
|
228
|
+
<div className="grid grid-cols-[auto_auto_auto_auto_auto_auto_auto] items-center gap-x-2 text-sm">
|
|
229
229
|
{/* Row 1: top branch outcome */}
|
|
230
230
|
<span /><span /><span /><span /><span />
|
|
231
231
|
<span className="text-neutral-600 text-base justify-self-center self-end mb-[-4px]">↗</span>
|
|
@@ -279,7 +279,7 @@ export function StatusOverview({
|
|
|
279
279
|
<span className="text-neutral-600 mt-0.5">has changes</span>
|
|
280
280
|
</div>
|
|
281
281
|
</div>
|
|
282
|
-
<p className="text-
|
|
282
|
+
<p className="text-sm text-neutral-600 mt-3">
|
|
283
283
|
When a component has no local changes, it is automatically updated to match the new golden version. Components with customizations are left untouched to preserve your edits — use the File Diff tab to review differences and selectively apply changes. You can reset any component to its golden version at any time using the reset buttons above.
|
|
284
284
|
</p>
|
|
285
285
|
</div>
|
|
@@ -290,9 +290,9 @@ export function StatusOverview({
|
|
|
290
290
|
<div className="bg-neutral-900 rounded-lg p-4 border border-neutral-700">
|
|
291
291
|
<div className="flex items-center gap-2 mb-3">
|
|
292
292
|
<Archive className="w-4 h-4 text-neutral-500" />
|
|
293
|
-
<h4 className="text-
|
|
293
|
+
<h4 className="text-md text-neutral-300 font-medium">Local Snapshots</h4>
|
|
294
294
|
</div>
|
|
295
|
-
<div className="flex gap-6 text-
|
|
295
|
+
<div className="flex gap-6 text-md">
|
|
296
296
|
<div>
|
|
297
297
|
<span className="text-neutral-500">Count: </span>
|
|
298
298
|
<span className="text-neutral-300">{manifest.snapshots.length}</span>
|
|
@@ -56,14 +56,14 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
|
|
|
56
56
|
<div className="bg-neutral-900 rounded-lg p-4 border border-teal-500/30">
|
|
57
57
|
<div className="flex items-center gap-3 mb-3">
|
|
58
58
|
<Tag className="w-5 h-5 text-teal-400" />
|
|
59
|
-
<h4 className="text-
|
|
59
|
+
<h4 className="text-md text-neutral-300 font-medium">Golden Version</h4>
|
|
60
60
|
{status?.goldenMeta && (
|
|
61
|
-
<span className="px-2 py-0.5 bg-teal-500/20 text-teal-400 text-
|
|
61
|
+
<span className="px-2 py-0.5 bg-teal-500/20 text-teal-400 text-sm rounded font-mono">
|
|
62
62
|
{status.goldenMeta.version}
|
|
63
63
|
</span>
|
|
64
64
|
)}
|
|
65
65
|
</div>
|
|
66
|
-
<p className="text-
|
|
66
|
+
<p className="text-sm text-neutral-600 mb-3">
|
|
67
67
|
Bump the overall golden version number. This updates the top-level version in meta.json.
|
|
68
68
|
</p>
|
|
69
69
|
<div className="flex gap-2">
|
|
@@ -100,8 +100,8 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
|
|
|
100
100
|
{/* Component Versions */}
|
|
101
101
|
<div className="bg-neutral-900 rounded-lg border border-neutral-700 overflow-hidden">
|
|
102
102
|
<div className="px-4 py-3 border-b border-neutral-700">
|
|
103
|
-
<h4 className="text-
|
|
104
|
-
<p className="text-
|
|
103
|
+
<h4 className="text-md text-neutral-300 font-medium">Component Versions</h4>
|
|
104
|
+
<p className="text-sm text-neutral-600 mt-1">
|
|
105
105
|
Update individual component versions. Click a component to edit.
|
|
106
106
|
</p>
|
|
107
107
|
</div>
|
|
@@ -117,12 +117,12 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
|
|
|
117
117
|
<div key={comp} className="px-4 py-3">
|
|
118
118
|
<div className="flex items-center justify-between">
|
|
119
119
|
<div className="flex items-center gap-2">
|
|
120
|
-
<span className="text-
|
|
120
|
+
<span className="text-md text-neutral-300">{getLabel(comp)}</span>
|
|
121
121
|
{currentVersion && (
|
|
122
|
-
<span className="text-
|
|
122
|
+
<span className="text-sm font-mono text-neutral-500">v{currentVersion}</span>
|
|
123
123
|
)}
|
|
124
124
|
{mismatch && (
|
|
125
|
-
<span className="text-
|
|
125
|
+
<span className="text-xs text-yellow-400">
|
|
126
126
|
(live: v{liveVersion})
|
|
127
127
|
</span>
|
|
128
128
|
)}
|