@toolr/ui-design 0.1.0
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 +63 -0
- package/components/content/info-panel-primitives.tsx +297 -0
- package/components/diagrams/diagram-utils.tsx +908 -0
- package/components/hooks/use-click-outside.ts +27 -0
- package/components/hooks/use-dropdown-max-height.ts +20 -0
- package/components/hooks/use-navigation-history.ts +94 -0
- package/components/lib/ai-tools.tsx +44 -0
- package/components/lib/cn.ts +6 -0
- package/components/lib/form-colors.ts +32 -0
- package/components/lib/theme-engine.ts +97 -0
- package/components/lib/toolr-brand.tsx +31 -0
- package/components/sections/ai-tools-paths/index.ts +37 -0
- package/components/sections/ai-tools-paths/tools-paths-panel.tsx +212 -0
- package/components/sections/ai-tools-paths/types.ts +111 -0
- package/components/sections/ai-tools-paths/use-tools-paths.ts +159 -0
- package/components/sections/captured-issues/captured-issues-panel.tsx +214 -0
- package/components/sections/captured-issues/index.ts +38 -0
- package/components/sections/captured-issues/types.ts +113 -0
- package/components/sections/captured-issues/use-captured-issues.ts +111 -0
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +420 -0
- package/components/sections/golden-snapshots/golden-sync-panel.tsx +223 -0
- package/components/sections/golden-snapshots/index.ts +145 -0
- package/components/sections/golden-snapshots/snapshot-manager.tsx +200 -0
- package/components/sections/golden-snapshots/status-overview.tsx +305 -0
- package/components/sections/golden-snapshots/types.ts +288 -0
- package/components/sections/golden-snapshots/use-golden-sync.ts +477 -0
- package/components/sections/golden-snapshots/version-manager.tsx +186 -0
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +210 -0
- package/components/sections/prompt-editor/index.ts +121 -0
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +276 -0
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +514 -0
- package/components/sections/prompt-editor/types.ts +101 -0
- package/components/sections/prompt-editor/use-prompt-editor.ts +131 -0
- package/components/sections/report-bug/error-logger.ts +392 -0
- package/components/sections/report-bug/index.ts +59 -0
- package/components/sections/report-bug/issue-reporter-api.ts +83 -0
- package/components/sections/report-bug/report-bug-form.tsx +282 -0
- package/components/sections/report-bug/screenshot-uploader.tsx +228 -0
- package/components/sections/report-bug/use-report-bug.ts +170 -0
- package/components/sections/snapshot-browser/index.ts +53 -0
- package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +147 -0
- package/components/sections/snapshot-browser/snapshot-tree.tsx +451 -0
- package/components/sections/snapshot-browser/types.ts +106 -0
- package/components/sections/snapshot-browser/use-snapshot-browser.ts +125 -0
- package/components/sections/snippets-editor/index.ts +31 -0
- package/components/sections/snippets-editor/snippets-editor.tsx +381 -0
- package/components/sections/snippets-editor/types.ts +48 -0
- package/components/sections/snippets-editor/use-snippets-editor.ts +217 -0
- package/components/ui/action-dialog.tsx +309 -0
- package/components/ui/ai-action-button.tsx +137 -0
- package/components/ui/ai-execution-action-buttons.tsx +106 -0
- package/components/ui/badge.tsx +67 -0
- package/components/ui/bottom-panel-header.tsx +240 -0
- package/components/ui/breadcrumb.tsx +168 -0
- package/components/ui/checkbox.tsx +102 -0
- package/components/ui/collapsible-section.tsx +100 -0
- package/components/ui/confirm-badge.tsx +71 -0
- package/components/ui/detail-section.tsx +67 -0
- package/components/ui/detail-view-wrapper.tsx +55 -0
- package/components/ui/editor-placeholder-card.tsx +197 -0
- package/components/ui/editor-toolbar.tsx +123 -0
- package/components/ui/execution-details-panel.tsx +93 -0
- package/components/ui/extension-list-card.tsx +105 -0
- package/components/ui/file-structure-section.tsx +373 -0
- package/components/ui/file-tree.tsx +171 -0
- package/components/ui/files-panel.tsx +251 -0
- package/components/ui/filter-dropdown.tsx +173 -0
- package/components/ui/form-actions.tsx +127 -0
- package/components/ui/frontmatter-form-header.tsx +80 -0
- package/components/ui/icon-button.tsx +388 -0
- package/components/ui/input.tsx +211 -0
- package/components/ui/label.tsx +159 -0
- package/components/ui/layout-tab-bar.tsx +289 -0
- package/components/ui/modal.tsx +194 -0
- package/components/ui/nav-card.tsx +81 -0
- package/components/ui/navigation-bar.tsx +285 -0
- package/components/ui/number-input.tsx +165 -0
- package/components/ui/registry-browser.tsx +261 -0
- package/components/ui/registry-card.tsx +710 -0
- package/components/ui/registry-detail.tsx +224 -0
- package/components/ui/resizable-textarea.tsx +290 -0
- package/components/ui/scope-badge.tsx +67 -0
- package/components/ui/segmented-toggle.tsx +133 -0
- package/components/ui/select.tsx +172 -0
- package/components/ui/selection-grid.tsx +313 -0
- package/components/ui/setting-row.tsx +97 -0
- package/components/ui/snapshot-card.tsx +107 -0
- package/components/ui/snippets-panel.tsx +161 -0
- package/components/ui/sort-dropdown.tsx +109 -0
- package/components/ui/status-card.tsx +96 -0
- package/components/ui/tab-bar.tsx +340 -0
- package/components/ui/toggle.tsx +142 -0
- package/components/ui/tooltip.tsx +326 -0
- package/dist/content.d.ts +110 -0
- package/dist/content.js +195 -0
- package/dist/diagrams.d.ts +371 -0
- package/dist/diagrams.js +702 -0
- package/dist/index.d.ts +2714 -0
- package/dist/index.js +11220 -0
- package/dist/preset.d.ts +24 -0
- package/dist/preset.js +17 -0
- package/dist/tokens/tokens/primitives.css +45 -0
- package/dist/tokens/tokens/semantic.css +46 -0
- package/dist/tokens/tokens/theme.css +11 -0
- package/dist/tokens/tokens/tokens.json +65 -0
- package/index.ts +123 -0
- package/package.json +63 -0
- package/tailwind-preset.ts +22 -0
- package/tokens/primitives.css +45 -0
- package/tokens/semantic.css +46 -0
- package/tokens/theme.css +11 -0
- package/tokens/tokens.json +65 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { useState, useRef, useLayoutEffect, useEffect } from 'react'
|
|
2
|
+
import type { ReactNode } from 'react'
|
|
3
|
+
import { createPortal } from 'react-dom'
|
|
4
|
+
|
|
5
|
+
export interface TooltipContent {
|
|
6
|
+
title?: string
|
|
7
|
+
/** Description can be a string or React node for rich content with icons/colors */
|
|
8
|
+
description: string | ReactNode
|
|
9
|
+
extra?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right' | 'auto'
|
|
13
|
+
export type TooltipAlign = 'start' | 'center' | 'end'
|
|
14
|
+
type ResolvedPosition = 'top' | 'bottom' | 'left' | 'right'
|
|
15
|
+
|
|
16
|
+
interface TooltipProps {
|
|
17
|
+
children: ReactNode
|
|
18
|
+
/** Tooltip content with required title and description */
|
|
19
|
+
content: TooltipContent
|
|
20
|
+
position?: TooltipPosition
|
|
21
|
+
align?: TooltipAlign
|
|
22
|
+
/** Allow multi-line content (disables whitespace-nowrap) */
|
|
23
|
+
multiline?: boolean
|
|
24
|
+
/** Maximum width for multiline tooltips (number for px, string for CSS value, default '80vw') */
|
|
25
|
+
maxWidth?: number | string
|
|
26
|
+
/** Maximum height for scrollable tooltips (only when interactive) */
|
|
27
|
+
maxHeight?: number
|
|
28
|
+
/** Allow hovering into the tooltip and scrolling its content */
|
|
29
|
+
interactive?: boolean
|
|
30
|
+
/** Trigger mode: 'hover' (default) or 'click' (toggle on click, dismiss on click-outside) */
|
|
31
|
+
trigger?: 'hover' | 'click'
|
|
32
|
+
/** Additional classes for the wrapper element (e.g., 'h-full' for flex containers) */
|
|
33
|
+
wrapperClassName?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const TOOLTIP_GAP = 8
|
|
37
|
+
const VIEWPORT_PADDING = 8
|
|
38
|
+
const AUTO_POSITION_THRESHOLD = 16
|
|
39
|
+
|
|
40
|
+
/** Resolve auto position based on available space */
|
|
41
|
+
function resolveAutoPosition(
|
|
42
|
+
triggerRect: DOMRect,
|
|
43
|
+
tooltipRect: DOMRect
|
|
44
|
+
): ResolvedPosition {
|
|
45
|
+
const spaceAbove = triggerRect.top
|
|
46
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom
|
|
47
|
+
const requiredSpace = tooltipRect.height + AUTO_POSITION_THRESHOLD
|
|
48
|
+
|
|
49
|
+
if (spaceAbove >= requiredSpace) return 'top'
|
|
50
|
+
if (spaceBelow >= requiredSpace) return 'bottom'
|
|
51
|
+
return 'top'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Calculate initial position based on trigger and resolved position */
|
|
55
|
+
function calculateBasePosition(
|
|
56
|
+
triggerRect: DOMRect,
|
|
57
|
+
resolvedPosition: ResolvedPosition,
|
|
58
|
+
align: TooltipAlign
|
|
59
|
+
): { top: number; left: number } {
|
|
60
|
+
let top = 0
|
|
61
|
+
let left = 0
|
|
62
|
+
|
|
63
|
+
switch (resolvedPosition) {
|
|
64
|
+
case 'top':
|
|
65
|
+
top = triggerRect.top - TOOLTIP_GAP
|
|
66
|
+
left = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right : triggerRect.left + triggerRect.width / 2
|
|
67
|
+
break
|
|
68
|
+
case 'bottom':
|
|
69
|
+
top = triggerRect.bottom + TOOLTIP_GAP
|
|
70
|
+
left = align === 'start' ? triggerRect.left : align === 'end' ? triggerRect.right : triggerRect.left + triggerRect.width / 2
|
|
71
|
+
break
|
|
72
|
+
case 'left':
|
|
73
|
+
top = triggerRect.top + triggerRect.height / 2
|
|
74
|
+
left = triggerRect.left - TOOLTIP_GAP
|
|
75
|
+
break
|
|
76
|
+
case 'right':
|
|
77
|
+
top = triggerRect.top + triggerRect.height / 2
|
|
78
|
+
left = triggerRect.right + TOOLTIP_GAP
|
|
79
|
+
break
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { top, left }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Adjust position based on tooltip dimensions */
|
|
86
|
+
function adjustForTooltipSize(
|
|
87
|
+
coords: { top: number; left: number },
|
|
88
|
+
tooltipRect: DOMRect,
|
|
89
|
+
resolvedPosition: ResolvedPosition,
|
|
90
|
+
align: TooltipAlign
|
|
91
|
+
): { top: number; left: number } {
|
|
92
|
+
let { top, left } = coords
|
|
93
|
+
|
|
94
|
+
if (resolvedPosition === 'top') {
|
|
95
|
+
top -= tooltipRect.height
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const isVertical = resolvedPosition === 'top' || resolvedPosition === 'bottom'
|
|
99
|
+
if (isVertical) {
|
|
100
|
+
if (align === 'center') {
|
|
101
|
+
left -= tooltipRect.width / 2
|
|
102
|
+
} else if (align === 'end') {
|
|
103
|
+
left -= tooltipRect.width
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (resolvedPosition === 'left') {
|
|
108
|
+
left -= tooltipRect.width
|
|
109
|
+
top -= tooltipRect.height / 2
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (resolvedPosition === 'right') {
|
|
113
|
+
top -= tooltipRect.height / 2
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { top, left }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Clamp position to viewport bounds */
|
|
120
|
+
function clampToViewport(
|
|
121
|
+
coords: { top: number; left: number },
|
|
122
|
+
tooltipRect: DOMRect
|
|
123
|
+
): { top: number; left: number } {
|
|
124
|
+
let { top, left } = coords
|
|
125
|
+
|
|
126
|
+
if (left < VIEWPORT_PADDING) left = VIEWPORT_PADDING
|
|
127
|
+
if (left + tooltipRect.width > window.innerWidth - VIEWPORT_PADDING) {
|
|
128
|
+
left = window.innerWidth - tooltipRect.width - VIEWPORT_PADDING
|
|
129
|
+
}
|
|
130
|
+
if (top < VIEWPORT_PADDING) top = VIEWPORT_PADDING
|
|
131
|
+
if (top + tooltipRect.height > window.innerHeight - VIEWPORT_PADDING) {
|
|
132
|
+
top = window.innerHeight - tooltipRect.height - VIEWPORT_PADDING
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { top, left }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const ARROW_BASE_CLASSES = 'absolute w-3 h-3 bg-neutral-800 border-neutral-600 rotate-45'
|
|
139
|
+
|
|
140
|
+
function getAlignmentClass(align: TooltipAlign): string {
|
|
141
|
+
if (align === 'start') return 'left-2'
|
|
142
|
+
if (align === 'end') return 'right-2'
|
|
143
|
+
return 'left-1/2 -translate-x-1/2'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Get CSS classes for the tooltip arrow based on position and alignment */
|
|
147
|
+
function getArrowClasses(pos: ResolvedPosition, align: TooltipAlign): string {
|
|
148
|
+
switch (pos) {
|
|
149
|
+
case 'top':
|
|
150
|
+
return `${ARROW_BASE_CLASSES} -bottom-1.5 border-r border-b ${getAlignmentClass(align)}`
|
|
151
|
+
case 'bottom':
|
|
152
|
+
return `${ARROW_BASE_CLASSES} -top-1.5 border-l border-t ${getAlignmentClass(align)}`
|
|
153
|
+
case 'left':
|
|
154
|
+
return `${ARROW_BASE_CLASSES} -right-1.5 border-r border-t top-1/2 -translate-y-1/2`
|
|
155
|
+
case 'right':
|
|
156
|
+
return `${ARROW_BASE_CLASSES} -left-1.5 border-l border-b top-1/2 -translate-y-1/2`
|
|
157
|
+
default:
|
|
158
|
+
return ARROW_BASE_CLASSES
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Portal-based tooltip that renders at document body level.
|
|
164
|
+
* This ensures tooltips always appear above all other elements,
|
|
165
|
+
* regardless of parent overflow or z-index settings.
|
|
166
|
+
*/
|
|
167
|
+
export function Tooltip({
|
|
168
|
+
children,
|
|
169
|
+
content,
|
|
170
|
+
position = 'top',
|
|
171
|
+
align = 'start',
|
|
172
|
+
multiline = false,
|
|
173
|
+
maxWidth,
|
|
174
|
+
maxHeight,
|
|
175
|
+
trigger = 'hover',
|
|
176
|
+
interactive = false,
|
|
177
|
+
wrapperClassName = '',
|
|
178
|
+
}: TooltipProps) {
|
|
179
|
+
const [isVisible, setIsVisible] = useState(false)
|
|
180
|
+
const [coords, setCoords] = useState({ top: 0, left: 0 })
|
|
181
|
+
const [actualPosition, setActualPosition] = useState<ResolvedPosition>(position === 'auto' ? 'top' : position)
|
|
182
|
+
const triggerRef = useRef<HTMLDivElement>(null)
|
|
183
|
+
const tooltipRef = useRef<HTMLDivElement>(null)
|
|
184
|
+
const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
185
|
+
|
|
186
|
+
const show = () => {
|
|
187
|
+
if (hideTimeoutRef.current) {
|
|
188
|
+
clearTimeout(hideTimeoutRef.current)
|
|
189
|
+
hideTimeoutRef.current = null
|
|
190
|
+
}
|
|
191
|
+
setIsVisible(true)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const hide = () => {
|
|
195
|
+
if (interactive) {
|
|
196
|
+
// Small delay so the user can move from trigger to tooltip
|
|
197
|
+
hideTimeoutRef.current = setTimeout(() => setIsVisible(false), 150)
|
|
198
|
+
} else {
|
|
199
|
+
setIsVisible(false)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Click-outside dismissal for click trigger mode
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
if (trigger !== 'click' || !isVisible) return
|
|
206
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
207
|
+
if (
|
|
208
|
+
triggerRef.current && !triggerRef.current.contains(e.target as Node) &&
|
|
209
|
+
tooltipRef.current && !tooltipRef.current.contains(e.target as Node)
|
|
210
|
+
) {
|
|
211
|
+
setIsVisible(false)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
document.addEventListener('mousedown', handleClickOutside)
|
|
215
|
+
return () => document.removeEventListener('mousedown', handleClickOutside)
|
|
216
|
+
}, [trigger, isVisible])
|
|
217
|
+
|
|
218
|
+
const updatePosition = () => {
|
|
219
|
+
if (!triggerRef.current) return
|
|
220
|
+
const triggerRect = triggerRef.current.getBoundingClientRect()
|
|
221
|
+
const tooltipEl = tooltipRef.current
|
|
222
|
+
|
|
223
|
+
let resolvedPosition: ResolvedPosition = position === 'auto' ? 'top' : position
|
|
224
|
+
|
|
225
|
+
if (position === 'auto' && tooltipEl) {
|
|
226
|
+
const tooltipRect = tooltipEl.getBoundingClientRect()
|
|
227
|
+
resolvedPosition = resolveAutoPosition(triggerRect, tooltipRect)
|
|
228
|
+
setActualPosition(resolvedPosition)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let newCoords = calculateBasePosition(triggerRect, resolvedPosition, align)
|
|
232
|
+
|
|
233
|
+
if (tooltipEl) {
|
|
234
|
+
const tooltipRect = tooltipEl.getBoundingClientRect()
|
|
235
|
+
newCoords = adjustForTooltipSize(newCoords, tooltipRect, resolvedPosition, align)
|
|
236
|
+
newCoords = clampToViewport(newCoords, tooltipRect)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
setCoords(newCoords)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
useLayoutEffect(() => {
|
|
243
|
+
if (!isVisible) return
|
|
244
|
+
updatePosition()
|
|
245
|
+
}, [isVisible, position, align])
|
|
246
|
+
|
|
247
|
+
// Reposition on scroll for click-triggered tooltips so they follow the trigger
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
if (trigger !== 'click' || !isVisible) return
|
|
250
|
+
const handleScroll = () => updatePosition()
|
|
251
|
+
window.addEventListener('scroll', handleScroll, true)
|
|
252
|
+
return () => window.removeEventListener('scroll', handleScroll, true)
|
|
253
|
+
}, [trigger, isVisible, position, align])
|
|
254
|
+
|
|
255
|
+
const resolvedPos = position === 'auto' ? actualPosition : position
|
|
256
|
+
const arrowClasses = getArrowClasses(resolvedPos, align)
|
|
257
|
+
|
|
258
|
+
const tooltipContent = (
|
|
259
|
+
<div
|
|
260
|
+
ref={tooltipRef}
|
|
261
|
+
className={`fixed px-3 py-1.5 bg-neutral-800 border border-neutral-600 rounded-lg shadow-xl z-[9999] ${interactive || trigger === 'click' ? '' : 'pointer-events-none'} ${multiline ? 'whitespace-pre-line' : 'whitespace-nowrap'}`}
|
|
262
|
+
style={{
|
|
263
|
+
top: coords.top,
|
|
264
|
+
left: coords.left,
|
|
265
|
+
opacity: isVisible ? 1 : 0,
|
|
266
|
+
visibility: isVisible ? 'visible' : 'hidden',
|
|
267
|
+
transition: 'opacity 150ms, visibility 150ms',
|
|
268
|
+
...(multiline ? { maxWidth: maxWidth ?? '80vw' } : {}),
|
|
269
|
+
...(maxHeight ? { maxHeight, overflowY: 'auto' as const } : {}),
|
|
270
|
+
}}
|
|
271
|
+
onMouseEnter={interactive && trigger !== 'click' ? show : undefined}
|
|
272
|
+
onMouseLeave={interactive && trigger !== 'click' ? hide : undefined}
|
|
273
|
+
>
|
|
274
|
+
{content.title && <p className="text-sm text-neutral-200 font-medium">{content.title}</p>}
|
|
275
|
+
<div className={`text-xs text-neutral-400 ${content.title ? 'mt-0.5' : ''}`}>{content.description}</div>
|
|
276
|
+
{content.extra && <p className="text-xs text-orange-400/70 mt-0.5">{content.extra}</p>}
|
|
277
|
+
<div className={arrowClasses} />
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<>
|
|
283
|
+
<div
|
|
284
|
+
ref={triggerRef}
|
|
285
|
+
onMouseEnter={trigger === 'hover' ? show : undefined}
|
|
286
|
+
onMouseLeave={trigger === 'hover' ? hide : undefined}
|
|
287
|
+
onMouseDown={trigger === 'hover' ? () => setIsVisible(false) : undefined}
|
|
288
|
+
onClick={trigger === 'click' ? () => setIsVisible((v) => !v) : undefined}
|
|
289
|
+
className={wrapperClassName || 'inline-flex'}
|
|
290
|
+
>
|
|
291
|
+
{children}
|
|
292
|
+
</div>
|
|
293
|
+
{createPortal(tooltipContent, document.body)}
|
|
294
|
+
</>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Simple tooltip wrapper for icon buttons.
|
|
300
|
+
* Provides consistent styling for action button tooltips.
|
|
301
|
+
*/
|
|
302
|
+
export function TooltipButton({
|
|
303
|
+
children,
|
|
304
|
+
content,
|
|
305
|
+
onClick,
|
|
306
|
+
className,
|
|
307
|
+
disabled,
|
|
308
|
+
}: {
|
|
309
|
+
children: ReactNode
|
|
310
|
+
content: TooltipContent
|
|
311
|
+
onClick?: () => void
|
|
312
|
+
className?: string
|
|
313
|
+
disabled?: boolean
|
|
314
|
+
}) {
|
|
315
|
+
return (
|
|
316
|
+
<Tooltip content={content} position="top" align="start">
|
|
317
|
+
<button
|
|
318
|
+
onClick={onClick}
|
|
319
|
+
disabled={disabled}
|
|
320
|
+
className={className}
|
|
321
|
+
>
|
|
322
|
+
{children}
|
|
323
|
+
</button>
|
|
324
|
+
</Tooltip>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
declare function P({ children }: {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}): react_jsx_runtime.JSX.Element;
|
|
7
|
+
declare function SectionHeader({ color, children }: {
|
|
8
|
+
color?: string;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}): react_jsx_runtime.JSX.Element;
|
|
11
|
+
declare function DL({ children }: {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}): react_jsx_runtime.JSX.Element;
|
|
14
|
+
declare function DLRow({ term, children, even }: {
|
|
15
|
+
term: ReactNode;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
even?: boolean;
|
|
18
|
+
}): react_jsx_runtime.JSX.Element;
|
|
19
|
+
declare function UL({ children }: {
|
|
20
|
+
children: ReactNode;
|
|
21
|
+
}): react_jsx_runtime.JSX.Element;
|
|
22
|
+
declare function LI({ color, children }: {
|
|
23
|
+
color: string;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
}): react_jsx_runtime.JSX.Element;
|
|
26
|
+
declare function OL({ children }: {
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}): react_jsx_runtime.JSX.Element;
|
|
29
|
+
declare function OLI({ n, color, children }: {
|
|
30
|
+
n: number;
|
|
31
|
+
color: string;
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}): react_jsx_runtime.JSX.Element;
|
|
34
|
+
declare function getCalloutColors(color: string): {
|
|
35
|
+
borderL: string;
|
|
36
|
+
borderY: string;
|
|
37
|
+
bg: string;
|
|
38
|
+
text: string;
|
|
39
|
+
codeText: string;
|
|
40
|
+
dimText: string;
|
|
41
|
+
};
|
|
42
|
+
declare function Callout({ color, children }: {
|
|
43
|
+
color: string;
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
}): react_jsx_runtime.JSX.Element;
|
|
46
|
+
declare function CalloutCode({ color, children }: {
|
|
47
|
+
color: string;
|
|
48
|
+
children: ReactNode;
|
|
49
|
+
}): react_jsx_runtime.JSX.Element;
|
|
50
|
+
declare function CalloutDim({ children }: {
|
|
51
|
+
children: ReactNode;
|
|
52
|
+
}): react_jsx_runtime.JSX.Element;
|
|
53
|
+
declare function CodeBlock({ children }: {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
}): react_jsx_runtime.JSX.Element;
|
|
56
|
+
declare function CK({ color, children }: {
|
|
57
|
+
color?: string;
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
}): react_jsx_runtime.JSX.Element;
|
|
60
|
+
declare function ExternalLink({ href, children }: {
|
|
61
|
+
href: string;
|
|
62
|
+
children: ReactNode;
|
|
63
|
+
}): react_jsx_runtime.JSX.Element;
|
|
64
|
+
declare function LocationList({ children }: {
|
|
65
|
+
children: ReactNode;
|
|
66
|
+
}): react_jsx_runtime.JSX.Element;
|
|
67
|
+
declare function LocationItem({ color, label, children, even, }: {
|
|
68
|
+
color: string;
|
|
69
|
+
label: string;
|
|
70
|
+
children: ReactNode;
|
|
71
|
+
even?: boolean;
|
|
72
|
+
}): react_jsx_runtime.JSX.Element;
|
|
73
|
+
declare function TitledLI({ color, title, children }: {
|
|
74
|
+
color: string;
|
|
75
|
+
title: string;
|
|
76
|
+
children: ReactNode;
|
|
77
|
+
}): react_jsx_runtime.JSX.Element;
|
|
78
|
+
declare function CalloutDialog({ color, lines }: {
|
|
79
|
+
color: string;
|
|
80
|
+
lines: {
|
|
81
|
+
speaker: string;
|
|
82
|
+
text: string;
|
|
83
|
+
}[];
|
|
84
|
+
}): react_jsx_runtime.JSX.Element;
|
|
85
|
+
declare function TagGrid({ color, tags }: {
|
|
86
|
+
color: string;
|
|
87
|
+
tags: string[];
|
|
88
|
+
}): react_jsx_runtime.JSX.Element;
|
|
89
|
+
declare function StatusBadge({ value, badgeColor, label, children, even }: {
|
|
90
|
+
value: string;
|
|
91
|
+
badgeColor: string;
|
|
92
|
+
label: string;
|
|
93
|
+
children: ReactNode;
|
|
94
|
+
even?: boolean;
|
|
95
|
+
}): react_jsx_runtime.JSX.Element;
|
|
96
|
+
declare function BulletGridRow({ color, term, children, even }: {
|
|
97
|
+
color: string;
|
|
98
|
+
term: string;
|
|
99
|
+
children: ReactNode;
|
|
100
|
+
even?: boolean;
|
|
101
|
+
}): react_jsx_runtime.JSX.Element;
|
|
102
|
+
declare function NumberGridRow({ color, n, term, children, even }: {
|
|
103
|
+
color: string;
|
|
104
|
+
n: number;
|
|
105
|
+
term: string;
|
|
106
|
+
children: ReactNode;
|
|
107
|
+
even?: boolean;
|
|
108
|
+
}): react_jsx_runtime.JSX.Element;
|
|
109
|
+
|
|
110
|
+
export { BulletGridRow, CK, Callout, CalloutCode, CalloutDialog, CalloutDim, CodeBlock, DL, DLRow, ExternalLink, LI, LocationItem, LocationList, NumberGridRow, OL, OLI, P, SectionHeader, StatusBadge, TagGrid, TitledLI, UL, getCalloutColors };
|
package/dist/content.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// components/content/info-panel-primitives.tsx
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
function P({ children }) {
|
|
4
|
+
return /* @__PURE__ */ jsx("p", { className: "text-sm text-neutral-400 leading-relaxed mb-5", children });
|
|
5
|
+
}
|
|
6
|
+
function SectionHeader({ color, children }) {
|
|
7
|
+
const textColor = color ? `text-${color}-500/70` : "text-neutral-500";
|
|
8
|
+
return /* @__PURE__ */ jsx("p", { className: `${textColor} text-xs uppercase font-semibold pb-0.5 border-b border-neutral-700/50 mb-2.5`, style: { letterSpacing: "0.8px" }, children });
|
|
9
|
+
}
|
|
10
|
+
function DL({ children }) {
|
|
11
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-5", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-[auto_1fr] gap-x-4", children }) });
|
|
12
|
+
}
|
|
13
|
+
function DLRow({ term, children, even }) {
|
|
14
|
+
const bg = even ? "bg-white/[0.015]" : "";
|
|
15
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16
|
+
/* @__PURE__ */ jsx("div", { className: `py-2 border-b border-neutral-800/60 ${bg} font-semibold text-sm whitespace-nowrap`, children: term }),
|
|
17
|
+
/* @__PURE__ */ jsx("div", { className: `py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`, children })
|
|
18
|
+
] });
|
|
19
|
+
}
|
|
20
|
+
function UL({ children }) {
|
|
21
|
+
return /* @__PURE__ */ jsx("ul", { className: "text-sm text-neutral-400 space-y-2 mb-5", children });
|
|
22
|
+
}
|
|
23
|
+
function LI({ color, children }) {
|
|
24
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2", children: [
|
|
25
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400 shrink-0`, style: { marginTop: "3px", fontSize: "18px", lineHeight: "14px" }, children: "\u2022" }),
|
|
26
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
27
|
+
] });
|
|
28
|
+
}
|
|
29
|
+
function OL({ children }) {
|
|
30
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-2 mb-5", children });
|
|
31
|
+
}
|
|
32
|
+
function OLI({ n, color, children }) {
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5 text-sm", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("span", { className: `text-${color}-400 shrink-0 w-4 text-right font-bold`, children: [
|
|
35
|
+
n,
|
|
36
|
+
"."
|
|
37
|
+
] }),
|
|
38
|
+
/* @__PURE__ */ jsx("span", { className: "text-neutral-400", children })
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
var CALLOUT_COLORS = {
|
|
42
|
+
amber: { borderL: "border-amber-500/40", borderY: "border-y-amber-500/15", bg: "bg-amber-500/5", text: "text-amber-400", codeText: "text-amber-300/80", dimText: "text-amber-400/60" },
|
|
43
|
+
blue: { borderL: "border-blue-500/40", borderY: "border-y-blue-500/15", bg: "bg-blue-500/5", text: "text-blue-400", codeText: "text-blue-300/80", dimText: "text-blue-400/60" },
|
|
44
|
+
cyan: { borderL: "border-cyan-500/40", borderY: "border-y-cyan-500/15", bg: "bg-cyan-500/5", text: "text-cyan-400", codeText: "text-cyan-300/80", dimText: "text-cyan-400/60" },
|
|
45
|
+
emerald: { borderL: "border-emerald-500/40", borderY: "border-y-emerald-500/15", bg: "bg-emerald-500/5", text: "text-emerald-400", codeText: "text-emerald-300/80", dimText: "text-emerald-400/60" },
|
|
46
|
+
fuchsia: { borderL: "border-fuchsia-500/40", borderY: "border-y-fuchsia-500/15", bg: "bg-fuchsia-500/5", text: "text-fuchsia-400", codeText: "text-fuchsia-300/80", dimText: "text-fuchsia-400/60" },
|
|
47
|
+
green: { borderL: "border-green-500/40", borderY: "border-y-green-500/15", bg: "bg-green-500/5", text: "text-green-400", codeText: "text-green-300/80", dimText: "text-green-400/60" },
|
|
48
|
+
indigo: { borderL: "border-indigo-500/40", borderY: "border-y-indigo-500/15", bg: "bg-indigo-500/5", text: "text-indigo-400", codeText: "text-indigo-300/80", dimText: "text-indigo-400/60" },
|
|
49
|
+
lime: { borderL: "border-lime-500/40", borderY: "border-y-lime-500/15", bg: "bg-lime-500/5", text: "text-lime-400", codeText: "text-lime-300/80", dimText: "text-lime-400/60" },
|
|
50
|
+
orange: { borderL: "border-orange-500/40", borderY: "border-y-orange-500/15", bg: "bg-orange-500/5", text: "text-orange-400", codeText: "text-orange-300/80", dimText: "text-orange-400/60" },
|
|
51
|
+
pink: { borderL: "border-pink-500/40", borderY: "border-y-pink-500/15", bg: "bg-pink-500/5", text: "text-pink-400", codeText: "text-pink-300/80", dimText: "text-pink-400/60" },
|
|
52
|
+
purple: { borderL: "border-purple-500/40", borderY: "border-y-purple-500/15", bg: "bg-purple-500/5", text: "text-purple-400", codeText: "text-purple-300/80", dimText: "text-purple-400/60" },
|
|
53
|
+
red: { borderL: "border-red-500/40", borderY: "border-y-red-500/15", bg: "bg-red-500/5", text: "text-red-400", codeText: "text-red-300/80", dimText: "text-red-400/60" },
|
|
54
|
+
rose: { borderL: "border-rose-500/40", borderY: "border-y-rose-500/15", bg: "bg-rose-500/5", text: "text-rose-400", codeText: "text-rose-300/80", dimText: "text-rose-400/60" },
|
|
55
|
+
sky: { borderL: "border-sky-500/40", borderY: "border-y-sky-500/15", bg: "bg-sky-500/5", text: "text-sky-400", codeText: "text-sky-300/80", dimText: "text-sky-400/60" },
|
|
56
|
+
teal: { borderL: "border-teal-500/40", borderY: "border-y-teal-500/15", bg: "bg-teal-500/5", text: "text-teal-400", codeText: "text-teal-300/80", dimText: "text-teal-400/60" },
|
|
57
|
+
violet: { borderL: "border-violet-500/40", borderY: "border-y-violet-500/15", bg: "bg-violet-500/5", text: "text-violet-400", codeText: "text-violet-300/80", dimText: "text-violet-400/60" }
|
|
58
|
+
};
|
|
59
|
+
function getCalloutColors(color) {
|
|
60
|
+
return CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue;
|
|
61
|
+
}
|
|
62
|
+
function Callout({ color, children }) {
|
|
63
|
+
const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue;
|
|
64
|
+
return /* @__PURE__ */ jsx("div", { className: `border-l-4 ${c.borderL} border-y ${c.borderY} ${c.bg} px-3 py-2.5 rounded-r mb-5 text-sm text-neutral-400`, children });
|
|
65
|
+
}
|
|
66
|
+
function CalloutCode({ color, children }) {
|
|
67
|
+
const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue;
|
|
68
|
+
return /* @__PURE__ */ jsx("code", { className: `block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-[13px] ${c.codeText}`, children });
|
|
69
|
+
}
|
|
70
|
+
function CalloutDim({ children }) {
|
|
71
|
+
return /* @__PURE__ */ jsx("p", { className: "text-neutral-500 mt-1.5", children });
|
|
72
|
+
}
|
|
73
|
+
function CodeBlock({ children }) {
|
|
74
|
+
return /* @__PURE__ */ jsx("div", { className: "bg-neutral-900/60 rounded-md p-3 font-mono text-xs text-neutral-400 mb-5 whitespace-pre overflow-x-auto leading-normal", children });
|
|
75
|
+
}
|
|
76
|
+
function CK({ color, children }) {
|
|
77
|
+
const textColor = color ? `text-${color}-400` : "";
|
|
78
|
+
return /* @__PURE__ */ jsx("code", { className: `bg-neutral-800/80 px-1.5 py-px rounded text-[0.9em] ${textColor}`, children });
|
|
79
|
+
}
|
|
80
|
+
function ExternalLink({ href, children }) {
|
|
81
|
+
return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "underline cursor-pointer", children });
|
|
82
|
+
}
|
|
83
|
+
function LocationList({ children }) {
|
|
84
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-5", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-[auto_1fr] gap-x-4", children }) });
|
|
85
|
+
}
|
|
86
|
+
function LocationItem({
|
|
87
|
+
color,
|
|
88
|
+
label,
|
|
89
|
+
children,
|
|
90
|
+
even
|
|
91
|
+
}) {
|
|
92
|
+
const bg = even ? "bg-white/[0.015]" : "";
|
|
93
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
94
|
+
/* @__PURE__ */ jsxs("div", { className: `py-2 border-b border-neutral-800/60 ${bg} flex items-center gap-1.5`, children: [
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
className: `w-2 h-2 rounded-full bg-${color}-500/50 border border-${color}-500 shrink-0`
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400 text-sm font-semibold`, children: label })
|
|
102
|
+
] }),
|
|
103
|
+
/* @__PURE__ */ jsx("div", { className: `py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`, children })
|
|
104
|
+
] });
|
|
105
|
+
}
|
|
106
|
+
function TitledLI({ color, title, children }) {
|
|
107
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-sm text-neutral-400", children: [
|
|
108
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400 shrink-0`, style: { marginTop: "3px", fontSize: "18px", lineHeight: "14px" }, children: "\u2022" }),
|
|
109
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
110
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-300 font-semibold`, children: title }),
|
|
111
|
+
" ",
|
|
112
|
+
"\u2014 ",
|
|
113
|
+
children
|
|
114
|
+
] })
|
|
115
|
+
] });
|
|
116
|
+
}
|
|
117
|
+
function CalloutDialog({ color, lines }) {
|
|
118
|
+
return /* @__PURE__ */ jsx("div", { className: "bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-[13px]", children: lines.map((line, idx) => /* @__PURE__ */ jsxs("div", { children: [
|
|
119
|
+
/* @__PURE__ */ jsxs("span", { className: `text-${color}-300 font-semibold mr-1`, children: [
|
|
120
|
+
line.speaker,
|
|
121
|
+
":"
|
|
122
|
+
] }),
|
|
123
|
+
/* @__PURE__ */ jsx("span", { className: "text-neutral-400", children: line.text })
|
|
124
|
+
] }, idx)) });
|
|
125
|
+
}
|
|
126
|
+
function TagGrid({ color, tags }) {
|
|
127
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 mb-5", children: tags.map((tag) => /* @__PURE__ */ jsx(CK, { color, children: tag }, tag)) });
|
|
128
|
+
}
|
|
129
|
+
function StatusBadge({ value, badgeColor, label, children, even }) {
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
DLRow,
|
|
132
|
+
{
|
|
133
|
+
term: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
134
|
+
/* @__PURE__ */ jsx("span", { className: `inline-flex items-center justify-center w-5 h-5 rounded-full bg-${badgeColor}-500/20 text-${badgeColor}-400 text-[11px] font-bold shrink-0`, children: value }),
|
|
135
|
+
/* @__PURE__ */ jsx("span", { className: `text-${badgeColor}-400 font-semibold`, children: label })
|
|
136
|
+
] }),
|
|
137
|
+
even,
|
|
138
|
+
children
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function BulletGridRow({ color, term, children, even }) {
|
|
143
|
+
return /* @__PURE__ */ jsx(
|
|
144
|
+
DLRow,
|
|
145
|
+
{
|
|
146
|
+
term: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
147
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400`, style: { fontSize: "18px", lineHeight: "14px" }, children: "\u2022" }),
|
|
148
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400 font-semibold`, children: term })
|
|
149
|
+
] }),
|
|
150
|
+
even,
|
|
151
|
+
children
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
function NumberGridRow({ color, n, term, children, even }) {
|
|
156
|
+
return /* @__PURE__ */ jsx(
|
|
157
|
+
DLRow,
|
|
158
|
+
{
|
|
159
|
+
term: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
160
|
+
/* @__PURE__ */ jsxs("span", { className: `text-${color}-400 font-bold w-4 text-right shrink-0`, children: [
|
|
161
|
+
n,
|
|
162
|
+
"."
|
|
163
|
+
] }),
|
|
164
|
+
/* @__PURE__ */ jsx("span", { className: `text-${color}-400 font-semibold`, children: term })
|
|
165
|
+
] }),
|
|
166
|
+
even,
|
|
167
|
+
children
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
export {
|
|
172
|
+
BulletGridRow,
|
|
173
|
+
CK,
|
|
174
|
+
Callout,
|
|
175
|
+
CalloutCode,
|
|
176
|
+
CalloutDialog,
|
|
177
|
+
CalloutDim,
|
|
178
|
+
CodeBlock,
|
|
179
|
+
DL,
|
|
180
|
+
DLRow,
|
|
181
|
+
ExternalLink,
|
|
182
|
+
LI,
|
|
183
|
+
LocationItem,
|
|
184
|
+
LocationList,
|
|
185
|
+
NumberGridRow,
|
|
186
|
+
OL,
|
|
187
|
+
OLI,
|
|
188
|
+
P,
|
|
189
|
+
SectionHeader,
|
|
190
|
+
StatusBadge,
|
|
191
|
+
TagGrid,
|
|
192
|
+
TitledLI,
|
|
193
|
+
UL,
|
|
194
|
+
getCalloutColors
|
|
195
|
+
};
|