@toolr/ui-design 0.1.3 → 0.1.4
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/README.md +0 -7
- package/components/content/info-panel-primitives.tsx +3 -3
- package/components/lib/ai-tools.tsx +1 -1
- package/components/lib/theme-engine.ts +10 -0
- package/components/sections/captured-issues/captured-issues-panel.tsx +1 -1
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +2 -2
- package/components/sections/golden-snapshots/snapshot-manager.tsx +3 -3
- package/components/sections/golden-snapshots/status-overview.tsx +4 -4
- package/components/sections/golden-snapshots/version-manager.tsx +3 -3
- package/components/sections/report-bug/screenshot-uploader.tsx +2 -2
- package/components/sections/snapshot-browser/snapshot-tree.tsx +1 -1
- package/components/sections/snippets-editor/snippets-editor.tsx +5 -5
- package/components/ui/action-dialog.tsx +1 -1
- package/components/ui/badge.tsx +4 -4
- package/components/ui/breadcrumb.tsx +1 -1
- package/components/ui/file-structure-section.tsx +4 -4
- package/components/ui/files-panel.tsx +5 -5
- package/components/ui/filter-dropdown.tsx +2 -2
- package/components/ui/frontmatter-form-header.tsx +2 -2
- package/components/ui/input.tsx +1 -1
- package/components/ui/label.tsx +4 -4
- package/components/ui/modal.tsx +1 -1
- package/components/ui/nav-card.tsx +1 -1
- package/components/ui/navigation-bar.tsx +1 -1
- package/components/ui/number-input.tsx +1 -1
- package/components/ui/registry-card.tsx +7 -7
- package/components/ui/registry-detail.tsx +2 -2
- package/components/ui/segmented-toggle.tsx +2 -2
- package/components/ui/select.tsx +2 -2
- package/components/ui/selection-grid.tsx +7 -19
- package/components/ui/snapshot-card.tsx +2 -2
- package/components/ui/snippets-panel.tsx +9 -9
- package/components/ui/tab-bar.tsx +1 -1
- package/dist/content.js +3 -3
- package/dist/index.d.ts +10 -0
- package/dist/index.js +78 -80
- package/dist/tokens/primitives.css +10 -0
- package/dist/tokens/semantic.css +3 -0
- package/package.json +1 -7
- package/tokens/primitives.css +10 -0
- package/tokens/semantic.css +3 -0
- package/dist/preset.d.ts +0 -24
- package/dist/preset.js +0 -17
- package/tailwind-preset.ts +0 -22
package/README.md
CHANGED
|
@@ -14,19 +14,12 @@ Shared UI design system for toolr applications. Provides components, design toke
|
|
|
14
14
|
@import "@toolr/ui-design/tokens";
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
```ts
|
|
18
|
-
// tailwind.config.ts
|
|
19
|
-
import { toolrPreset } from '@toolr/ui-design/preset'
|
|
20
|
-
export default { presets: [toolrPreset] }
|
|
21
|
-
```
|
|
22
|
-
|
|
23
17
|
## Exports
|
|
24
18
|
|
|
25
19
|
| Path | Content |
|
|
26
20
|
|------|---------|
|
|
27
21
|
| `@toolr/ui-design` | All components, hooks, types, utilities |
|
|
28
22
|
| `@toolr/ui-design/tokens` | CSS design tokens (semantic + primitives + keyframes) |
|
|
29
|
-
| `@toolr/ui-design/preset` | Tailwind preset (Inter font, extended breakpoints) |
|
|
30
23
|
| `@toolr/ui-design/content` | Info panel primitives |
|
|
31
24
|
| `@toolr/ui-design/diagrams` | Diagram utilities |
|
|
32
25
|
|
|
@@ -114,7 +114,7 @@ export function Callout({ color, children }: { color: string; children: ReactNod
|
|
|
114
114
|
export function CalloutCode({ color, children }: { color: string; children: ReactNode }) {
|
|
115
115
|
const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
|
|
116
116
|
return (
|
|
117
|
-
<code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-
|
|
117
|
+
<code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-sm ${c.codeText}`}>
|
|
118
118
|
{children}
|
|
119
119
|
</code>
|
|
120
120
|
)
|
|
@@ -204,7 +204,7 @@ export function TitledLI({ color, title, children }: { color: string; title: str
|
|
|
204
204
|
|
|
205
205
|
export function CalloutDialog({ color, lines }: { color: string; lines: { speaker: string; text: string }[] }) {
|
|
206
206
|
return (
|
|
207
|
-
<div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-
|
|
207
|
+
<div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-sm">
|
|
208
208
|
{lines.map((line, idx) => (
|
|
209
209
|
<div key={idx}>
|
|
210
210
|
<span className={`text-${color}-300 font-semibold mr-1`}>{line.speaker}:</span>
|
|
@@ -238,7 +238,7 @@ export function StatusBadge({ value, badgeColor, label, children, even }: {
|
|
|
238
238
|
<DLRow
|
|
239
239
|
term={
|
|
240
240
|
<span className="flex items-center gap-1.5">
|
|
241
|
-
<span className={`inline-flex items-center justify-center w-5 h-5 rounded-full bg-${badgeColor}-500/20 text-${badgeColor}-400 text-
|
|
241
|
+
<span className={`inline-flex items-center justify-center w-5 h-5 rounded-full bg-${badgeColor}-500/20 text-${badgeColor}-400 text-xss font-bold shrink-0`}>{value}</span>
|
|
242
242
|
<span className={`text-${badgeColor}-400 font-semibold`}>{label}</span>
|
|
243
243
|
</span>
|
|
244
244
|
}
|
|
@@ -38,7 +38,7 @@ export function AiToolIcon({ tool, size, showName, className, style }: {
|
|
|
38
38
|
return (
|
|
39
39
|
<span style={{ display: 'inline-flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
|
|
40
40
|
{img}
|
|
41
|
-
<span className="text-
|
|
41
|
+
<span className="text-xss text-neutral-400">{AI_TOOL_NAMES[tool as AiToolKey] ?? tool}</span>
|
|
42
42
|
</span>
|
|
43
43
|
)
|
|
44
44
|
}
|
|
@@ -109,6 +109,16 @@ export function isLightTheme(themeId: ThemeId): boolean {
|
|
|
109
109
|
return LIGHT_THEMES.includes(themeId)
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Apply a theme to the document by setting CSS custom properties on the root element.
|
|
114
|
+
*
|
|
115
|
+
* IMPORTANT — body background: Portal-based components (Select, Tooltip) render at
|
|
116
|
+
* document.body via createPortal. Their backgrounds use --popover which is semi-transparent
|
|
117
|
+
* (rgba(0,0,0,0.8)). If <body> has no background-color, the browser default (white) bleeds
|
|
118
|
+
* through, making dropdowns/tooltips appear gray instead of dark.
|
|
119
|
+
*
|
|
120
|
+
* Consuming apps MUST set: body { background-color: var(--background); }
|
|
121
|
+
*/
|
|
112
122
|
export function applyTheme(themeId: ThemeId, accentHue: number | null, dims: Record<SurfaceKey, number> = DEFAULT_DIMS, outline: number = DEFAULT_OUTLINE, root: HTMLElement = document.documentElement): void {
|
|
113
123
|
const scale = generateScale(themeId, accentHue, BASE_THEMES[themeId].maxSat, dims, outline)
|
|
114
124
|
const light = isLightTheme(themeId)
|
|
@@ -163,7 +163,7 @@ export function CapturedIssuesPanel({
|
|
|
163
163
|
<Check className="w-5 h-5 text-green-400" />
|
|
164
164
|
</div>
|
|
165
165
|
<div>
|
|
166
|
-
<h3 className="text-neutral-300 font-medium">No Issues Captured</h3>
|
|
166
|
+
<h3 className="text-sm text-neutral-300 font-medium">No Issues Captured</h3>
|
|
167
167
|
<p className="text-sm text-neutral-500">Everything is running smoothly.</p>
|
|
168
168
|
</div>
|
|
169
169
|
</div>
|
|
@@ -93,7 +93,7 @@ function DiffFileItem({ file, isSelected, onSelect, onReset, resettingFile, anyR
|
|
|
93
93
|
{icon}
|
|
94
94
|
<span className="truncate">{filename}</span>
|
|
95
95
|
{statusLabel && (
|
|
96
|
-
<span className={`text-
|
|
96
|
+
<span className={`text-xss font-medium ml-auto flex-shrink-0 ${statusColor}`}>
|
|
97
97
|
{statusLabel}
|
|
98
98
|
</span>
|
|
99
99
|
)}
|
|
@@ -171,7 +171,7 @@ function DiffFileTreePanel({ sync, componentLabels, renderFileIcon }: DiffFileTr
|
|
|
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-xss font-medium ${color.pillBg} ${color.text}`}>
|
|
175
175
|
{fileCount}
|
|
176
176
|
</span>
|
|
177
177
|
) : (
|
|
@@ -54,7 +54,7 @@ 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-neutral-300 font-medium">Create Snapshot</h4>
|
|
57
|
+
<h4 className="text-sm text-neutral-300 font-medium">Create Snapshot</h4>
|
|
58
58
|
</div>
|
|
59
59
|
<p className="text-xs text-neutral-600 mb-3">
|
|
60
60
|
Archives the current live state. If components differ from golden, their patch version is auto-bumped.
|
|
@@ -85,7 +85,7 @@ 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-neutral-300 font-medium">Snapshots</h4>
|
|
88
|
+
<h4 className="text-sm text-neutral-300 font-medium">Snapshots</h4>
|
|
89
89
|
<span className="text-xs text-neutral-500">({manifest?.snapshots.length ?? 0})</span>
|
|
90
90
|
</div>
|
|
91
91
|
<IconButton
|
|
@@ -114,7 +114,7 @@ export function SnapshotManager({ sync }: SnapshotManagerProps) {
|
|
|
114
114
|
<div className="flex items-center gap-2">
|
|
115
115
|
<span className="text-sm 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-xss rounded font-medium">
|
|
118
118
|
active
|
|
119
119
|
</span>
|
|
120
120
|
)}
|
|
@@ -84,7 +84,7 @@ 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-neutral-300 font-medium">Bundled Seed (App Distribution)</h3>
|
|
87
|
+
<h3 className="text-sm 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
90
|
<div className="grid grid-cols-2 gap-4 text-sm">
|
|
@@ -121,7 +121,7 @@ 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-neutral-300 font-medium">Golden (Reference)</h4>
|
|
124
|
+
<h4 className="text-sm text-neutral-300 font-medium">Golden (Reference)</h4>
|
|
125
125
|
{renderVersionBadge(status?.goldenMeta, 'bg-blue-500/20 text-blue-400')}
|
|
126
126
|
</div>
|
|
127
127
|
<div className="space-y-2 text-sm">
|
|
@@ -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-neutral-300 font-medium">Live (Working Copy)</h4>
|
|
156
|
+
<h4 className="text-sm 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
|
|
@@ -290,7 +290,7 @@ 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-neutral-300 font-medium">Local Snapshots</h4>
|
|
293
|
+
<h4 className="text-sm text-neutral-300 font-medium">Local Snapshots</h4>
|
|
294
294
|
</div>
|
|
295
295
|
<div className="flex gap-6 text-sm">
|
|
296
296
|
<div>
|
|
@@ -56,7 +56,7 @@ 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-neutral-300 font-medium">Golden Version</h4>
|
|
59
|
+
<h4 className="text-sm text-neutral-300 font-medium">Golden Version</h4>
|
|
60
60
|
{status?.goldenMeta && (
|
|
61
61
|
<span className="px-2 py-0.5 bg-teal-500/20 text-teal-400 text-xs rounded font-mono">
|
|
62
62
|
{status.goldenMeta.version}
|
|
@@ -100,7 +100,7 @@ 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-neutral-300 font-medium">Component Versions</h4>
|
|
103
|
+
<h4 className="text-sm text-neutral-300 font-medium">Component Versions</h4>
|
|
104
104
|
<p className="text-xs text-neutral-600 mt-1">
|
|
105
105
|
Update individual component versions. Click a component to edit.
|
|
106
106
|
</p>
|
|
@@ -122,7 +122,7 @@ export function VersionManager({ sync, components, componentLabels }: VersionMan
|
|
|
122
122
|
<span className="text-xs font-mono text-neutral-500">v{currentVersion}</span>
|
|
123
123
|
)}
|
|
124
124
|
{mismatch && (
|
|
125
|
-
<span className="text-
|
|
125
|
+
<span className="text-xss text-yellow-400">
|
|
126
126
|
(live: v{liveVersion})
|
|
127
127
|
</span>
|
|
128
128
|
)}
|
|
@@ -195,7 +195,7 @@ export function ScreenshotUploader({
|
|
|
195
195
|
alt={s.filename}
|
|
196
196
|
className="w-full h-full object-cover"
|
|
197
197
|
/>
|
|
198
|
-
<div className="absolute inset-0 bg-
|
|
198
|
+
<div className="absolute inset-0 bg-[var(--background)]/60 opacity-0 group-hover:opacity-100 transition-opacity flex flex-col justify-between p-2">
|
|
199
199
|
<button
|
|
200
200
|
type="button"
|
|
201
201
|
onClick={(e) => {
|
|
@@ -209,7 +209,7 @@ export function ScreenshotUploader({
|
|
|
209
209
|
</button>
|
|
210
210
|
<span className="text-xs text-white truncate">{s.filename}</span>
|
|
211
211
|
</div>
|
|
212
|
-
<div className="absolute bottom-1 right-1 px-1.5 py-0.5 bg-
|
|
212
|
+
<div className="absolute bottom-1 right-1 px-1.5 py-0.5 bg-[var(--background)]/70 rounded text-xs text-neutral-400">
|
|
213
213
|
{formatFileSize(s.size)}
|
|
214
214
|
</div>
|
|
215
215
|
</div>
|
|
@@ -201,7 +201,7 @@ function SnapshotEntryRow({
|
|
|
201
201
|
<span className="text-xs flex-1 truncate">
|
|
202
202
|
{searchQuery ? highlightMatch(displayName, searchQuery) : displayName}
|
|
203
203
|
</span>
|
|
204
|
-
<span className="text-
|
|
204
|
+
<span className="text-xss text-neutral-500 shrink-0" title={formatFullDate(entry.savedAt)}>
|
|
205
205
|
{formatRelativeTime(entry.savedAt)}
|
|
206
206
|
</span>
|
|
207
207
|
<IconButton
|
|
@@ -144,7 +144,7 @@ export function SnippetsEditor({
|
|
|
144
144
|
<p className="text-xs text-neutral-500 mb-1">
|
|
145
145
|
{searchQuery ? 'No matching snippets' : 'No snippets defined'}
|
|
146
146
|
</p>
|
|
147
|
-
<p className="text-
|
|
147
|
+
<p className="text-xss text-neutral-600">
|
|
148
148
|
{searchQuery ? 'Try a different search term' : 'Click + to add your first snippet'}
|
|
149
149
|
</p>
|
|
150
150
|
</div>
|
|
@@ -228,11 +228,11 @@ function SnippetListItem({ snippet, selected, onSelect, onDelete }: SnippetListI
|
|
|
228
228
|
<p className="text-xs font-mono font-medium text-neutral-300 truncate">
|
|
229
229
|
{snippet.name}
|
|
230
230
|
</p>
|
|
231
|
-
<p className="text-
|
|
231
|
+
<p className="text-xss text-neutral-500 truncate mt-0.5">
|
|
232
232
|
{snippet.description}
|
|
233
233
|
</p>
|
|
234
234
|
{snippet.value && (
|
|
235
|
-
<p className="text-
|
|
235
|
+
<p className="text-xss text-neutral-600 truncate mt-0.5 font-mono">
|
|
236
236
|
{snippet.value.slice(0, 80)}{snippet.value.length > 80 ? '...' : ''}
|
|
237
237
|
</p>
|
|
238
238
|
)}
|
|
@@ -292,7 +292,7 @@ function SnippetForm({
|
|
|
292
292
|
error={nameHasError}
|
|
293
293
|
autoFocus={!isEditing}
|
|
294
294
|
/>
|
|
295
|
-
<p className="mt-1 text-
|
|
295
|
+
<p className="mt-1 text-xss text-neutral-600">
|
|
296
296
|
Use in prompts as <span className="font-mono text-purple-400">{'{{' + (formData.name || 'NAME') + '}}'}</span>
|
|
297
297
|
</p>
|
|
298
298
|
</div>
|
|
@@ -319,7 +319,7 @@ function SnippetForm({
|
|
|
319
319
|
onChange={(val) => setFormField('value', val)}
|
|
320
320
|
minHeight={160}
|
|
321
321
|
/>
|
|
322
|
-
<p className="mt-1 text-
|
|
322
|
+
<p className="mt-1 text-xss text-neutral-600">
|
|
323
323
|
Can be a single value, multi-line text, or an entire document
|
|
324
324
|
</p>
|
|
325
325
|
</div>
|
|
@@ -194,7 +194,7 @@ export function ActionDialog({
|
|
|
194
194
|
|
|
195
195
|
return createPortal(
|
|
196
196
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
197
|
-
<div className="absolute inset-0 bg-
|
|
197
|
+
<div className="absolute inset-0 bg-[var(--dialog-backdrop)] backdrop-blur-sm" onClick={onCancel} />
|
|
198
198
|
<div
|
|
199
199
|
className={cn(
|
|
200
200
|
'relative bg-neutral-950 border border-neutral-700 rounded-xl shadow-2xl w-full max-w-[800px] mx-4 flex flex-col',
|
package/components/ui/badge.tsx
CHANGED
|
@@ -42,10 +42,10 @@ const colorClasses: Record<BadgeColor, string> = {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const sizeClasses = {
|
|
45
|
-
xss: 'min-w-[14px] h-[14px] px-0.5 text-
|
|
46
|
-
xs: 'min-w-[16px] h-[16px] px-1 text-
|
|
47
|
-
sm: 'min-w-[18px] h-[18px] px-1 text-
|
|
48
|
-
md: 'min-w-[20px] h-[20px] px-1.5 text-
|
|
45
|
+
xss: 'min-w-[14px] h-[14px] px-0.5 text-xss',
|
|
46
|
+
xs: 'min-w-[16px] h-[16px] px-1 text-xss',
|
|
47
|
+
sm: 'min-w-[18px] h-[18px] px-1 text-xss',
|
|
48
|
+
md: 'min-w-[20px] h-[20px] px-1.5 text-xss',
|
|
49
49
|
lg: 'min-w-[22px] h-[22px] px-1.5 text-xs',
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -66,7 +66,7 @@ export interface BreadcrumbProps {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
const sizeConfig = {
|
|
69
|
-
xss: { text: 'text-
|
|
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
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
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' },
|
|
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' },
|
|
@@ -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-
|
|
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">
|
|
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,12 +104,12 @@ 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-
|
|
107
|
+
<pre key={i} className="mb-2 p-2 bg-[var(--background)]/30 rounded text-xss 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-
|
|
112
|
+
nodes.push(<h3 key={i} className="text-xss font-semibold text-neutral-300 mt-2 mb-0.5">{line.slice(4)}</h3>)
|
|
113
113
|
} else if (line.startsWith('## ')) {
|
|
114
114
|
nodes.push(<h2 key={i} className="text-xs font-semibold text-neutral-200 mt-2.5 mb-1">{line.slice(3)}</h2>)
|
|
115
115
|
} else if (line.startsWith('# ')) {
|
|
@@ -117,7 +117,7 @@ function renderMarkdownContent(content: string) {
|
|
|
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-
|
|
120
|
+
nodes.push(<p key={i} className="text-xss text-neutral-400 leading-relaxed">{line}</p>)
|
|
121
121
|
}
|
|
122
122
|
i++
|
|
123
123
|
}
|
|
@@ -144,7 +144,7 @@ function FileNode({ entry, depth, selectedPath, expandedPaths, onToggleExpand, o
|
|
|
144
144
|
/>
|
|
145
145
|
<span className="truncate">{entry.name}</span>
|
|
146
146
|
{entry.badge && (
|
|
147
|
-
<span className="ml-auto shrink-0 px-1.5 py-0.5 text-
|
|
147
|
+
<span className="ml-auto shrink-0 px-1.5 py-0.5 text-xss rounded bg-neutral-700 text-neutral-500">
|
|
148
148
|
{entry.badge}
|
|
149
149
|
</span>
|
|
150
150
|
)}
|
|
@@ -210,12 +210,12 @@ export function FilesPanel({
|
|
|
210
210
|
return (
|
|
211
211
|
<div className={cn('flex flex-col bg-neutral-800 rounded-lg overflow-hidden', className)}>
|
|
212
212
|
<div className="flex items-center justify-between px-3 py-2 border-b border-neutral-700">
|
|
213
|
-
<span className="text-
|
|
214
|
-
<span className="text-
|
|
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>
|
|
215
215
|
</div>
|
|
216
216
|
{showSearch && (
|
|
217
217
|
<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-
|
|
218
|
+
<div className="flex items-center gap-1.5 px-2 py-1 bg-[var(--background)] border border-neutral-700 rounded text-xs">
|
|
219
219
|
<Search className="w-3 h-3 text-neutral-500 shrink-0" />
|
|
220
220
|
<input
|
|
221
221
|
type="text"
|
|
@@ -243,7 +243,7 @@ export function FilesPanel({
|
|
|
243
243
|
))}
|
|
244
244
|
</ul>
|
|
245
245
|
{displayedFiles.length === 0 && (
|
|
246
|
-
<p className="text-
|
|
246
|
+
<p className="text-xss text-neutral-500 text-center py-4">No files found</p>
|
|
247
247
|
)}
|
|
248
248
|
</div>
|
|
249
249
|
</div>
|
|
@@ -135,7 +135,7 @@ export function FilterDropdown({
|
|
|
135
135
|
onClick={() => handleSelect('all')}
|
|
136
136
|
className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs 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}`
|
|
140
140
|
}`}
|
|
141
141
|
>
|
|
@@ -154,7 +154,7 @@ export function FilterDropdown({
|
|
|
154
154
|
onClick={() => handleSelect(opt.value)}
|
|
155
155
|
className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs 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}`
|
|
159
159
|
}`}
|
|
160
160
|
>
|
|
@@ -43,12 +43,12 @@ export function FrontmatterFormHeader({
|
|
|
43
43
|
Configuration
|
|
44
44
|
</span>
|
|
45
45
|
{collapsed && hasFm && (
|
|
46
|
-
<span className="text-
|
|
46
|
+
<span className="text-xss text-neutral-500 font-mono ml-2 truncate">
|
|
47
47
|
{renderSummary()}
|
|
48
48
|
</span>
|
|
49
49
|
)}
|
|
50
50
|
{collapsed && !hasFm && (
|
|
51
|
-
<span className="text-
|
|
51
|
+
<span className="text-xss text-neutral-600 ml-2">No frontmatter</span>
|
|
52
52
|
)}
|
|
53
53
|
</button>
|
|
54
54
|
|
package/components/ui/input.tsx
CHANGED
|
@@ -38,7 +38,7 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const sizeClasses = {
|
|
41
|
-
xss: 'px-1 py-0.5 text-
|
|
41
|
+
xss: 'px-1 py-0.5 text-xss',
|
|
42
42
|
xs: 'px-1.5 py-0.5 text-xs',
|
|
43
43
|
sm: 'px-2 py-1 text-xs',
|
|
44
44
|
md: 'px-3 py-1.5 text-sm',
|
package/components/ui/label.tsx
CHANGED
|
@@ -86,10 +86,10 @@ const progressFillColors: Record<LabelColor, string> = {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
const sizeConfig = {
|
|
89
|
-
xss: { height: 14, padding: 'px-1', text: 'text-
|
|
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-
|
|
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-xss', iconSize: 'w-2.5 h-2.5', gap: 'gap-1' },
|
|
91
|
+
sm: { height: 18, padding: 'px-1.5', text: 'text-xss', iconSize: 'w-2.5 h-2.5', gap: 'gap-1.5' },
|
|
92
|
+
md: { height: 20, padding: 'px-1.5', text: 'text-xss', iconSize: 'w-3 h-3', gap: 'gap-1' },
|
|
93
93
|
lg: { height: 22, padding: 'px-2', text: 'text-xs', iconSize: 'w-3 h-3', gap: 'gap-1' },
|
|
94
94
|
}
|
|
95
95
|
|
package/components/ui/modal.tsx
CHANGED
|
@@ -61,7 +61,7 @@ function Modal({ isOpen, onClose, title, children, kind = 'info', size = 'md', h
|
|
|
61
61
|
|
|
62
62
|
return createPortal(
|
|
63
63
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
64
|
-
<div className="absolute inset-0 bg-
|
|
64
|
+
<div className="absolute inset-0 bg-[var(--dialog-backdrop)] backdrop-blur-sm" onClick={onClose} />
|
|
65
65
|
<div
|
|
66
66
|
ref={modalRef}
|
|
67
67
|
data-testid={testId}
|
|
@@ -51,7 +51,7 @@ export function NavCard({
|
|
|
51
51
|
disabled={disabled}
|
|
52
52
|
className={cn(
|
|
53
53
|
'relative w-full text-left rounded-lg border border-neutral-700 bg-neutral-800 p-4 transition-all duration-200 cursor-pointer',
|
|
54
|
-
!disabled && 'hover:-translate-y-0.5 hover:
|
|
54
|
+
!disabled && 'hover:-translate-y-0.5 hover:border-neutral-600 hover:bg-neutral-700',
|
|
55
55
|
disabled && 'opacity-50 cursor-not-allowed',
|
|
56
56
|
className,
|
|
57
57
|
)}
|
|
@@ -69,7 +69,7 @@ export interface NavigationBarProps {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
const sizeConfig = {
|
|
72
|
-
xss: { text: 'text-
|
|
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
73
|
xs: { text: 'text-xs', 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
74
|
sm: { text: 'text-sm', 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' },
|
|
@@ -16,7 +16,7 @@ export interface NumberInputProps {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const SIZE_CONFIG = {
|
|
19
|
-
xss: { wrapper: 'h-[18px]', input: 'px-1 text-
|
|
19
|
+
xss: { wrapper: 'h-[18px]', input: 'px-1 text-xss', chevron: 'w-2.5 h-2.5', stepperW: 'w-4' },
|
|
20
20
|
xs: { wrapper: 'h-6', input: 'px-1.5 text-xs', chevron: 'w-2.5 h-2.5', stepperW: 'w-5' },
|
|
21
21
|
sm: { wrapper: 'h-7', input: 'px-2 text-xs', chevron: 'w-3 h-3', stepperW: 'w-5' },
|
|
22
22
|
md: { wrapper: 'h-8', input: 'px-3 text-sm', chevron: 'w-3 h-3', stepperW: 'w-6' },
|
|
@@ -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-xss 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-xss 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-xss 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-xss text-neutral-500">
|
|
585
585
|
<Download className="w-3 h-3" />
|
|
586
586
|
{props.installs.toLocaleString()}
|
|
587
587
|
</span>
|
|
@@ -642,7 +642,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
642
642
|
|
|
643
643
|
{/* Error/warning message */}
|
|
644
644
|
{errorMessage && (
|
|
645
|
-
<p className={`text-
|
|
645
|
+
<p className={`text-xss 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-xss 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" />
|
|
@@ -690,7 +690,7 @@ export function RegistryCard(props: RegistryCardProps) {
|
|
|
690
690
|
// Basic fallback: just install on confirm
|
|
691
691
|
return (
|
|
692
692
|
<div onClick={(e) => e.stopPropagation()}>
|
|
693
|
-
<div className="fixed inset-0 bg-
|
|
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
695
|
<h3 className="text-sm font-medium text-neutral-200 mb-2">{ALREADY_AT_USER}</h3>
|
|
696
696
|
<p className="text-xs text-neutral-400 mb-4">
|
|
@@ -122,7 +122,7 @@ function CompatibleWithSection({ tools }: { tools: string[] }) {
|
|
|
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-xss text-neutral-400">{AI_TOOL_NAMES[tool as AiToolKey] ?? tool}</span>
|
|
126
126
|
</div>
|
|
127
127
|
))}
|
|
128
128
|
</div>
|
|
@@ -162,7 +162,7 @@ export function RegistryDetail({
|
|
|
162
162
|
<div className="min-w-0">
|
|
163
163
|
<div className="flex items-center gap-3 flex-wrap">
|
|
164
164
|
<Icon className={`w-6 h-6 shrink-0 ${iconColor}`} />
|
|
165
|
-
<h2 className="text-
|
|
165
|
+
<h2 className="text-lg font-semibold text-neutral-200">{title}</h2>
|
|
166
166
|
{labels && labels.length > 0 && labels.map((labelProps, i) => (
|
|
167
167
|
<Label key={i} size="lg" {...labelProps} />
|
|
168
168
|
))}
|
|
@@ -34,8 +34,8 @@ const ICON_SIZE_CLASSES = {
|
|
|
34
34
|
|
|
35
35
|
/** Text label button sizes — horizontal padding instead of fixed width */
|
|
36
36
|
const TEXT_SIZE_CLASSES = {
|
|
37
|
-
xss: 'h-[18px] px-1.5 text-
|
|
38
|
-
xs: 'h-6 px-2 text-
|
|
37
|
+
xss: 'h-[18px] px-1.5 text-xss',
|
|
38
|
+
xs: 'h-6 px-2 text-xss',
|
|
39
39
|
sm: 'h-7 px-2.5 text-xs',
|
|
40
40
|
md: 'h-8 px-3 text-xs',
|
|
41
41
|
lg: 'h-9 px-3.5 text-sm',
|
package/components/ui/select.tsx
CHANGED
|
@@ -29,7 +29,7 @@ const VARIANT_CLASSES = {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const SIZE_CLASSES = {
|
|
32
|
-
xss: 'h-[18px] px-1.5 text-
|
|
32
|
+
xss: 'h-[18px] px-1.5 text-xss',
|
|
33
33
|
xs: 'h-6 px-2 text-xs',
|
|
34
34
|
sm: 'h-7 px-2 text-xs',
|
|
35
35
|
md: 'h-8 px-3 text-sm',
|
|
@@ -154,7 +154,7 @@ export function Select<T extends string | number = string>({
|
|
|
154
154
|
onPointerEnter={() => setHighlightIdx(idx)}
|
|
155
155
|
className={`w-full flex items-center gap-2 px-3 py-1.5 text-xs 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}`
|
|
159
159
|
}`}
|
|
160
160
|
>
|