@toolr/ui-design 0.1.9 → 0.1.10
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/components/lib/form-colors.ts +16 -16
- package/components/lib/toolr-brand.tsx +1 -1
- package/components/ui/breadcrumb.tsx +5 -5
- package/components/ui/file-structure-section.tsx +5 -2
- package/components/ui/navigation-bar.tsx +129 -75
- package/components/ui/registry-detail.tsx +9 -9
- package/dist/index.d.ts +7 -3
- package/dist/index.js +136 -92
- package/package.json +1 -1
|
@@ -38,22 +38,22 @@ export const ACCENT_TEXT: Record<AccentColor, string> = {
|
|
|
38
38
|
|
|
39
39
|
export const ACCENT_ICON = ACCENT_TEXT
|
|
40
40
|
|
|
41
|
-
export const ACCENT_NAV: Record<AccentColor, { bg: string; text: string }> = {
|
|
42
|
-
blue: { bg: 'bg-blue-500/10', text: 'text-blue-400' },
|
|
43
|
-
green: { bg: 'bg-green-500/10', text: 'text-green-400' },
|
|
44
|
-
red: { bg: 'bg-red-500/10', text: 'text-red-400' },
|
|
45
|
-
orange: { bg: 'bg-orange-500/10', text: 'text-orange-400' },
|
|
46
|
-
cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-400' },
|
|
47
|
-
yellow: { bg: 'bg-yellow-500/10', text: 'text-yellow-400' },
|
|
48
|
-
purple: { bg: 'bg-purple-500/10', text: 'text-purple-400' },
|
|
49
|
-
indigo: { bg: 'bg-indigo-500/10', text: 'text-indigo-400' },
|
|
50
|
-
emerald: { bg: 'bg-emerald-500/10', text: 'text-emerald-400' },
|
|
51
|
-
amber: { bg: 'bg-amber-500/10', text: 'text-amber-400' },
|
|
52
|
-
violet: { bg: 'bg-violet-500/10', text: 'text-violet-400' },
|
|
53
|
-
neutral: { bg: 'bg-neutral-500/10', text: 'text-neutral-400' },
|
|
54
|
-
sky: { bg: 'bg-sky-500/10', text: 'text-sky-400' },
|
|
55
|
-
pink: { bg: 'bg-pink-500/10', text: 'text-pink-400' },
|
|
56
|
-
teal: { bg: 'bg-teal-500/10', text: 'text-teal-400' },
|
|
41
|
+
export const ACCENT_NAV: Record<AccentColor, { bg: string; text: string; border: string }> = {
|
|
42
|
+
blue: { bg: 'bg-blue-500/10', text: 'text-blue-400', border: 'border-blue-500/30' },
|
|
43
|
+
green: { bg: 'bg-green-500/10', text: 'text-green-400', border: 'border-green-500/30' },
|
|
44
|
+
red: { bg: 'bg-red-500/10', text: 'text-red-400', border: 'border-red-500/30' },
|
|
45
|
+
orange: { bg: 'bg-orange-500/10', text: 'text-orange-400', border: 'border-orange-500/30' },
|
|
46
|
+
cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-400', border: 'border-cyan-500/30' },
|
|
47
|
+
yellow: { bg: 'bg-yellow-500/10', text: 'text-yellow-400', border: 'border-yellow-500/30' },
|
|
48
|
+
purple: { bg: 'bg-purple-500/10', text: 'text-purple-400', border: 'border-purple-500/30' },
|
|
49
|
+
indigo: { bg: 'bg-indigo-500/10', text: 'text-indigo-400', border: 'border-indigo-500/30' },
|
|
50
|
+
emerald: { bg: 'bg-emerald-500/10', text: 'text-emerald-400', border: 'border-emerald-500/30' },
|
|
51
|
+
amber: { bg: 'bg-amber-500/10', text: 'text-amber-400', border: 'border-amber-500/30' },
|
|
52
|
+
violet: { bg: 'bg-violet-500/10', text: 'text-violet-400', border: 'border-violet-500/30' },
|
|
53
|
+
neutral: { bg: 'bg-neutral-500/10', text: 'text-neutral-400', border: 'border-neutral-500/30' },
|
|
54
|
+
sky: { bg: 'bg-sky-500/10', text: 'text-sky-400', border: 'border-sky-500/30' },
|
|
55
|
+
pink: { bg: 'bg-pink-500/10', text: 'text-pink-400', border: 'border-pink-500/30' },
|
|
56
|
+
teal: { bg: 'bg-teal-500/10', text: 'text-teal-400', border: 'border-teal-500/30' },
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export const FORM_COLORS: Record<FormColor, FormColorConfig> = {
|
|
@@ -9,7 +9,7 @@ export const TOOLR_APPS: Record<ToolrAppId, { name: string; accent: string }> =
|
|
|
9
9
|
configr: { name: 'Configr', accent: 'violet' }, // #8b5cf6
|
|
10
10
|
reviewr: { name: 'Reviewr', accent: 'orange' }, // #f97316
|
|
11
11
|
learnr: { name: 'Learnr', accent: 'yellow' }, // #eab308
|
|
12
|
-
seedr: { name: 'Seedr', accent: '
|
|
12
|
+
seedr: { name: 'Seedr', accent: 'green' }, // #22c55e
|
|
13
13
|
planr: { name: 'Planr', accent: 'pink' }, // #ec4899 (not in ACCENT_DEFS, fallback hex)
|
|
14
14
|
vibr: { name: 'Vibr', accent: 'red' }, // #ef4444
|
|
15
15
|
}
|
|
@@ -77,13 +77,13 @@ export function Breadcrumb({
|
|
|
77
77
|
<nav className={cn('flex items-center min-w-0', className)}>
|
|
78
78
|
<div className={cn(
|
|
79
79
|
'flex items-center gap-1',
|
|
80
|
-
isBox && [s.px, s.py, 'bg-neutral-960/50
|
|
80
|
+
isBox && [s.px, s.py, 'bg-neutral-960/50 rounded-lg'],
|
|
81
81
|
)}>
|
|
82
82
|
{segments.map((segment, index) => {
|
|
83
83
|
const isLast = index === segments.length - 1
|
|
84
84
|
const isClickable = !isLast && !!segment.onClick
|
|
85
85
|
const colors = segment.color && ACCENT_NAV[segment.color as AccentColor] ? ACCENT_NAV[segment.color as AccentColor] : null
|
|
86
|
-
const
|
|
86
|
+
const isFirst = !isBox && index === 0
|
|
87
87
|
|
|
88
88
|
return (
|
|
89
89
|
<div key={segment.id} className="flex items-center gap-1 min-w-0">
|
|
@@ -94,7 +94,7 @@ export function Breadcrumb({
|
|
|
94
94
|
onClick={segment.onClick}
|
|
95
95
|
className={cn(
|
|
96
96
|
'flex items-center gap-1.5 pr-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0',
|
|
97
|
-
|
|
97
|
+
isFirst ? 'pl-0' : 'pl-2',
|
|
98
98
|
s.text,
|
|
99
99
|
'font-medium hover:text-white',
|
|
100
100
|
colors ? [colors.text, `hover:${colors.bg}`] : ['text-neutral-300', 'hover:bg-neutral-700/50'],
|
|
@@ -107,10 +107,10 @@ export function Breadcrumb({
|
|
|
107
107
|
<div
|
|
108
108
|
className={cn(
|
|
109
109
|
'flex items-center gap-1.5 pr-2 py-0.5 rounded-md min-w-0',
|
|
110
|
-
|
|
110
|
+
isFirst ? 'pl-0' : 'pl-2',
|
|
111
111
|
s.text,
|
|
112
112
|
isLast
|
|
113
|
-
?
|
|
113
|
+
? 'font-medium text-white'
|
|
114
114
|
: ['font-medium', colors ? colors.text : 'text-neutral-300'],
|
|
115
115
|
)}
|
|
116
116
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef, useMemo, type ReactNode } from 'react'
|
|
2
2
|
import { FileCode, FolderTree, Loader2, AlertCircle, AlignLeft, Code2, Type } from 'lucide-react'
|
|
3
3
|
import { type AccentColor, ACCENT_ICON } from '../lib/form-colors.ts'
|
|
4
|
+
import { useAccentColor } from '../lib/accent-context.ts'
|
|
4
5
|
import { CollapseButton } from './icon-button.tsx'
|
|
5
6
|
import { SegmentedToggle } from './segmented-toggle.tsx'
|
|
6
7
|
import { FileTree, collectDirPaths, type FileTreeNode } from './file-tree.tsx'
|
|
@@ -124,10 +125,12 @@ export function FileStructureSection({
|
|
|
124
125
|
format,
|
|
125
126
|
language,
|
|
126
127
|
default: defaultMode,
|
|
127
|
-
accentColor
|
|
128
|
+
accentColor: accentColorProp,
|
|
128
129
|
renderPreview,
|
|
129
130
|
initialHeight,
|
|
130
131
|
}: FileStructureSectionProps) {
|
|
132
|
+
const contextAccent = useAccentColor()
|
|
133
|
+
const accentColor = accentColorProp ?? contextAccent ?? 'blue'
|
|
131
134
|
const [selectedFilePath, setSelectedFilePath] = useState<string | null>(null)
|
|
132
135
|
const [fileContent, setFileContent] = useState<string | null>(null)
|
|
133
136
|
const [fetchedFilePath, setFetchedFilePath] = useState<string | null>(null)
|
|
@@ -335,7 +338,7 @@ export function FileStructureSection({
|
|
|
335
338
|
<CollapseButton
|
|
336
339
|
collapsed={allCollapsed}
|
|
337
340
|
onToggle={() => setExpandedPaths(allCollapsed ? new Set(allDirPaths) : new Set())}
|
|
338
|
-
accentColor=
|
|
341
|
+
accentColor="neutral"
|
|
339
342
|
/>
|
|
340
343
|
</div>
|
|
341
344
|
<div className={`${variant === 'split' ? 'flex-1 overflow-y-auto' : ''} p-3`}>
|
|
@@ -18,10 +18,13 @@ export interface NavigationBarProps {
|
|
|
18
18
|
onForward?: () => void
|
|
19
19
|
showHistory?: boolean
|
|
20
20
|
historyEntries?: BreadcrumbSegment[][]
|
|
21
|
+
currentHistoryIndex?: number
|
|
21
22
|
onHistorySelect?: (index: number) => void
|
|
22
23
|
leadingAction?: { icon: IconName; onClick?: () => void }
|
|
23
24
|
separator?: 'chevron' | 'slash' | 'dot'
|
|
24
25
|
size?: 'xss' | 'xs' | 'sm' | 'md' | 'lg'
|
|
26
|
+
/** 'bar' (default): all-in-one bordered box. 'header': nav controls left-aligned, breadcrumb absolutely centered. */
|
|
27
|
+
layout?: 'bar' | 'header'
|
|
25
28
|
accentColor?: AccentColor
|
|
26
29
|
className?: string
|
|
27
30
|
}
|
|
@@ -113,10 +116,12 @@ export function NavigationBar({
|
|
|
113
116
|
onForward,
|
|
114
117
|
showHistory = false,
|
|
115
118
|
historyEntries,
|
|
119
|
+
currentHistoryIndex,
|
|
116
120
|
onHistorySelect,
|
|
117
121
|
leadingAction,
|
|
118
122
|
separator = 'chevron',
|
|
119
123
|
size = 'sm',
|
|
124
|
+
layout = 'bar',
|
|
120
125
|
accentColor,
|
|
121
126
|
className,
|
|
122
127
|
}: NavigationBarProps) {
|
|
@@ -135,6 +140,128 @@ export function NavigationBar({
|
|
|
135
140
|
|
|
136
141
|
const hasHistoryEntries = historyEntries && historyEntries.length > 0
|
|
137
142
|
|
|
143
|
+
const renderSegments = () => segments.map((segment, index) => {
|
|
144
|
+
const isLast = index === segments.length - 1
|
|
145
|
+
const isClickable = !isLast && !!segment.onClick
|
|
146
|
+
const colors = segment.color && ACCENT_NAV[segment.color as AccentColor] ? ACCENT_NAV[segment.color as AccentColor] : null
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div key={segment.id} className="flex items-center gap-1 min-w-0">
|
|
150
|
+
{index > 0 && <SegmentSeparator type={separator} size={size} />}
|
|
151
|
+
{isClickable ? (
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
onClick={segment.onClick}
|
|
155
|
+
className={cn(
|
|
156
|
+
'flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0',
|
|
157
|
+
s.text,
|
|
158
|
+
'font-medium hover:text-white',
|
|
159
|
+
colors ? [colors.text, `hover:${colors.bg}`] : ['text-neutral-300', 'hover:bg-neutral-700/50'],
|
|
160
|
+
)}
|
|
161
|
+
>
|
|
162
|
+
{segment.icon && <SegmentIcon icon={segment.icon} color={segment.color} size={size} />}
|
|
163
|
+
<span className="truncate max-w-[200px]">{segment.label}</span>
|
|
164
|
+
</button>
|
|
165
|
+
) : (
|
|
166
|
+
<div
|
|
167
|
+
className={cn(
|
|
168
|
+
'flex items-center gap-1.5 px-2 py-0.5 rounded-md min-w-0',
|
|
169
|
+
s.text,
|
|
170
|
+
isLast
|
|
171
|
+
? ['font-medium bg-neutral-700/50', colors ? colors.text : 'text-white']
|
|
172
|
+
: ['font-medium', colors ? colors.text : 'text-neutral-300'],
|
|
173
|
+
)}
|
|
174
|
+
>
|
|
175
|
+
{segment.icon && <SegmentIcon icon={segment.icon} color={segment.color} size={size} />}
|
|
176
|
+
<span className="truncate max-w-[200px]">{segment.label}</span>
|
|
177
|
+
</div>
|
|
178
|
+
)}
|
|
179
|
+
</div>
|
|
180
|
+
)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const renderHistoryDropdown = () => {
|
|
184
|
+
if (!historyOpen || !hasHistoryEntries || !historyEntries) return null
|
|
185
|
+
const entries = layout === 'header' ? [...historyEntries].reverse() : historyEntries
|
|
186
|
+
return (
|
|
187
|
+
<div className="absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-black/80 backdrop-blur-sm border border-neutral-700 rounded-lg shadow-lg z-50">
|
|
188
|
+
<div className="px-3 py-1.5 border-b border-neutral-700/50">
|
|
189
|
+
<p className="text-sm font-medium text-neutral-500">History{layout === 'header' && ` (${historyEntries.length})`}</p>
|
|
190
|
+
</div>
|
|
191
|
+
<div className="max-h-[300px] overflow-y-auto py-1">
|
|
192
|
+
{entries.map((entry, entryIdx) => {
|
|
193
|
+
const actualIdx = layout === 'header' ? historyEntries.length - 1 - entryIdx : entryIdx
|
|
194
|
+
const isCurrent = currentHistoryIndex !== undefined && actualIdx === currentHistoryIndex
|
|
195
|
+
return (
|
|
196
|
+
<button
|
|
197
|
+
key={actualIdx}
|
|
198
|
+
type="button"
|
|
199
|
+
onClick={() => {
|
|
200
|
+
onHistorySelect?.(actualIdx)
|
|
201
|
+
setHistoryOpen(false)
|
|
202
|
+
}}
|
|
203
|
+
className={cn(
|
|
204
|
+
'w-full px-3 py-1.5 flex items-center gap-1 text-left transition-colors cursor-pointer',
|
|
205
|
+
isCurrent ? 'bg-green-500/10' : 'hover:bg-neutral-800',
|
|
206
|
+
)}
|
|
207
|
+
>
|
|
208
|
+
{entry.map((seg, segIdx) => (
|
|
209
|
+
<span key={seg.id} className="flex items-center gap-1 min-w-0">
|
|
210
|
+
{segIdx > 0 && <ChevronRight className="w-2.5 h-2.5 text-neutral-600 flex-shrink-0" />}
|
|
211
|
+
{seg.icon && <SegmentIcon icon={seg.icon} color={seg.color} size="xs" />}
|
|
212
|
+
<span className={cn(
|
|
213
|
+
'text-sm truncate',
|
|
214
|
+
seg.color && ACCENT_NAV[seg.color as AccentColor] ? ACCENT_NAV[seg.color as AccentColor].text : 'text-neutral-300',
|
|
215
|
+
)}>
|
|
216
|
+
{seg.label}
|
|
217
|
+
</span>
|
|
218
|
+
</span>
|
|
219
|
+
))}
|
|
220
|
+
{isCurrent && <span className="ml-auto pl-4 text-xs text-green-400 flex-shrink-0">Current</span>}
|
|
221
|
+
</button>
|
|
222
|
+
)
|
|
223
|
+
})}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (layout === 'header') {
|
|
230
|
+
return (
|
|
231
|
+
<nav className={cn('relative flex items-center h-full', className)}>
|
|
232
|
+
{/* Left: nav controls */}
|
|
233
|
+
<div className="flex items-center gap-2 flex-shrink-0">
|
|
234
|
+
{hasNav && (
|
|
235
|
+
<>
|
|
236
|
+
<NavButton icon={ChevronLeft} onClick={onBack} disabled={!canGoBack} size={size} colorStyle={colorStyle} />
|
|
237
|
+
<NavButton icon={ChevronRight} onClick={onForward} disabled={!canGoForward} size={size} colorStyle={colorStyle} />
|
|
238
|
+
</>
|
|
239
|
+
)}
|
|
240
|
+
{showHistory && (
|
|
241
|
+
<div className="relative" ref={historyRef}>
|
|
242
|
+
<NavButton
|
|
243
|
+
icon={History}
|
|
244
|
+
onClick={() => setHistoryOpen(o => !o)}
|
|
245
|
+
disabled={!hasHistoryEntries}
|
|
246
|
+
size={size}
|
|
247
|
+
active={historyOpen}
|
|
248
|
+
colorStyle={colorStyle}
|
|
249
|
+
/>
|
|
250
|
+
{renderHistoryDropdown()}
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
{/* Center: breadcrumb absolutely centered */}
|
|
256
|
+
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
|
257
|
+
<div className={cn('pointer-events-auto flex items-center gap-1', s.px, s.py, 'bg-neutral-960/50 rounded-lg')}>
|
|
258
|
+
{renderSegments()}
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
</nav>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
138
265
|
return (
|
|
139
266
|
<nav className={cn('flex items-center', className)}>
|
|
140
267
|
<div className={cn('flex items-center gap-1', s.px, s.py, 'bg-neutral-960/50 border rounded-lg', colorStyle.border)}>
|
|
@@ -166,86 +293,13 @@ export function NavigationBar({
|
|
|
166
293
|
active={historyOpen}
|
|
167
294
|
colorStyle={colorStyle}
|
|
168
295
|
/>
|
|
169
|
-
{
|
|
170
|
-
<div className="absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-neutral-960 border border-neutral-700 rounded-lg shadow-lg z-50">
|
|
171
|
-
<div className="px-3 py-1.5 border-b border-neutral-700/50">
|
|
172
|
-
<p className="text-sm font-medium text-neutral-500">History</p>
|
|
173
|
-
</div>
|
|
174
|
-
<div className="max-h-[300px] overflow-y-auto py-1">
|
|
175
|
-
{historyEntries.map((entry, i) => (
|
|
176
|
-
<button
|
|
177
|
-
key={i}
|
|
178
|
-
type="button"
|
|
179
|
-
onClick={() => {
|
|
180
|
-
onHistorySelect?.(i)
|
|
181
|
-
setHistoryOpen(false)
|
|
182
|
-
}}
|
|
183
|
-
className="w-full px-3 py-1.5 flex items-center gap-1 text-left hover:bg-neutral-960 transition-colors cursor-pointer"
|
|
184
|
-
>
|
|
185
|
-
{entry.map((seg, segIdx) => (
|
|
186
|
-
<span key={seg.id} className="flex items-center gap-1 min-w-0">
|
|
187
|
-
{segIdx > 0 && <ChevronRight className="w-2.5 h-2.5 text-neutral-600 flex-shrink-0" />}
|
|
188
|
-
{seg.icon && <SegmentIcon icon={seg.icon} color={seg.color} size="xs" />}
|
|
189
|
-
<span className={cn(
|
|
190
|
-
'text-sm truncate',
|
|
191
|
-
seg.color && ACCENT_NAV[seg.color as AccentColor] ? ACCENT_NAV[seg.color as AccentColor].text : 'text-neutral-300',
|
|
192
|
-
)}>
|
|
193
|
-
{seg.label}
|
|
194
|
-
</span>
|
|
195
|
-
</span>
|
|
196
|
-
))}
|
|
197
|
-
</button>
|
|
198
|
-
))}
|
|
199
|
-
</div>
|
|
200
|
-
<div className="px-3 py-1.5 border-t border-neutral-700/50">
|
|
201
|
-
<p className="text-sm text-neutral-600">Click to navigate</p>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
)}
|
|
296
|
+
{renderHistoryDropdown()}
|
|
205
297
|
</div>
|
|
206
298
|
<Divider size={size} />
|
|
207
299
|
</>
|
|
208
300
|
)}
|
|
209
301
|
|
|
210
|
-
{
|
|
211
|
-
const isLast = index === segments.length - 1
|
|
212
|
-
const isClickable = !isLast && !!segment.onClick
|
|
213
|
-
const colors = segment.color && ACCENT_NAV[segment.color as AccentColor] ? ACCENT_NAV[segment.color as AccentColor] : null
|
|
214
|
-
|
|
215
|
-
return (
|
|
216
|
-
<div key={segment.id} className="flex items-center gap-1 min-w-0">
|
|
217
|
-
{index > 0 && <SegmentSeparator type={separator} size={size} />}
|
|
218
|
-
{isClickable ? (
|
|
219
|
-
<button
|
|
220
|
-
type="button"
|
|
221
|
-
onClick={segment.onClick}
|
|
222
|
-
className={cn(
|
|
223
|
-
'flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0',
|
|
224
|
-
s.text,
|
|
225
|
-
'font-medium hover:text-white',
|
|
226
|
-
colors ? [colors.text, `hover:${colors.bg}`] : ['text-neutral-300', 'hover:bg-neutral-700/50'],
|
|
227
|
-
)}
|
|
228
|
-
>
|
|
229
|
-
{segment.icon && <SegmentIcon icon={segment.icon} color={segment.color} size={size} />}
|
|
230
|
-
<span className="truncate max-w-[200px]">{segment.label}</span>
|
|
231
|
-
</button>
|
|
232
|
-
) : (
|
|
233
|
-
<div
|
|
234
|
-
className={cn(
|
|
235
|
-
'flex items-center gap-1.5 px-2 py-0.5 rounded-md min-w-0',
|
|
236
|
-
s.text,
|
|
237
|
-
isLast
|
|
238
|
-
? ['font-medium bg-neutral-700/50', colors ? colors.text : 'text-white']
|
|
239
|
-
: ['font-medium', colors ? colors.text : 'text-neutral-300'],
|
|
240
|
-
)}
|
|
241
|
-
>
|
|
242
|
-
{segment.icon && <SegmentIcon icon={segment.icon} color={segment.color} size={size} />}
|
|
243
|
-
<span className="truncate max-w-[200px]">{segment.label}</span>
|
|
244
|
-
</div>
|
|
245
|
-
)}
|
|
246
|
-
</div>
|
|
247
|
-
)
|
|
248
|
-
})}
|
|
302
|
+
{renderSegments()}
|
|
249
303
|
</div>
|
|
250
304
|
</nav>
|
|
251
305
|
)
|
|
@@ -3,6 +3,7 @@ import { ChevronsUpDown, ChevronsDownUp } from 'lucide-react'
|
|
|
3
3
|
import { IconButton } from './icon-button.tsx'
|
|
4
4
|
import { Label, type LabelProps } from './label.tsx'
|
|
5
5
|
import { CodingAgentIcon, CODING_AGENT_NAMES, type CodingAgentKey } from '../lib/coding-agents.tsx'
|
|
6
|
+
import { Tooltip } from './tooltip.tsx'
|
|
6
7
|
import { FileStructureSection, type FileStructureSectionProps } from './file-structure-section.tsx'
|
|
7
8
|
import { type AccentColor } from '../lib/form-colors.ts'
|
|
8
9
|
import { AccentColorProvider, useAccentColor } from '../lib/accent-context.ts'
|
|
@@ -24,7 +25,7 @@ export interface RegistryDetailProps {
|
|
|
24
25
|
|
|
25
26
|
// Standard sections (rendered in order before children)
|
|
26
27
|
description?: string
|
|
27
|
-
longDescription?:
|
|
28
|
+
longDescription?: ReactNode
|
|
28
29
|
integration?: boolean
|
|
29
30
|
compatibleTools?: string[]
|
|
30
31
|
|
|
@@ -56,7 +57,7 @@ const MARKDOWN_CLASSES = 'text-md text-neutral-400 leading-relaxed [&_strong]:te
|
|
|
56
57
|
|
|
57
58
|
const COLLAPSED_MAX_HEIGHT = 240
|
|
58
59
|
|
|
59
|
-
function CollapsibleTextSection({ children, header }: { children:
|
|
60
|
+
function CollapsibleTextSection({ children, header }: { children: ReactNode; header?: string }) {
|
|
60
61
|
const contentRef = useRef<HTMLDivElement>(null)
|
|
61
62
|
const [overflows, setOverflows] = useState(false)
|
|
62
63
|
const [expanded, setExpanded] = useState(false)
|
|
@@ -107,7 +108,7 @@ function CollapsibleTextSection({ children, header }: { children: string; header
|
|
|
107
108
|
className={MARKDOWN_CLASSES}
|
|
108
109
|
style={showCollapsed ? { maxHeight: COLLAPSED_MAX_HEIGHT, overflow: 'hidden' } : undefined}
|
|
109
110
|
>
|
|
110
|
-
<
|
|
111
|
+
<div>{children}</div>
|
|
111
112
|
</div>
|
|
112
113
|
|
|
113
114
|
{showCollapsed && (
|
|
@@ -128,10 +129,9 @@ function CompatibleWithSection({ agents }: { agents: string[] }) {
|
|
|
128
129
|
<h3 className="text-sm font-medium text-neutral-500 uppercase tracking-wider mb-3">Compatible with</h3>
|
|
129
130
|
<div className="flex items-start gap-3">
|
|
130
131
|
{agents.map((agent) => (
|
|
131
|
-
<
|
|
132
|
-
<CodingAgentIcon agent={agent} size={
|
|
133
|
-
|
|
134
|
-
</div>
|
|
132
|
+
<Tooltip key={agent} content={{ description: CODING_AGENT_NAMES[agent as CodingAgentKey] ?? agent }} position="top">
|
|
133
|
+
<CodingAgentIcon agent={agent} size={24} />
|
|
134
|
+
</Tooltip>
|
|
135
135
|
))}
|
|
136
136
|
</div>
|
|
137
137
|
</div>
|
|
@@ -166,8 +166,8 @@ export function RegistryDetail({
|
|
|
166
166
|
const resolvedAccent = accentColor ?? contextAccent
|
|
167
167
|
|
|
168
168
|
const content = (
|
|
169
|
-
<div className="h-full overflow-y-auto
|
|
170
|
-
<div className={`${maxWidth} mx-auto space-y-
|
|
169
|
+
<div className="h-full overflow-y-auto">
|
|
170
|
+
<div className={`${maxWidth} mx-auto px-4 py-6 space-y-8`}>
|
|
171
171
|
{/* Above header badges */}
|
|
172
172
|
{aboveHeader}
|
|
173
173
|
{/* Header row */}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ declare const ACCENT_ICON: Record<FormColor, string>;
|
|
|
24
24
|
declare const ACCENT_NAV: Record<AccentColor, {
|
|
25
25
|
bg: string;
|
|
26
26
|
text: string;
|
|
27
|
+
border: string;
|
|
27
28
|
}>;
|
|
28
29
|
declare const FORM_COLORS: Record<FormColor, FormColorConfig>;
|
|
29
30
|
|
|
@@ -1030,7 +1031,7 @@ interface FileStructureSectionProps {
|
|
|
1030
1031
|
initialHeight?: number;
|
|
1031
1032
|
}
|
|
1032
1033
|
declare function getLanguageFromPath(filePath: string): string;
|
|
1033
|
-
declare function FileStructureSection({ files, rootName, variant, isLoading, error, onFetchContent, format, language, default: defaultMode, accentColor, renderPreview, initialHeight, }: FileStructureSectionProps): react_jsx_runtime.JSX.Element | null;
|
|
1034
|
+
declare function FileStructureSection({ files, rootName, variant, isLoading, error, onFetchContent, format, language, default: defaultMode, accentColor: accentColorProp, renderPreview, initialHeight, }: FileStructureSectionProps): react_jsx_runtime.JSX.Element | null;
|
|
1034
1035
|
|
|
1035
1036
|
interface RegistryDetailProps {
|
|
1036
1037
|
icon: LucideIcon;
|
|
@@ -1041,7 +1042,7 @@ interface RegistryDetailProps {
|
|
|
1041
1042
|
actionButton?: ReactNode;
|
|
1042
1043
|
labels?: LabelProps[];
|
|
1043
1044
|
description?: string;
|
|
1044
|
-
longDescription?:
|
|
1045
|
+
longDescription?: ReactNode;
|
|
1045
1046
|
integration?: boolean;
|
|
1046
1047
|
compatibleTools?: string[];
|
|
1047
1048
|
files?: FileStructureSectionProps['files'];
|
|
@@ -2540,6 +2541,7 @@ interface NavigationBarProps {
|
|
|
2540
2541
|
onForward?: () => void;
|
|
2541
2542
|
showHistory?: boolean;
|
|
2542
2543
|
historyEntries?: BreadcrumbSegment[][];
|
|
2544
|
+
currentHistoryIndex?: number;
|
|
2543
2545
|
onHistorySelect?: (index: number) => void;
|
|
2544
2546
|
leadingAction?: {
|
|
2545
2547
|
icon: IconName;
|
|
@@ -2547,10 +2549,12 @@ interface NavigationBarProps {
|
|
|
2547
2549
|
};
|
|
2548
2550
|
separator?: 'chevron' | 'slash' | 'dot';
|
|
2549
2551
|
size?: 'xss' | 'xs' | 'sm' | 'md' | 'lg';
|
|
2552
|
+
/** 'bar' (default): all-in-one bordered box. 'header': nav controls left-aligned, breadcrumb absolutely centered. */
|
|
2553
|
+
layout?: 'bar' | 'header';
|
|
2550
2554
|
accentColor?: AccentColor;
|
|
2551
2555
|
className?: string;
|
|
2552
2556
|
}
|
|
2553
|
-
declare function NavigationBar({ segments, canGoBack, canGoForward, onBack, onForward, showHistory, historyEntries, onHistorySelect, leadingAction, separator, size, accentColor, className, }: NavigationBarProps): react_jsx_runtime.JSX.Element;
|
|
2557
|
+
declare function NavigationBar({ segments, canGoBack, canGoForward, onBack, onForward, showHistory, historyEntries, currentHistoryIndex, onHistorySelect, leadingAction, separator, size, layout, accentColor, className, }: NavigationBarProps): react_jsx_runtime.JSX.Element;
|
|
2554
2558
|
|
|
2555
2559
|
interface Tab {
|
|
2556
2560
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -18,21 +18,21 @@ var ACCENT_TEXT = {
|
|
|
18
18
|
};
|
|
19
19
|
var ACCENT_ICON = ACCENT_TEXT;
|
|
20
20
|
var ACCENT_NAV = {
|
|
21
|
-
blue: { bg: "bg-blue-500/10", text: "text-blue-400" },
|
|
22
|
-
green: { bg: "bg-green-500/10", text: "text-green-400" },
|
|
23
|
-
red: { bg: "bg-red-500/10", text: "text-red-400" },
|
|
24
|
-
orange: { bg: "bg-orange-500/10", text: "text-orange-400" },
|
|
25
|
-
cyan: { bg: "bg-cyan-500/10", text: "text-cyan-400" },
|
|
26
|
-
yellow: { bg: "bg-yellow-500/10", text: "text-yellow-400" },
|
|
27
|
-
purple: { bg: "bg-purple-500/10", text: "text-purple-400" },
|
|
28
|
-
indigo: { bg: "bg-indigo-500/10", text: "text-indigo-400" },
|
|
29
|
-
emerald: { bg: "bg-emerald-500/10", text: "text-emerald-400" },
|
|
30
|
-
amber: { bg: "bg-amber-500/10", text: "text-amber-400" },
|
|
31
|
-
violet: { bg: "bg-violet-500/10", text: "text-violet-400" },
|
|
32
|
-
neutral: { bg: "bg-neutral-500/10", text: "text-neutral-400" },
|
|
33
|
-
sky: { bg: "bg-sky-500/10", text: "text-sky-400" },
|
|
34
|
-
pink: { bg: "bg-pink-500/10", text: "text-pink-400" },
|
|
35
|
-
teal: { bg: "bg-teal-500/10", text: "text-teal-400" }
|
|
21
|
+
blue: { bg: "bg-blue-500/10", text: "text-blue-400", border: "border-blue-500/30" },
|
|
22
|
+
green: { bg: "bg-green-500/10", text: "text-green-400", border: "border-green-500/30" },
|
|
23
|
+
red: { bg: "bg-red-500/10", text: "text-red-400", border: "border-red-500/30" },
|
|
24
|
+
orange: { bg: "bg-orange-500/10", text: "text-orange-400", border: "border-orange-500/30" },
|
|
25
|
+
cyan: { bg: "bg-cyan-500/10", text: "text-cyan-400", border: "border-cyan-500/30" },
|
|
26
|
+
yellow: { bg: "bg-yellow-500/10", text: "text-yellow-400", border: "border-yellow-500/30" },
|
|
27
|
+
purple: { bg: "bg-purple-500/10", text: "text-purple-400", border: "border-purple-500/30" },
|
|
28
|
+
indigo: { bg: "bg-indigo-500/10", text: "text-indigo-400", border: "border-indigo-500/30" },
|
|
29
|
+
emerald: { bg: "bg-emerald-500/10", text: "text-emerald-400", border: "border-emerald-500/30" },
|
|
30
|
+
amber: { bg: "bg-amber-500/10", text: "text-amber-400", border: "border-amber-500/30" },
|
|
31
|
+
violet: { bg: "bg-violet-500/10", text: "text-violet-400", border: "border-violet-500/30" },
|
|
32
|
+
neutral: { bg: "bg-neutral-500/10", text: "text-neutral-400", border: "border-neutral-500/30" },
|
|
33
|
+
sky: { bg: "bg-sky-500/10", text: "text-sky-400", border: "border-sky-500/30" },
|
|
34
|
+
pink: { bg: "bg-pink-500/10", text: "text-pink-400", border: "border-pink-500/30" },
|
|
35
|
+
teal: { bg: "bg-teal-500/10", text: "text-teal-400", border: "border-teal-500/30" }
|
|
36
36
|
};
|
|
37
37
|
var FORM_COLORS = {
|
|
38
38
|
blue: { border: "border-blue-500/30", hover: "hover:bg-blue-500/20 hover:border-blue-500/40", focus: "focus:border-blue-500", selectedBg: "bg-blue-600/20", accent: "text-blue-400" },
|
|
@@ -193,8 +193,8 @@ var TOOLR_APPS = {
|
|
|
193
193
|
// #f97316
|
|
194
194
|
learnr: { name: "Learnr", accent: "yellow" },
|
|
195
195
|
// #eab308
|
|
196
|
-
seedr: { name: "Seedr", accent: "
|
|
197
|
-
// #
|
|
196
|
+
seedr: { name: "Seedr", accent: "green" },
|
|
197
|
+
// #22c55e
|
|
198
198
|
planr: { name: "Planr", accent: "pink" },
|
|
199
199
|
// #ec4899 (not in ACCENT_DEFS, fallback hex)
|
|
200
200
|
vibr: { name: "Vibr", accent: "red" }
|
|
@@ -4377,10 +4377,12 @@ function FileStructureSection({
|
|
|
4377
4377
|
format,
|
|
4378
4378
|
language,
|
|
4379
4379
|
default: defaultMode,
|
|
4380
|
-
accentColor
|
|
4380
|
+
accentColor: accentColorProp,
|
|
4381
4381
|
renderPreview,
|
|
4382
4382
|
initialHeight
|
|
4383
4383
|
}) {
|
|
4384
|
+
const contextAccent = useAccentColor();
|
|
4385
|
+
const accentColor = accentColorProp ?? contextAccent ?? "blue";
|
|
4384
4386
|
const [selectedFilePath, setSelectedFilePath] = useState14(null);
|
|
4385
4387
|
const [fileContent, setFileContent] = useState14(null);
|
|
4386
4388
|
const [fetchedFilePath, setFetchedFilePath] = useState14(null);
|
|
@@ -4550,7 +4552,7 @@ function FileStructureSection({
|
|
|
4550
4552
|
{
|
|
4551
4553
|
collapsed: allCollapsed,
|
|
4552
4554
|
onToggle: () => setExpandedPaths(allCollapsed ? new Set(allDirPaths) : /* @__PURE__ */ new Set()),
|
|
4553
|
-
accentColor
|
|
4555
|
+
accentColor: "neutral"
|
|
4554
4556
|
}
|
|
4555
4557
|
)
|
|
4556
4558
|
] }),
|
|
@@ -4661,7 +4663,7 @@ function CollapsibleTextSection({ children, header }) {
|
|
|
4661
4663
|
ref: contentRef,
|
|
4662
4664
|
className: MARKDOWN_CLASSES,
|
|
4663
4665
|
style: showCollapsed ? { maxHeight: COLLAPSED_MAX_HEIGHT, overflow: "hidden" } : void 0,
|
|
4664
|
-
children: /* @__PURE__ */ jsx34("
|
|
4666
|
+
children: /* @__PURE__ */ jsx34("div", { children })
|
|
4665
4667
|
}
|
|
4666
4668
|
),
|
|
4667
4669
|
showCollapsed && /* @__PURE__ */ jsx34("div", { className: "absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-neutral-960 to-transparent pointer-events-none" })
|
|
@@ -4672,10 +4674,7 @@ function CompatibleWithSection({ agents }) {
|
|
|
4672
4674
|
if (agents.length === 0) return null;
|
|
4673
4675
|
return /* @__PURE__ */ jsxs26("div", { children: [
|
|
4674
4676
|
/* @__PURE__ */ jsx34("h3", { className: "text-sm font-medium text-neutral-500 uppercase tracking-wider mb-3", children: "Compatible with" }),
|
|
4675
|
-
/* @__PURE__ */ jsx34("div", { className: "flex items-start gap-3", children: agents.map((agent) => /* @__PURE__ */
|
|
4676
|
-
/* @__PURE__ */ jsx34(CodingAgentIcon, { agent, size: 18 }),
|
|
4677
|
-
/* @__PURE__ */ jsx34("span", { className: "text-xs text-neutral-400", children: CODING_AGENT_NAMES[agent] ?? agent })
|
|
4678
|
-
] }, agent)) })
|
|
4677
|
+
/* @__PURE__ */ jsx34("div", { className: "flex items-start gap-3", children: agents.map((agent) => /* @__PURE__ */ jsx34(Tooltip, { content: { description: CODING_AGENT_NAMES[agent] ?? agent }, position: "top", children: /* @__PURE__ */ jsx34(CodingAgentIcon, { agent, size: 24 }) }, agent)) })
|
|
4679
4678
|
] });
|
|
4680
4679
|
}
|
|
4681
4680
|
function RegistryDetail({
|
|
@@ -4702,7 +4701,7 @@ function RegistryDetail({
|
|
|
4702
4701
|
}) {
|
|
4703
4702
|
const contextAccent = useAccentColor();
|
|
4704
4703
|
const resolvedAccent = accentColor ?? contextAccent;
|
|
4705
|
-
const content = /* @__PURE__ */ jsx34("div", { className: "h-full overflow-y-auto
|
|
4704
|
+
const content = /* @__PURE__ */ jsx34("div", { className: "h-full overflow-y-auto", children: /* @__PURE__ */ jsxs26("div", { className: `${maxWidth} mx-auto px-4 py-6 space-y-8`, children: [
|
|
4706
4705
|
aboveHeader,
|
|
4707
4706
|
/* @__PURE__ */ jsxs26("div", { className: "flex items-start justify-between gap-4", children: [
|
|
4708
4707
|
/* @__PURE__ */ jsxs26("div", { className: "min-w-0", children: [
|
|
@@ -9886,12 +9885,12 @@ function Breadcrumb({
|
|
|
9886
9885
|
const isBox = variant === "box";
|
|
9887
9886
|
return /* @__PURE__ */ jsx56(AccentColorProvider, { value: effectiveColor, children: /* @__PURE__ */ jsx56("nav", { className: cn("flex items-center min-w-0", className), children: /* @__PURE__ */ jsx56("div", { className: cn(
|
|
9888
9887
|
"flex items-center gap-1",
|
|
9889
|
-
isBox && [s.px, s.py, "bg-neutral-960/50
|
|
9888
|
+
isBox && [s.px, s.py, "bg-neutral-960/50 rounded-lg"]
|
|
9890
9889
|
), children: segments.map((segment, index) => {
|
|
9891
9890
|
const isLast = index === segments.length - 1;
|
|
9892
9891
|
const isClickable = !isLast && !!segment.onClick;
|
|
9893
9892
|
const colors = segment.color && ACCENT_NAV[segment.color] ? ACCENT_NAV[segment.color] : null;
|
|
9894
|
-
const
|
|
9893
|
+
const isFirst = !isBox && index === 0;
|
|
9895
9894
|
return /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-1 min-w-0", children: [
|
|
9896
9895
|
index > 0 && /* @__PURE__ */ jsx56(Separator, { type: separator, size }),
|
|
9897
9896
|
isClickable ? /* @__PURE__ */ jsxs47(
|
|
@@ -9901,7 +9900,7 @@ function Breadcrumb({
|
|
|
9901
9900
|
onClick: segment.onClick,
|
|
9902
9901
|
className: cn(
|
|
9903
9902
|
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0",
|
|
9904
|
-
|
|
9903
|
+
isFirst ? "pl-0" : "pl-2",
|
|
9905
9904
|
s.text,
|
|
9906
9905
|
"font-medium hover:text-white",
|
|
9907
9906
|
colors ? [colors.text, `hover:${colors.bg}`] : ["text-neutral-300", "hover:bg-neutral-700/50"]
|
|
@@ -9916,9 +9915,9 @@ function Breadcrumb({
|
|
|
9916
9915
|
{
|
|
9917
9916
|
className: cn(
|
|
9918
9917
|
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md min-w-0",
|
|
9919
|
-
|
|
9918
|
+
isFirst ? "pl-0" : "pl-2",
|
|
9920
9919
|
s.text,
|
|
9921
|
-
isLast ?
|
|
9920
|
+
isLast ? "font-medium text-white" : ["font-medium", colors ? colors.text : "text-neutral-300"]
|
|
9922
9921
|
),
|
|
9923
9922
|
children: [
|
|
9924
9923
|
segment.icon && /* @__PURE__ */ jsx56(SegmentIcon, { icon: segment.icon, color: segment.color, size }),
|
|
@@ -9998,10 +9997,12 @@ function NavigationBar({
|
|
|
9998
9997
|
onForward,
|
|
9999
9998
|
showHistory = false,
|
|
10000
9999
|
historyEntries,
|
|
10000
|
+
currentHistoryIndex,
|
|
10001
10001
|
onHistorySelect,
|
|
10002
10002
|
leadingAction,
|
|
10003
10003
|
separator = "chevron",
|
|
10004
10004
|
size = "sm",
|
|
10005
|
+
layout = "bar",
|
|
10005
10006
|
accentColor,
|
|
10006
10007
|
className
|
|
10007
10008
|
}) {
|
|
@@ -10016,6 +10017,109 @@ function NavigationBar({
|
|
|
10016
10017
|
const closeHistory = useCallback20(() => setHistoryOpen(false), []);
|
|
10017
10018
|
useClickOutside(historyRef, historyOpen, closeHistory);
|
|
10018
10019
|
const hasHistoryEntries = historyEntries && historyEntries.length > 0;
|
|
10020
|
+
const renderSegments = () => segments.map((segment, index) => {
|
|
10021
|
+
const isLast = index === segments.length - 1;
|
|
10022
|
+
const isClickable = !isLast && !!segment.onClick;
|
|
10023
|
+
const colors = segment.color && ACCENT_NAV[segment.color] ? ACCENT_NAV[segment.color] : null;
|
|
10024
|
+
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-1 min-w-0", children: [
|
|
10025
|
+
index > 0 && /* @__PURE__ */ jsx57(SegmentSeparator, { type: separator, size }),
|
|
10026
|
+
isClickable ? /* @__PURE__ */ jsxs48(
|
|
10027
|
+
"button",
|
|
10028
|
+
{
|
|
10029
|
+
type: "button",
|
|
10030
|
+
onClick: segment.onClick,
|
|
10031
|
+
className: cn(
|
|
10032
|
+
"flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0",
|
|
10033
|
+
s.text,
|
|
10034
|
+
"font-medium hover:text-white",
|
|
10035
|
+
colors ? [colors.text, `hover:${colors.bg}`] : ["text-neutral-300", "hover:bg-neutral-700/50"]
|
|
10036
|
+
),
|
|
10037
|
+
children: [
|
|
10038
|
+
segment.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: segment.icon, color: segment.color, size }),
|
|
10039
|
+
/* @__PURE__ */ jsx57("span", { className: "truncate max-w-[200px]", children: segment.label })
|
|
10040
|
+
]
|
|
10041
|
+
}
|
|
10042
|
+
) : /* @__PURE__ */ jsxs48(
|
|
10043
|
+
"div",
|
|
10044
|
+
{
|
|
10045
|
+
className: cn(
|
|
10046
|
+
"flex items-center gap-1.5 px-2 py-0.5 rounded-md min-w-0",
|
|
10047
|
+
s.text,
|
|
10048
|
+
isLast ? ["font-medium bg-neutral-700/50", colors ? colors.text : "text-white"] : ["font-medium", colors ? colors.text : "text-neutral-300"]
|
|
10049
|
+
),
|
|
10050
|
+
children: [
|
|
10051
|
+
segment.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: segment.icon, color: segment.color, size }),
|
|
10052
|
+
/* @__PURE__ */ jsx57("span", { className: "truncate max-w-[200px]", children: segment.label })
|
|
10053
|
+
]
|
|
10054
|
+
}
|
|
10055
|
+
)
|
|
10056
|
+
] }, segment.id);
|
|
10057
|
+
});
|
|
10058
|
+
const renderHistoryDropdown = () => {
|
|
10059
|
+
if (!historyOpen || !hasHistoryEntries || !historyEntries) return null;
|
|
10060
|
+
const entries = layout === "header" ? [...historyEntries].reverse() : historyEntries;
|
|
10061
|
+
return /* @__PURE__ */ jsxs48("div", { className: "absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-black/80 backdrop-blur-sm border border-neutral-700 rounded-lg shadow-lg z-50", children: [
|
|
10062
|
+
/* @__PURE__ */ jsx57("div", { className: "px-3 py-1.5 border-b border-neutral-700/50", children: /* @__PURE__ */ jsxs48("p", { className: "text-sm font-medium text-neutral-500", children: [
|
|
10063
|
+
"History",
|
|
10064
|
+
layout === "header" && ` (${historyEntries.length})`
|
|
10065
|
+
] }) }),
|
|
10066
|
+
/* @__PURE__ */ jsx57("div", { className: "max-h-[300px] overflow-y-auto py-1", children: entries.map((entry, entryIdx) => {
|
|
10067
|
+
const actualIdx = layout === "header" ? historyEntries.length - 1 - entryIdx : entryIdx;
|
|
10068
|
+
const isCurrent = currentHistoryIndex !== void 0 && actualIdx === currentHistoryIndex;
|
|
10069
|
+
return /* @__PURE__ */ jsxs48(
|
|
10070
|
+
"button",
|
|
10071
|
+
{
|
|
10072
|
+
type: "button",
|
|
10073
|
+
onClick: () => {
|
|
10074
|
+
onHistorySelect?.(actualIdx);
|
|
10075
|
+
setHistoryOpen(false);
|
|
10076
|
+
},
|
|
10077
|
+
className: cn(
|
|
10078
|
+
"w-full px-3 py-1.5 flex items-center gap-1 text-left transition-colors cursor-pointer",
|
|
10079
|
+
isCurrent ? "bg-green-500/10" : "hover:bg-neutral-800"
|
|
10080
|
+
),
|
|
10081
|
+
children: [
|
|
10082
|
+
entry.map((seg, segIdx) => /* @__PURE__ */ jsxs48("span", { className: "flex items-center gap-1 min-w-0", children: [
|
|
10083
|
+
segIdx > 0 && /* @__PURE__ */ jsx57(ChevronRight10, { className: "w-2.5 h-2.5 text-neutral-600 flex-shrink-0" }),
|
|
10084
|
+
seg.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: seg.icon, color: seg.color, size: "xs" }),
|
|
10085
|
+
/* @__PURE__ */ jsx57("span", { className: cn(
|
|
10086
|
+
"text-sm truncate",
|
|
10087
|
+
seg.color && ACCENT_NAV[seg.color] ? ACCENT_NAV[seg.color].text : "text-neutral-300"
|
|
10088
|
+
), children: seg.label })
|
|
10089
|
+
] }, seg.id)),
|
|
10090
|
+
isCurrent && /* @__PURE__ */ jsx57("span", { className: "ml-auto pl-4 text-xs text-green-400 flex-shrink-0", children: "Current" })
|
|
10091
|
+
]
|
|
10092
|
+
},
|
|
10093
|
+
actualIdx
|
|
10094
|
+
);
|
|
10095
|
+
}) })
|
|
10096
|
+
] });
|
|
10097
|
+
};
|
|
10098
|
+
if (layout === "header") {
|
|
10099
|
+
return /* @__PURE__ */ jsxs48("nav", { className: cn("relative flex items-center h-full", className), children: [
|
|
10100
|
+
/* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
10101
|
+
hasNav && /* @__PURE__ */ jsxs48(Fragment12, { children: [
|
|
10102
|
+
/* @__PURE__ */ jsx57(NavButton, { icon: ChevronLeft2, onClick: onBack, disabled: !canGoBack, size, colorStyle }),
|
|
10103
|
+
/* @__PURE__ */ jsx57(NavButton, { icon: ChevronRight10, onClick: onForward, disabled: !canGoForward, size, colorStyle })
|
|
10104
|
+
] }),
|
|
10105
|
+
showHistory && /* @__PURE__ */ jsxs48("div", { className: "relative", ref: historyRef, children: [
|
|
10106
|
+
/* @__PURE__ */ jsx57(
|
|
10107
|
+
NavButton,
|
|
10108
|
+
{
|
|
10109
|
+
icon: History3,
|
|
10110
|
+
onClick: () => setHistoryOpen((o) => !o),
|
|
10111
|
+
disabled: !hasHistoryEntries,
|
|
10112
|
+
size,
|
|
10113
|
+
active: historyOpen,
|
|
10114
|
+
colorStyle
|
|
10115
|
+
}
|
|
10116
|
+
),
|
|
10117
|
+
renderHistoryDropdown()
|
|
10118
|
+
] })
|
|
10119
|
+
] }),
|
|
10120
|
+
/* @__PURE__ */ jsx57("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsx57("div", { className: cn("pointer-events-auto flex items-center gap-1", s.px, s.py, "bg-neutral-960/50 rounded-lg"), children: renderSegments() }) })
|
|
10121
|
+
] });
|
|
10122
|
+
}
|
|
10019
10123
|
return /* @__PURE__ */ jsx57("nav", { className: cn("flex items-center", className), children: /* @__PURE__ */ jsxs48("div", { className: cn("flex items-center gap-1", s.px, s.py, "bg-neutral-960/50 border rounded-lg", colorStyle.border), children: [
|
|
10020
10124
|
leadingAction && LeadIcon && /* @__PURE__ */ jsxs48(Fragment12, { children: [
|
|
10021
10125
|
/* @__PURE__ */ jsx57(NavButton, { icon: LeadIcon, onClick: leadingAction.onClick, size, colorStyle }),
|
|
@@ -10041,71 +10145,11 @@ function NavigationBar({
|
|
|
10041
10145
|
colorStyle
|
|
10042
10146
|
}
|
|
10043
10147
|
),
|
|
10044
|
-
|
|
10045
|
-
/* @__PURE__ */ jsx57("div", { className: "px-3 py-1.5 border-b border-neutral-700/50", children: /* @__PURE__ */ jsx57("p", { className: "text-sm font-medium text-neutral-500", children: "History" }) }),
|
|
10046
|
-
/* @__PURE__ */ jsx57("div", { className: "max-h-[300px] overflow-y-auto py-1", children: historyEntries.map((entry, i) => /* @__PURE__ */ jsx57(
|
|
10047
|
-
"button",
|
|
10048
|
-
{
|
|
10049
|
-
type: "button",
|
|
10050
|
-
onClick: () => {
|
|
10051
|
-
onHistorySelect?.(i);
|
|
10052
|
-
setHistoryOpen(false);
|
|
10053
|
-
},
|
|
10054
|
-
className: "w-full px-3 py-1.5 flex items-center gap-1 text-left hover:bg-neutral-960 transition-colors cursor-pointer",
|
|
10055
|
-
children: entry.map((seg, segIdx) => /* @__PURE__ */ jsxs48("span", { className: "flex items-center gap-1 min-w-0", children: [
|
|
10056
|
-
segIdx > 0 && /* @__PURE__ */ jsx57(ChevronRight10, { className: "w-2.5 h-2.5 text-neutral-600 flex-shrink-0" }),
|
|
10057
|
-
seg.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: seg.icon, color: seg.color, size: "xs" }),
|
|
10058
|
-
/* @__PURE__ */ jsx57("span", { className: cn(
|
|
10059
|
-
"text-sm truncate",
|
|
10060
|
-
seg.color && ACCENT_NAV[seg.color] ? ACCENT_NAV[seg.color].text : "text-neutral-300"
|
|
10061
|
-
), children: seg.label })
|
|
10062
|
-
] }, seg.id))
|
|
10063
|
-
},
|
|
10064
|
-
i
|
|
10065
|
-
)) }),
|
|
10066
|
-
/* @__PURE__ */ jsx57("div", { className: "px-3 py-1.5 border-t border-neutral-700/50", children: /* @__PURE__ */ jsx57("p", { className: "text-sm text-neutral-600", children: "Click to navigate" }) })
|
|
10067
|
-
] })
|
|
10148
|
+
renderHistoryDropdown()
|
|
10068
10149
|
] }),
|
|
10069
10150
|
/* @__PURE__ */ jsx57(Divider, { size })
|
|
10070
10151
|
] }),
|
|
10071
|
-
|
|
10072
|
-
const isLast = index === segments.length - 1;
|
|
10073
|
-
const isClickable = !isLast && !!segment.onClick;
|
|
10074
|
-
const colors = segment.color && ACCENT_NAV[segment.color] ? ACCENT_NAV[segment.color] : null;
|
|
10075
|
-
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-1 min-w-0", children: [
|
|
10076
|
-
index > 0 && /* @__PURE__ */ jsx57(SegmentSeparator, { type: separator, size }),
|
|
10077
|
-
isClickable ? /* @__PURE__ */ jsxs48(
|
|
10078
|
-
"button",
|
|
10079
|
-
{
|
|
10080
|
-
type: "button",
|
|
10081
|
-
onClick: segment.onClick,
|
|
10082
|
-
className: cn(
|
|
10083
|
-
"flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0",
|
|
10084
|
-
s.text,
|
|
10085
|
-
"font-medium hover:text-white",
|
|
10086
|
-
colors ? [colors.text, `hover:${colors.bg}`] : ["text-neutral-300", "hover:bg-neutral-700/50"]
|
|
10087
|
-
),
|
|
10088
|
-
children: [
|
|
10089
|
-
segment.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: segment.icon, color: segment.color, size }),
|
|
10090
|
-
/* @__PURE__ */ jsx57("span", { className: "truncate max-w-[200px]", children: segment.label })
|
|
10091
|
-
]
|
|
10092
|
-
}
|
|
10093
|
-
) : /* @__PURE__ */ jsxs48(
|
|
10094
|
-
"div",
|
|
10095
|
-
{
|
|
10096
|
-
className: cn(
|
|
10097
|
-
"flex items-center gap-1.5 px-2 py-0.5 rounded-md min-w-0",
|
|
10098
|
-
s.text,
|
|
10099
|
-
isLast ? ["font-medium bg-neutral-700/50", colors ? colors.text : "text-white"] : ["font-medium", colors ? colors.text : "text-neutral-300"]
|
|
10100
|
-
),
|
|
10101
|
-
children: [
|
|
10102
|
-
segment.icon && /* @__PURE__ */ jsx57(SegmentIcon2, { icon: segment.icon, color: segment.color, size }),
|
|
10103
|
-
/* @__PURE__ */ jsx57("span", { className: "truncate max-w-[200px]", children: segment.label })
|
|
10104
|
-
]
|
|
10105
|
-
}
|
|
10106
|
-
)
|
|
10107
|
-
] }, segment.id);
|
|
10108
|
-
})
|
|
10152
|
+
renderSegments()
|
|
10109
10153
|
] }) });
|
|
10110
10154
|
}
|
|
10111
10155
|
|