@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.
- package/agent-rules.json +91 -0
- package/ai-manifest.json +190 -0
- package/components/content/info-panel-primitives.tsx +14 -14
- package/components/lib/ai-tools.tsx +1 -1
- package/components/sections/ai-tools-paths/tools-paths-panel.tsx +7 -7
- package/components/sections/captured-issues/captured-issues-panel.tsx +11 -11
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +13 -13
- package/components/sections/golden-snapshots/golden-sync-panel.tsx +5 -5
- package/components/sections/golden-snapshots/snapshot-manager.tsx +11 -11
- package/components/sections/golden-snapshots/status-overview.tsx +20 -20
- package/components/sections/golden-snapshots/version-manager.tsx +8 -8
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +4 -4
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +5 -5
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +10 -10
- package/components/sections/report-bug/report-bug-form.tsx +14 -14
- package/components/sections/report-bug/screenshot-uploader.tsx +6 -6
- package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +3 -3
- package/components/sections/snapshot-browser/snapshot-tree.tsx +8 -8
- package/components/sections/snippets-editor/snippets-editor.tsx +81 -22
- package/components/settings/SettingsHeader.tsx +1 -1
- package/components/settings/SettingsTreeNav.tsx +22 -4
- package/components/ui/action-dialog.tsx +5 -5
- package/components/ui/badge.tsx +4 -4
- package/components/ui/bottom-panel-header.tsx +4 -4
- package/components/ui/breadcrumb.tsx +2 -2
- package/components/ui/collapsible-section.tsx +1 -1
- package/components/ui/cookie-consent.tsx +5 -5
- package/components/ui/detail-section.tsx +3 -3
- package/components/ui/editor-placeholder-card.tsx +7 -7
- package/components/ui/editor-toolbar.tsx +12 -0
- package/components/ui/execution-details-panel.tsx +6 -6
- package/components/ui/extension-list-card.tsx +3 -3
- package/components/ui/file-structure-section.tsx +17 -17
- package/components/ui/file-tree.tsx +3 -1
- package/components/ui/files-panel.tsx +27 -9
- package/components/ui/filter-dropdown.tsx +5 -5
- package/components/ui/form-actions.tsx +1 -1
- package/components/ui/frontmatter-form-header.tsx +4 -4
- package/components/ui/icon-button.tsx +1 -1
- package/components/ui/input.tsx +7 -7
- package/components/ui/label.tsx +4 -4
- package/components/ui/layout-tab-bar.tsx +4 -4
- package/components/ui/modal.tsx +2 -2
- package/components/ui/nav-card.tsx +18 -11
- package/components/ui/navigation-bar.tsx +5 -5
- package/components/ui/number-input.tsx +4 -4
- package/components/ui/registry-browser.tsx +6 -6
- package/components/ui/registry-card.tsx +13 -13
- package/components/ui/registry-detail.tsx +6 -6
- package/components/ui/segmented-toggle.tsx +4 -4
- package/components/ui/select.tsx +5 -5
- package/components/ui/selection-grid.tsx +4 -4
- package/components/ui/setting-row.tsx +1 -1
- package/components/ui/settings-card.tsx +3 -3
- package/components/ui/settings-info-box.tsx +1 -1
- package/components/ui/settings-section-title.tsx +1 -1
- package/components/ui/snapshot-card.tsx +7 -7
- package/components/ui/snippets-panel.tsx +10 -10
- package/components/ui/sort-dropdown.tsx +2 -2
- package/components/ui/status-card.tsx +4 -4
- package/components/ui/tab-bar.tsx +2 -2
- package/components/ui/tooltip.tsx +3 -3
- package/dist/content.js +14 -14
- package/dist/index.d.ts +24 -7
- package/dist/index.js +440 -346
- package/dist/tokens/primitives.css +9 -2
- package/dist/tokens/semantic.css +1 -1
- package/package.json +13 -3
- package/tokens/primitives.css +9 -2
- package/tokens/semantic.css +1 -1
package/components/ui/input.tsx
CHANGED
|
@@ -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-
|
|
43
|
-
sm: 'px-2 py-1 text-
|
|
44
|
-
md: 'px-3 py-1.5 text-
|
|
45
|
-
lg: 'px-3 py-2 text-
|
|
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 = {
|
|
@@ -183,13 +183,13 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input({
|
|
|
183
183
|
{debounceMs > 0 && debounceKey > 0 && (
|
|
184
184
|
<svg
|
|
185
185
|
key={debounceKey}
|
|
186
|
-
className="absolute inset-0 pointer-events-none"
|
|
186
|
+
className="absolute inset-0 pointer-events-none text-emerald-400/70"
|
|
187
187
|
style={{ width: '100%', height: '100%' }}
|
|
188
188
|
>
|
|
189
189
|
<rect
|
|
190
190
|
x="1" y="1" rx="5" ry="5"
|
|
191
191
|
fill="none"
|
|
192
|
-
stroke="
|
|
192
|
+
stroke="currentColor"
|
|
193
193
|
strokeWidth="1.5"
|
|
194
194
|
pathLength="100"
|
|
195
195
|
strokeDasharray="100"
|
|
@@ -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-
|
|
207
|
+
<p className="text-sm text-red-400 mt-1 text-right">{error}</p>
|
|
208
208
|
)}
|
|
209
209
|
</div>
|
|
210
210
|
)
|
package/components/ui/label.tsx
CHANGED
|
@@ -87,10 +87,10 @@ const progressFillColors: Record<LabelColor, string> = {
|
|
|
87
87
|
|
|
88
88
|
const sizeConfig = {
|
|
89
89
|
xss: { height: 14, padding: 'px-1', text: 'text-xss', iconSize: 'w-2 h-2', gap: 'gap-0.5' },
|
|
90
|
-
xs: { height: 16, padding: 'px-1.5', text: 'text-
|
|
91
|
-
sm: { height: 18, padding: 'px-1.5', text: 'text-
|
|
92
|
-
md: { height: 20, padding: 'px-1.5', text: 'text-
|
|
93
|
-
lg: { height: 22, padding: 'px-2', text: 'text-
|
|
90
|
+
xs: { height: 16, padding: 'px-1.5', text: 'text-xs', iconSize: 'w-2.5 h-2.5', gap: 'gap-1' },
|
|
91
|
+
sm: { height: 18, padding: 'px-1.5', text: 'text-xs', iconSize: 'w-2.5 h-2.5', gap: 'gap-1.5' },
|
|
92
|
+
md: { height: 20, padding: 'px-1.5', text: 'text-xs', iconSize: 'w-3 h-3', gap: 'gap-1' },
|
|
93
|
+
lg: { height: 22, padding: 'px-2', text: 'text-sm', iconSize: 'w-3 h-3', gap: 'gap-1' },
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/** Smart capitalize: capitalizes first letter of each word separated by spaces or dashes */
|
|
@@ -220,14 +220,14 @@ export function LayoutTabBar({ tabs, activeId, onSelect, onClose, onReorder, cla
|
|
|
220
220
|
{/* Line 1: Icon + Title */}
|
|
221
221
|
<div className="flex items-center gap-1.5 w-full transition-[padding] duration-150 group-hover:pr-5">
|
|
222
222
|
{tab.icon && <span className={cn('shrink-0 inline-flex', isActive ? iconC : 'text-neutral-400')} style={{ width: 14, height: 14 }}>{tab.icon}</span>}
|
|
223
|
-
<span className={cn('truncate text-
|
|
223
|
+
<span className={cn('truncate text-md font-medium', isActive ? titleC : 'text-neutral-300')}>{tab.title}</span>
|
|
224
224
|
</div>
|
|
225
225
|
|
|
226
226
|
{/* Line 2: Subtitle with optional icon */}
|
|
227
227
|
{tab.subtitle && (
|
|
228
228
|
<div className="flex items-center gap-1 w-full">
|
|
229
229
|
{tab.subtitleIcon && <span className={cn('shrink-0 inline-flex', isActive ? subIconC : 'text-neutral-500')} style={{ width: 10, height: 10 }}>{tab.subtitleIcon}</span>}
|
|
230
|
-
<span className={cn('truncate text-
|
|
230
|
+
<span className={cn('truncate text-sm', isActive ? subC : 'text-neutral-500')}>{tab.subtitle}</span>
|
|
231
231
|
</div>
|
|
232
232
|
)}
|
|
233
233
|
|
|
@@ -272,12 +272,12 @@ export function LayoutTabBar({ tabs, activeId, onSelect, onClose, onReorder, cla
|
|
|
272
272
|
<div className={cn('flex flex-col gap-0.5 px-2.5 py-1.5 rounded-t-lg border-t-2 shadow-xl bg-neutral-800', ghostBorder)}>
|
|
273
273
|
<div className="flex items-center gap-1.5">
|
|
274
274
|
{t.icon && <span className={cn('shrink-0 inline-flex', ghostIconC)} style={{ width: 14, height: 14 }}>{t.icon}</span>}
|
|
275
|
-
<span className={cn('text-
|
|
275
|
+
<span className={cn('text-md font-medium', ghostTitleC)}>{t.title}</span>
|
|
276
276
|
</div>
|
|
277
277
|
{t.subtitle && (
|
|
278
278
|
<div className="flex items-center gap-1">
|
|
279
279
|
{t.subtitleIcon && <span className={cn('shrink-0 inline-flex', ghostSubIconC)} style={{ width: 10, height: 10 }}>{t.subtitleIcon}</span>}
|
|
280
|
-
<span className={cn('text-
|
|
280
|
+
<span className={cn('text-sm', ghostSubC)}>{t.subtitle}</span>
|
|
281
281
|
</div>
|
|
282
282
|
)}
|
|
283
283
|
</div>
|
package/components/ui/modal.tsx
CHANGED
|
@@ -139,11 +139,11 @@ export function ConfirmModal({
|
|
|
139
139
|
{message}
|
|
140
140
|
{warning && (
|
|
141
141
|
<div className="mt-3 p-3 bg-amber-500/10 border border-amber-500/30 rounded-lg">
|
|
142
|
-
<p className="text-amber-300 text-
|
|
142
|
+
<p className="text-amber-300 text-md font-medium">{warning}</p>
|
|
143
143
|
{warningItems && warningItems.length > 0 && (
|
|
144
144
|
<ul className="mt-2 space-y-1">
|
|
145
145
|
{warningItems.map((item, i) => (
|
|
146
|
-
<li key={i} className="text-amber-300/80 text-
|
|
146
|
+
<li key={i} className="text-amber-300/80 text-md ml-4 list-disc">{item}</li>
|
|
147
147
|
))}
|
|
148
148
|
</ul>
|
|
149
149
|
)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Navigation card with icon, description,
|
|
1
|
+
/** Navigation card with icon, description, label, and hover lift effect. */
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Settings, Puzzle, Zap, Shield, Folder, Code, Database, Globe,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from 'lucide-react'
|
|
8
8
|
import type { LucideIcon } from 'lucide-react'
|
|
9
9
|
import type { IconName } from './icon-button.tsx'
|
|
10
|
-
import {
|
|
10
|
+
import { Label, type LabelColor } from './label.tsx'
|
|
11
11
|
import { cn } from '../lib/cn.ts'
|
|
12
12
|
|
|
13
13
|
const iconSubset: Partial<Record<IconName, LucideIcon>> = {
|
|
@@ -23,9 +23,11 @@ export interface NavCardProps {
|
|
|
23
23
|
title: string
|
|
24
24
|
description?: string
|
|
25
25
|
icon?: IconName
|
|
26
|
+
/** Custom icon component. Takes precedence over icon name. */
|
|
27
|
+
IconComponent?: React.ComponentType<{ className?: string }>
|
|
26
28
|
iconColor?: string
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
label?: { text: string; color: LabelColor; tooltip: { description: string } }
|
|
30
|
+
stats?: string
|
|
29
31
|
onClick?: () => void
|
|
30
32
|
disabled?: boolean
|
|
31
33
|
className?: string
|
|
@@ -35,14 +37,15 @@ export function NavCard({
|
|
|
35
37
|
title,
|
|
36
38
|
description,
|
|
37
39
|
icon,
|
|
40
|
+
IconComponent,
|
|
38
41
|
iconColor = '#60a5fa',
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
label,
|
|
43
|
+
stats,
|
|
41
44
|
onClick,
|
|
42
45
|
disabled = false,
|
|
43
46
|
className,
|
|
44
47
|
}: NavCardProps) {
|
|
45
|
-
const Icon = icon ? iconSubset[icon] : undefined
|
|
48
|
+
const Icon = IconComponent ?? (icon ? iconSubset[icon] : undefined)
|
|
46
49
|
|
|
47
50
|
return (
|
|
48
51
|
<button
|
|
@@ -56,9 +59,9 @@ export function NavCard({
|
|
|
56
59
|
className,
|
|
57
60
|
)}
|
|
58
61
|
>
|
|
59
|
-
{
|
|
62
|
+
{label && (
|
|
60
63
|
<span className="absolute top-3 right-3">
|
|
61
|
-
<
|
|
64
|
+
<Label text={label.text} color={label.color} size="xs" tooltip={label.tooltip} />
|
|
62
65
|
</span>
|
|
63
66
|
)}
|
|
64
67
|
|
|
@@ -71,10 +74,14 @@ export function NavCard({
|
|
|
71
74
|
</div>
|
|
72
75
|
)}
|
|
73
76
|
|
|
74
|
-
<h3 className="text-
|
|
77
|
+
<h3 className="text-md font-medium text-neutral-200">{title}</h3>
|
|
75
78
|
|
|
76
79
|
{description && (
|
|
77
|
-
<p className="mt-1 text-
|
|
80
|
+
<p className="mt-1 text-sm text-neutral-500 leading-relaxed line-clamp-2">{description}</p>
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
{stats && (
|
|
84
|
+
<p className="mt-2 text-sm text-neutral-600">{stats}</p>
|
|
78
85
|
)}
|
|
79
86
|
</button>
|
|
80
87
|
)
|
|
@@ -70,8 +70,8 @@ export interface NavigationBarProps {
|
|
|
70
70
|
|
|
71
71
|
const sizeConfig = {
|
|
72
72
|
xss: { text: 'text-xss', segIcon: 'w-2.5 h-2.5', navIcon: 'w-2.5 h-2.5', navBtn: 'w-[18px] h-[18px] rounded-[3px]', px: 'px-1', py: 'py-0.5', sep: 'w-2 h-2', divH: 'h-3' },
|
|
73
|
-
xs: { text: 'text-
|
|
74
|
-
sm: { text: 'text-
|
|
73
|
+
xs: { text: 'text-sm', segIcon: 'w-3 h-3', navIcon: 'w-3 h-3', navBtn: 'w-6 h-6 rounded-[5px]', px: 'px-1.5', py: 'py-0.5', sep: 'w-2.5 h-2.5', divH: 'h-3.5' },
|
|
74
|
+
sm: { text: 'text-md', segIcon: 'w-3.5 h-3.5', navIcon: 'w-3.5 h-3.5', navBtn: 'w-7 h-7 rounded-md', px: 'px-2', py: 'py-1', sep: 'w-3 h-3', divH: 'h-4' },
|
|
75
75
|
md: { text: 'text-base', segIcon: 'w-4 h-4', navIcon: 'w-4 h-4', navBtn: 'w-8 h-8 rounded-md', px: 'px-2.5', py: 'py-1', sep: 'w-3.5 h-3.5', divH: 'h-5' },
|
|
76
76
|
lg: { text: 'text-lg', segIcon: 'w-5 h-5', navIcon: 'w-5 h-5', navBtn: 'w-9 h-9 rounded-md', px: 'px-3', py: 'py-1.5', sep: 'w-4 h-4', divH: 'h-6' },
|
|
77
77
|
}
|
|
@@ -202,7 +202,7 @@ export function NavigationBar({
|
|
|
202
202
|
{historyOpen && hasHistoryEntries && (
|
|
203
203
|
<div className="absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-neutral-800 border border-neutral-700 rounded-lg shadow-xl z-50">
|
|
204
204
|
<div className="px-3 py-1.5 border-b border-neutral-700/50">
|
|
205
|
-
<p className="text-
|
|
205
|
+
<p className="text-sm font-medium text-neutral-500">History</p>
|
|
206
206
|
</div>
|
|
207
207
|
<div className="max-h-[300px] overflow-y-auto py-1">
|
|
208
208
|
{historyEntries.map((entry, i) => (
|
|
@@ -220,7 +220,7 @@ export function NavigationBar({
|
|
|
220
220
|
{segIdx > 0 && <ChevronRight className="w-2.5 h-2.5 text-neutral-600 flex-shrink-0" />}
|
|
221
221
|
{seg.icon && <SegmentIcon icon={seg.icon} color={seg.color} size="xs" />}
|
|
222
222
|
<span className={cn(
|
|
223
|
-
'text-
|
|
223
|
+
'text-sm truncate',
|
|
224
224
|
seg.color && colorMap[seg.color] ? colorMap[seg.color].text : 'text-neutral-300',
|
|
225
225
|
)}>
|
|
226
226
|
{seg.label}
|
|
@@ -231,7 +231,7 @@ export function NavigationBar({
|
|
|
231
231
|
))}
|
|
232
232
|
</div>
|
|
233
233
|
<div className="px-3 py-1.5 border-t border-neutral-700/50">
|
|
234
|
-
<p className="text-
|
|
234
|
+
<p className="text-sm text-neutral-600">Click to navigate</p>
|
|
235
235
|
</div>
|
|
236
236
|
</div>
|
|
237
237
|
)}
|
|
@@ -17,10 +17,10 @@ export interface NumberInputProps {
|
|
|
17
17
|
|
|
18
18
|
const SIZE_CONFIG = {
|
|
19
19
|
xss: { wrapper: 'h-[18px]', input: 'px-1 text-xss', chevron: 'w-2.5 h-2.5', stepperW: 'w-4' },
|
|
20
|
-
xs: { wrapper: 'h-6', input: 'px-1.5 text-
|
|
21
|
-
sm: { wrapper: 'h-7', input: 'px-2 text-
|
|
22
|
-
md: { wrapper: 'h-8', input: 'px-3 text-
|
|
23
|
-
lg: { wrapper: 'h-9', input: 'px-3 text-
|
|
20
|
+
xs: { wrapper: 'h-6', input: 'px-1.5 text-sm', chevron: 'w-2.5 h-2.5', stepperW: 'w-5' },
|
|
21
|
+
sm: { wrapper: 'h-7', input: 'px-2 text-sm', chevron: 'w-3 h-3', stepperW: 'w-5' },
|
|
22
|
+
md: { wrapper: 'h-8', input: 'px-3 text-md', chevron: 'w-3 h-3', stepperW: 'w-6' },
|
|
23
|
+
lg: { wrapper: 'h-9', input: 'px-3 text-md', chevron: 'w-3.5 h-3.5', stepperW: 'w-7' },
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const VARIANT_CLASSES = {
|
|
@@ -172,13 +172,13 @@ export function RegistryBrowser({
|
|
|
172
172
|
{debounceKey != null && debounceKey > 0 && (
|
|
173
173
|
<svg
|
|
174
174
|
key={debounceKey}
|
|
175
|
-
className="absolute inset-0 pointer-events-none"
|
|
175
|
+
className="absolute inset-0 pointer-events-none text-emerald-400/70"
|
|
176
176
|
style={{ width: '100%', height: '100%' }}
|
|
177
177
|
>
|
|
178
178
|
<rect
|
|
179
179
|
x="1" y="1" rx="5" ry="5"
|
|
180
180
|
fill="none"
|
|
181
|
-
stroke="
|
|
181
|
+
stroke="currentColor"
|
|
182
182
|
strokeWidth="1.5"
|
|
183
183
|
pathLength="100"
|
|
184
184
|
strokeDasharray="100"
|
|
@@ -231,18 +231,18 @@ export function RegistryBrowser({
|
|
|
231
231
|
) : error ? (
|
|
232
232
|
<div className="flex flex-col items-center justify-center py-12 text-neutral-500">
|
|
233
233
|
<AlertTriangle className="w-6 h-6 text-amber-400 mb-2" />
|
|
234
|
-
<p className="text-
|
|
234
|
+
<p className="text-md">{error}</p>
|
|
235
235
|
{onRetry && (
|
|
236
|
-
<button onClick={onRetry} className="mt-2 text-
|
|
236
|
+
<button onClick={onRetry} className="mt-2 text-sm text-blue-400 hover:underline cursor-pointer">
|
|
237
237
|
Try again
|
|
238
238
|
</button>
|
|
239
239
|
)}
|
|
240
240
|
</div>
|
|
241
241
|
) : isEmpty ? (
|
|
242
242
|
<div className="flex flex-col items-center justify-center py-12 text-neutral-500">
|
|
243
|
-
<p className="text-
|
|
243
|
+
<p className="text-md">{emptyMessage}</p>
|
|
244
244
|
{hasActiveFilters && onResetFilters && (
|
|
245
|
-
<button onClick={onResetFilters} className="mt-2 text-
|
|
245
|
+
<button onClick={onResetFilters} className="mt-2 text-sm text-blue-400 hover:underline cursor-pointer">
|
|
246
246
|
Reset filters
|
|
247
247
|
</button>
|
|
248
248
|
)}
|
|
@@ -412,7 +412,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
412
412
|
<Tooltip key={`pkg-${key}`} content={{ description: `${count} ${count === 1 ? label : labelPlural}` }} position="top">
|
|
413
413
|
<span className="flex items-center gap-0.5">
|
|
414
414
|
<Icon className={`w-3 h-3 ${color}`} />
|
|
415
|
-
<span className="text-
|
|
415
|
+
<span className="text-xs text-neutral-500">{count}</span>
|
|
416
416
|
</span>
|
|
417
417
|
</Tooltip>
|
|
418
418
|
)]
|
|
@@ -469,7 +469,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
469
469
|
...(props.stars != null && props.stars > 0 ? [(
|
|
470
470
|
<CardClickable key="stars" onClick={() => props.onSortBy?.('stars')}>
|
|
471
471
|
<Tooltip content={{ description: `${props.stars.toLocaleString()} stars \u00b7 Click to sort` }} position="top">
|
|
472
|
-
<span className="flex items-center gap-1 text-
|
|
472
|
+
<span className="flex items-center gap-1 text-xs text-amber-400/80">
|
|
473
473
|
<Star className="w-3 h-3" />
|
|
474
474
|
{formatCount(props.stars)}
|
|
475
475
|
</span>
|
|
@@ -479,7 +479,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
479
479
|
...(props.downloads != null && props.downloads > 0 ? [(
|
|
480
480
|
<CardClickable key="downloads" onClick={() => props.onSortBy?.('downloads')}>
|
|
481
481
|
<Tooltip content={{ description: `${props.downloads.toLocaleString()} downloads \u00b7 Click to sort` }} position="top">
|
|
482
|
-
<span className="flex items-center gap-1 text-
|
|
482
|
+
<span className="flex items-center gap-1 text-xs text-emerald-400/80">
|
|
483
483
|
<Download className="w-3 h-3" />
|
|
484
484
|
{formatCount(props.downloads)}
|
|
485
485
|
</span>
|
|
@@ -581,7 +581,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
581
581
|
if (props.installs != null && props.installs > 0) {
|
|
582
582
|
bottomStats = [(
|
|
583
583
|
<Tooltip key="installs" content={{ description: `${props.installs.toLocaleString()} installs` }} position="top">
|
|
584
|
-
<span className="flex items-center gap-1 text-
|
|
584
|
+
<span className="flex items-center gap-1 text-xs text-neutral-500">
|
|
585
585
|
<Download className="w-3 h-3" />
|
|
586
586
|
{props.installs.toLocaleString()}
|
|
587
587
|
</span>
|
|
@@ -632,17 +632,17 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
632
632
|
</div>
|
|
633
633
|
|
|
634
634
|
{/* Name */}
|
|
635
|
-
<h3 className="text-
|
|
635
|
+
<h3 className="text-md font-medium text-white">{name}</h3>
|
|
636
636
|
|
|
637
637
|
{/* Subtitle */}
|
|
638
|
-
{subtitle && <div className="text-
|
|
638
|
+
{subtitle && <div className="text-sm text-neutral-400 mb-1.5">{subtitle}</div>}
|
|
639
639
|
|
|
640
640
|
{/* Description */}
|
|
641
|
-
{description && <p className="text-
|
|
641
|
+
{description && <p className="text-sm text-neutral-500 mb-3 flex-grow line-clamp-2">{description}</p>}
|
|
642
642
|
|
|
643
643
|
{/* Error/warning message */}
|
|
644
644
|
{errorMessage && (
|
|
645
|
-
<p className={`text-
|
|
645
|
+
<p className={`text-xs mb-2 break-all ${flash === 'warning' ? 'text-amber-400' : 'text-red-400'}`}>{errorMessage}</p>
|
|
646
646
|
)}
|
|
647
647
|
|
|
648
648
|
{/* Bottom row */}
|
|
@@ -650,7 +650,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
650
650
|
const dateNode = updatedAt ? (
|
|
651
651
|
<Tooltip content={{ description: onDateClick ? `Last updated ${formatFullDate(updatedAt)} \u00b7 Click to sort by date` : `Last updated ${formatFullDate(updatedAt)}` }} position="top">
|
|
652
652
|
<span
|
|
653
|
-
className={`flex items-center gap-1 text-
|
|
653
|
+
className={`flex items-center gap-1 text-xs text-neutral-500 whitespace-nowrap${onDateClick ? ' cursor-pointer hover:brightness-125 transition-all' : ''}`}
|
|
654
654
|
onClick={onDateClick ? (e: MouseEvent) => { e.stopPropagation(); onDateClick() } : undefined}
|
|
655
655
|
>
|
|
656
656
|
<Clock className="w-3 h-3" />
|
|
@@ -692,13 +692,13 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
692
692
|
<div onClick={(e) => e.stopPropagation()}>
|
|
693
693
|
<div className="fixed inset-0 bg-[var(--background)]/50 z-50 flex items-center justify-center" onClick={() => setShowScopeConfirm(false)}>
|
|
694
694
|
<div className="bg-neutral-800 border border-neutral-700 rounded-lg p-4 max-w-sm" onClick={(e) => e.stopPropagation()}>
|
|
695
|
-
<h3 className="text-
|
|
696
|
-
<p className="text-
|
|
695
|
+
<h3 className="text-md font-medium text-neutral-200 mb-2">{ALREADY_AT_USER}</h3>
|
|
696
|
+
<p className="text-sm text-neutral-400 mb-4">
|
|
697
697
|
<strong className="text-neutral-300">{name}</strong> is already installed at user level and available to all projects. Do you also want to install it at project level?
|
|
698
698
|
</p>
|
|
699
699
|
<div className="flex justify-end gap-2">
|
|
700
|
-
<button type="button" onClick={() => setShowScopeConfirm(false)} className="px-3 py-1.5 text-
|
|
701
|
-
<button type="button" onClick={() => { setShowScopeConfirm(false); props.onInstall() }} className="px-3 py-1.5 text-
|
|
700
|
+
<button type="button" onClick={() => setShowScopeConfirm(false)} className="px-3 py-1.5 text-sm text-neutral-400 hover:text-neutral-200 transition-colors cursor-pointer">Cancel</button>
|
|
701
|
+
<button type="button" onClick={() => { setShowScopeConfirm(false); props.onInstall() }} className="px-3 py-1.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-500 transition-colors cursor-pointer">Install to project</button>
|
|
702
702
|
</div>
|
|
703
703
|
</div>
|
|
704
704
|
</div>
|
|
@@ -42,7 +42,7 @@ export interface RegistryDetailProps {
|
|
|
42
42
|
children?: ReactNode
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const MARKDOWN_CLASSES = 'text-
|
|
45
|
+
const MARKDOWN_CLASSES = 'text-md text-neutral-400 leading-relaxed [&_strong]:text-neutral-200 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:bg-neutral-700/40 [&_code]:border [&_code]:border-neutral-500/40 [&_code]:text-neutral-200 [&_code]:font-mono [&_code]:text-sm [&_h1]:text-lg [&_h1]:font-semibold [&_h1]:text-neutral-200 [&_h1]:mb-2 [&_h2]:text-base [&_h2]:font-semibold [&_h2]:text-neutral-200 [&_h2]:mb-2 [&_h3]:text-md [&_h3]:font-medium [&_h3]:text-neutral-200 [&_h3]:mb-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-1 [&_p]:mb-2 [&_pre]:bg-neutral-900 [&_pre]:rounded [&_pre]:p-3 [&_pre]:overflow-x-auto [&_pre]:text-sm'
|
|
46
46
|
|
|
47
47
|
// ── CollapsibleSection ────────────────────────────────────────────────────────
|
|
48
48
|
|
|
@@ -78,7 +78,7 @@ function CollapsibleTextSection({ children, header }: { children: string; header
|
|
|
78
78
|
{(header || overflows) && (
|
|
79
79
|
<div className="flex items-center justify-between mb-2">
|
|
80
80
|
{header && (
|
|
81
|
-
<h3 className="text-
|
|
81
|
+
<h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider">{header}</h3>
|
|
82
82
|
)}
|
|
83
83
|
{overflows && (
|
|
84
84
|
<IconButton
|
|
@@ -117,12 +117,12 @@ function CompatibleWithSection({ tools }: { tools: string[] }) {
|
|
|
117
117
|
|
|
118
118
|
return (
|
|
119
119
|
<div>
|
|
120
|
-
<h3 className="text-
|
|
120
|
+
<h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-3">Compatible with</h3>
|
|
121
121
|
<div className="flex items-start gap-3">
|
|
122
122
|
{tools.map((tool) => (
|
|
123
123
|
<div key={tool} className="flex flex-col items-center gap-1">
|
|
124
124
|
<AiToolIcon tool={tool} size={18} />
|
|
125
|
-
<span className="text-
|
|
125
|
+
<span className="text-xs text-neutral-400">{AI_TOOL_NAMES[tool as AiToolKey] ?? tool}</span>
|
|
126
126
|
</div>
|
|
127
127
|
))}
|
|
128
128
|
</div>
|
|
@@ -181,8 +181,8 @@ export function RegistryDetail({
|
|
|
181
181
|
{/* Description */}
|
|
182
182
|
{description && (
|
|
183
183
|
<div>
|
|
184
|
-
<h3 className="text-
|
|
185
|
-
<p className="text-
|
|
184
|
+
<h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-2">Description</h3>
|
|
185
|
+
<p className="text-md text-neutral-400 leading-relaxed">{description}</p>
|
|
186
186
|
</div>
|
|
187
187
|
)}
|
|
188
188
|
|
|
@@ -35,10 +35,10 @@ const ICON_SIZE_CLASSES = {
|
|
|
35
35
|
/** Text label button sizes — horizontal padding instead of fixed width */
|
|
36
36
|
const TEXT_SIZE_CLASSES = {
|
|
37
37
|
xss: 'h-[18px] px-1.5 text-xss',
|
|
38
|
-
xs: 'h-6 px-2 text-
|
|
39
|
-
sm: 'h-7 px-2.5 text-
|
|
40
|
-
md: 'h-8 px-3 text-
|
|
41
|
-
lg: 'h-9 px-3.5 text-
|
|
38
|
+
xs: 'h-6 px-2 text-xs',
|
|
39
|
+
sm: 'h-7 px-2.5 text-sm',
|
|
40
|
+
md: 'h-8 px-3 text-sm',
|
|
41
|
+
lg: 'h-9 px-3.5 text-md',
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const ROUNDING_CLASSES = {
|
package/components/ui/select.tsx
CHANGED
|
@@ -30,10 +30,10 @@ const VARIANT_CLASSES = {
|
|
|
30
30
|
|
|
31
31
|
const SIZE_CLASSES = {
|
|
32
32
|
xss: 'h-[18px] px-1.5 text-xss',
|
|
33
|
-
xs: 'h-6 px-2 text-
|
|
34
|
-
sm: 'h-7 px-2 text-
|
|
35
|
-
md: 'h-8 px-3 text-
|
|
36
|
-
lg: 'h-9 px-3 text-
|
|
33
|
+
xs: 'h-6 px-2 text-sm',
|
|
34
|
+
sm: 'h-7 px-2 text-sm',
|
|
35
|
+
md: 'h-8 px-3 text-md',
|
|
36
|
+
lg: 'h-9 px-3 text-md',
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function Select<T extends string | number = string>({
|
|
@@ -152,7 +152,7 @@ export function Select<T extends string | number = string>({
|
|
|
152
152
|
data-idx={idx}
|
|
153
153
|
onClick={() => { onChange(opt.value); close() }}
|
|
154
154
|
onPointerEnter={() => setHighlightIdx(idx)}
|
|
155
|
-
className={`w-full flex items-center gap-2 px-3 py-1.5 text-
|
|
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}`
|
|
@@ -251,10 +251,10 @@ function GridCard({ item, selected, onClick }: CardProps) {
|
|
|
251
251
|
/>
|
|
252
252
|
)}
|
|
253
253
|
|
|
254
|
-
<span className="text-
|
|
254
|
+
<span className="text-sm font-medium text-neutral-200 block">{item.name}</span>
|
|
255
255
|
|
|
256
256
|
{item.description && (
|
|
257
|
-
<span className="text-
|
|
257
|
+
<span className="text-sm text-neutral-500 block mt-0.5">{item.description}</span>
|
|
258
258
|
)}
|
|
259
259
|
</button>
|
|
260
260
|
)
|
|
@@ -291,9 +291,9 @@ function ListCard({ item, selected, onClick }: CardProps) {
|
|
|
291
291
|
)}
|
|
292
292
|
|
|
293
293
|
<div className="min-w-0">
|
|
294
|
-
<span className="text-
|
|
294
|
+
<span className="text-sm font-medium text-neutral-200 block">{item.name}</span>
|
|
295
295
|
{item.description && (
|
|
296
|
-
<span className="text-
|
|
296
|
+
<span className="text-sm text-neutral-500 block mt-0.5">{item.description}</span>
|
|
297
297
|
)}
|
|
298
298
|
</div>
|
|
299
299
|
</button>
|
|
@@ -58,7 +58,7 @@ export function SettingRow(props: SettingRowProps) {
|
|
|
58
58
|
<div className={`flex items-start justify-between gap-4 ${className}`}>
|
|
59
59
|
<div>
|
|
60
60
|
<label className="text-neutral-200 leading-7">{label}</label>
|
|
61
|
-
{description && <p className="text-
|
|
61
|
+
{description && <p className="text-md text-neutral-500">{description}</p>}
|
|
62
62
|
</div>
|
|
63
63
|
{props.type === 'toggle' && (
|
|
64
64
|
<Toggle
|
|
@@ -16,11 +16,11 @@ export function SettingsCard({ children, className, title, description, testId }
|
|
|
16
16
|
>
|
|
17
17
|
{title && (
|
|
18
18
|
<div>
|
|
19
|
-
<h3 className="text-
|
|
20
|
-
{description && <p className="text-
|
|
19
|
+
<h3 className="text-md font-medium text-neutral-200">{title}</h3>
|
|
20
|
+
{description && <p className="text-md text-neutral-500 mt-1">{description}</p>}
|
|
21
21
|
</div>
|
|
22
22
|
)}
|
|
23
|
-
{!title && description && <p className="text-
|
|
23
|
+
{!title && description && <p className="text-md text-neutral-500">{description}</p>}
|
|
24
24
|
{children}
|
|
25
25
|
</div>
|
|
26
26
|
)
|
|
@@ -74,7 +74,7 @@ export function SettingsInfoBox({ children, color = 'neutral', className, testId
|
|
|
74
74
|
data-testid={testId}
|
|
75
75
|
>
|
|
76
76
|
<Icon className={cn('w-4 h-4 mt-0.5 shrink-0', iconColorMap[color])} />
|
|
77
|
-
<div className="text-
|
|
77
|
+
<div className="text-md text-neutral-500">{children}</div>
|
|
78
78
|
</div>
|
|
79
79
|
)
|
|
80
80
|
}
|
|
@@ -15,7 +15,7 @@ export interface SettingsSectionTitleProps {
|
|
|
15
15
|
export function SettingsSectionTitle({ children, className = '', testId }: SettingsSectionTitleProps) {
|
|
16
16
|
return (
|
|
17
17
|
<h3
|
|
18
|
-
className={`text-
|
|
18
|
+
className={`text-sm font-medium text-neutral-400 uppercase tracking-wider ${className}`}
|
|
19
19
|
data-testid={testId}
|
|
20
20
|
>
|
|
21
21
|
{children}
|
|
@@ -48,7 +48,7 @@ export function SnapshotCard({
|
|
|
48
48
|
|
|
49
49
|
<div className="p-4">
|
|
50
50
|
<div className="flex items-start justify-between gap-2">
|
|
51
|
-
<h3 className="text-
|
|
51
|
+
<h3 className="text-md font-medium text-neutral-200 truncate">{title}</h3>
|
|
52
52
|
<Label
|
|
53
53
|
text={statusLabelConfig[status].text}
|
|
54
54
|
color={statusLabelConfig[status].color}
|
|
@@ -59,19 +59,19 @@ export function SnapshotCard({
|
|
|
59
59
|
</div>
|
|
60
60
|
|
|
61
61
|
{timestamp && (
|
|
62
|
-
<p className="mt-1 text-
|
|
62
|
+
<p className="mt-1 text-xs text-neutral-500">{timestamp}</p>
|
|
63
63
|
)}
|
|
64
64
|
|
|
65
65
|
{description && (
|
|
66
|
-
<p className="mt-2 text-
|
|
66
|
+
<p className="mt-2 text-sm text-neutral-500 leading-relaxed line-clamp-2">{description}</p>
|
|
67
67
|
)}
|
|
68
68
|
|
|
69
69
|
{stats && stats.length > 0 && (
|
|
70
70
|
<div className="mt-3 grid grid-cols-2 gap-x-4 gap-y-2">
|
|
71
71
|
{stats.map((stat) => (
|
|
72
72
|
<div key={stat.label}>
|
|
73
|
-
<p className="text-
|
|
74
|
-
<p className="text-
|
|
73
|
+
<p className="text-xs text-neutral-500">{stat.label}</p>
|
|
74
|
+
<p className="text-sm font-medium text-neutral-200">{stat.value}</p>
|
|
75
75
|
</div>
|
|
76
76
|
))}
|
|
77
77
|
</div>
|
|
@@ -83,7 +83,7 @@ export function SnapshotCard({
|
|
|
83
83
|
<button
|
|
84
84
|
type="button"
|
|
85
85
|
onClick={onSync}
|
|
86
|
-
className="flex items-center gap-1.5 px-2.5 py-1 text-
|
|
86
|
+
className="flex items-center gap-1.5 px-2.5 py-1 text-sm font-medium rounded-md bg-blue-400/15 text-blue-400 hover:bg-blue-400/25 transition-colors cursor-pointer"
|
|
87
87
|
>
|
|
88
88
|
<RefreshCw className={cn('w-3 h-3', status === 'pending' && 'animate-spin')} />
|
|
89
89
|
Sync
|
|
@@ -93,7 +93,7 @@ export function SnapshotCard({
|
|
|
93
93
|
<button
|
|
94
94
|
type="button"
|
|
95
95
|
onClick={onView}
|
|
96
|
-
className="flex items-center gap-1.5 px-2.5 py-1 text-
|
|
96
|
+
className="flex items-center gap-1.5 px-2.5 py-1 text-sm font-medium rounded-md text-neutral-400 hover:bg-neutral-700 transition-colors cursor-pointer"
|
|
97
97
|
>
|
|
98
98
|
<Eye className="w-3 h-3" />
|
|
99
99
|
View
|