feat: migrate remaining atoms batch 3 - InfoBox through NumberInput (12 components)

This commit is contained in:
2026-01-21 01:58:10 +00:00
parent eb8a8689fb
commit a6a3ba2042
95 changed files with 2620 additions and 598 deletions

View File

@@ -2,7 +2,7 @@
"$schema": "./schemas/json-components-registry-schema.json",
"version": "2.0.0",
"description": "Registry of all components in the application",
"lastUpdated": "2026-01-18T13:03:47Z",
"lastUpdated": "2026-01-21T01:57:14.374Z",
"categories": {
"layout": "Layout and container components",
"input": "Form inputs and interactive controls",
@@ -3549,7 +3549,12 @@
"canHaveChildren": true,
"description": "TabIcon component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true,
"metadata": {
"conversionDate": "2026-01-21",
"autoGenerated": true
}
},
{
"type": "table",
@@ -3880,7 +3885,12 @@
"canHaveChildren": true,
"description": "TipsCard component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true,
"metadata": {
"conversionDate": "2026-01-21",
"autoGenerated": true
}
},
{
"type": "toggle",
@@ -4165,4 +4175,4 @@
"wrappers": 10
}
}
}
}

View File

@@ -1,41 +0,0 @@
import { cn } from '@/lib/utils'
import { Info, Warning, CheckCircle, XCircle } from '@phosphor-icons/react'
interface InfoBoxProps {
type?: 'info' | 'warning' | 'success' | 'error'
title?: string
children: React.ReactNode
className?: string
}
const iconMap = {
info: Info,
warning: Warning,
success: CheckCircle,
error: XCircle,
}
const variantClasses = {
info: 'bg-blue-500/10 border-blue-500/20 text-blue-700 dark:text-blue-300',
warning: 'bg-yellow-500/10 border-yellow-500/20 text-yellow-700 dark:text-yellow-300',
success: 'bg-green-500/10 border-green-500/20 text-green-700 dark:text-green-300',
error: 'bg-destructive/10 border-destructive/20 text-destructive',
}
export function InfoBox({ type = 'info', title, children, className }: InfoBoxProps) {
const Icon = iconMap[type]
return (
<div className={cn(
'flex gap-3 p-4 rounded-lg border',
variantClasses[type],
className
)}>
<Icon size={20} weight="fill" className="flex-shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
{title && <div className="font-semibold mb-1">{title}</div>}
<div className="text-sm opacity-90">{children}</div>
</div>
</div>
)
}

View File

@@ -1,34 +0,0 @@
import { cn } from '@/lib/utils'
interface KeyValueProps {
label: string
value: React.ReactNode
orientation?: 'horizontal' | 'vertical'
className?: string
labelClassName?: string
valueClassName?: string
}
export function KeyValue({
label,
value,
orientation = 'horizontal',
className,
labelClassName,
valueClassName
}: KeyValueProps) {
return (
<div className={cn(
'flex gap-2',
orientation === 'vertical' ? 'flex-col' : 'flex-row items-center justify-between',
className
)}>
<span className={cn('text-sm text-muted-foreground', labelClassName)}>
{label}
</span>
<span className={cn('text-sm font-medium', valueClassName)}>
{value}
</span>
</div>
)
}

View File

@@ -1,24 +0,0 @@
import { ReactNode } from 'react'
import { cn } from '@/lib/utils'
interface LabelProps {
children: ReactNode
htmlFor?: string
required?: boolean
className?: string
}
export function Label({ children, htmlFor, required, className }: LabelProps) {
return (
<label
htmlFor={htmlFor}
className={cn(
'text-sm font-medium text-foreground leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
className
)}
>
{children}
{required && <span className="text-destructive ml-1">*</span>}
</label>
)
}

View File

@@ -1,35 +0,0 @@
import { ReactNode } from 'react'
interface ListProps<T> {
items: T[]
renderItem: (item: T, index: number) => ReactNode
emptyMessage?: string
className?: string
itemClassName?: string
}
export function List<T>({
items,
renderItem,
emptyMessage = 'No items to display',
className = '',
itemClassName = ''
}: ListProps<T>) {
if (items.length === 0) {
return (
<div className="text-center text-muted-foreground py-8">
{emptyMessage}
</div>
)
}
return (
<div className={className}>
{items.map((item, index) => (
<div key={index} className={itemClassName}>
{renderItem(item, index)}
</div>
))}
</div>
)
}

View File

@@ -1,32 +0,0 @@
import { cn } from '@/lib/utils'
interface ListItemProps {
icon?: React.ReactNode
children: React.ReactNode
onClick?: () => void
active?: boolean
className?: string
endContent?: React.ReactNode
}
export function ListItem({ icon, children, onClick, active, className, endContent }: ListItemProps) {
const isInteractive = !!onClick
return (
<div
className={cn(
'flex items-center gap-3 px-3 py-2 rounded-md transition-colors',
isInteractive && 'cursor-pointer hover:bg-accent',
active && 'bg-accent',
className
)}
onClick={onClick}
role={isInteractive ? 'button' : undefined}
tabIndex={isInteractive ? 0 : undefined}
>
{icon && <div className="flex-shrink-0 text-muted-foreground">{icon}</div>}
<div className="flex-1 min-w-0 text-sm">{children}</div>
{endContent && <div className="flex-shrink-0">{endContent}</div>}
</div>
)
}

View File

@@ -1,49 +0,0 @@
import { cn } from '@/lib/utils'
interface LiveIndicatorProps {
label?: string
showLabel?: boolean
size?: 'sm' | 'md' | 'lg'
className?: string
}
export function LiveIndicator({
label = 'LIVE',
showLabel = true,
size = 'md',
className,
}: LiveIndicatorProps) {
const sizeClasses = {
sm: 'text-xs gap-1.5',
md: 'text-sm gap-2',
lg: 'text-base gap-2.5',
}
const dotSizeClasses = {
sm: 'w-2 h-2',
md: 'w-2.5 h-2.5',
lg: 'w-3 h-3',
}
return (
<div className={cn('inline-flex items-center font-medium', sizeClasses[size], className)}>
<span className="relative flex">
<span
className={cn(
'absolute inline-flex rounded-full bg-red-500 opacity-75 animate-ping',
dotSizeClasses[size]
)}
/>
<span
className={cn(
'relative inline-flex rounded-full bg-red-500',
dotSizeClasses[size]
)}
/>
</span>
{showLabel && (
<span className="text-red-500 font-bold tracking-wider">{label}</span>
)}
</div>
)
}

View File

@@ -1,20 +0,0 @@
interface LoadingSpinnerProps {
size?: 'sm' | 'md' | 'lg'
className?: string
}
export function LoadingSpinner({ size = 'md', className = '' }: LoadingSpinnerProps) {
const sizeClasses = {
sm: 'w-4 h-4 border-2',
md: 'w-6 h-6 border-2',
lg: 'w-8 h-8 border-3',
}
return (
<div
className={`inline-block ${sizeClasses[size]} border-primary border-t-transparent rounded-full animate-spin ${className}`}
role="status"
aria-label="Loading"
/>
)
}

View File

@@ -1,31 +0,0 @@
import { cn } from '@/lib/utils'
export interface LoadingStateProps {
message?: string
size?: 'sm' | 'md' | 'lg'
className?: string
}
export function LoadingState({
message = 'Loading...',
size = 'md',
className
}: LoadingStateProps) {
const sizeClasses = {
sm: 'w-4 h-4 border-2',
md: 'w-8 h-8 border-3',
lg: 'w-12 h-12 border-4',
}
return (
<div className={cn('flex flex-col items-center justify-center gap-3 py-8', className)}>
<div className={cn(
'border-primary border-t-transparent rounded-full animate-spin',
sizeClasses[size]
)} />
{message && (
<p className="text-sm text-muted-foreground">{message}</p>
)}
</div>
)
}

View File

@@ -1,52 +0,0 @@
import { cn } from '@/lib/utils'
import { TrendUp, TrendDown } from '@phosphor-icons/react'
interface MetricDisplayProps {
label: string
value: string | number
trend?: {
value: number
direction: 'up' | 'down'
}
icon?: React.ReactNode
className?: string
variant?: 'default' | 'primary' | 'accent'
}
export function MetricDisplay({
label,
value,
trend,
icon,
className,
variant = 'default'
}: MetricDisplayProps) {
const variantClasses = {
default: 'text-foreground',
primary: 'text-primary',
accent: 'text-accent',
}
return (
<div className={cn('flex flex-col gap-1', className)}>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
{icon && <span className="text-muted-foreground">{icon}</span>}
{label}
</div>
<div className="flex items-baseline gap-2">
<span className={cn('text-2xl font-bold', variantClasses[variant])}>
{value}
</span>
{trend && (
<span className={cn(
'flex items-center gap-0.5 text-xs font-medium',
trend.direction === 'up' ? 'text-green-600 dark:text-green-400' : 'text-destructive'
)}>
{trend.direction === 'up' ? <TrendUp size={14} /> : <TrendDown size={14} />}
{Math.abs(trend.value)}%
</span>
)}
</div>
</div>
)
}

View File

@@ -1,64 +0,0 @@
import { X } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
interface ModalProps {
isOpen: boolean
onClose: () => void
title?: string
children: React.ReactNode
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
showCloseButton?: boolean
className?: string
}
export function Modal({
isOpen,
onClose,
title,
children,
size = 'md',
showCloseButton = true,
className,
}: ModalProps) {
if (!isOpen) return null
const sizeStyles = {
sm: 'max-w-sm',
md: 'max-w-md',
lg: 'max-w-lg',
xl: 'max-w-xl',
full: 'max-w-full m-4',
}
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm animate-in fade-in-0"
onClick={onClose}
>
<div
className={cn(
'relative w-full bg-card border border-border rounded-lg shadow-lg animate-in zoom-in-95',
sizeStyles[size],
className
)}
onClick={(e) => e.stopPropagation()}
>
{(title || showCloseButton) && (
<div className="flex items-center justify-between p-6 border-b border-border">
{title && <h2 className="text-lg font-semibold">{title}</h2>}
{showCloseButton && (
<button
onClick={onClose}
className="ml-auto p-1 rounded-md hover:bg-accent transition-colors"
aria-label="Close modal"
>
<X className="w-5 h-5" />
</button>
)}
</div>
)}
<div className="p-6">{children}</div>
</div>
</div>
)
}

View File

@@ -1,67 +0,0 @@
import { Info, CheckCircle, Warning, XCircle } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
interface NotificationProps {
type: 'info' | 'success' | 'warning' | 'error'
title: string
message?: string
onClose?: () => void
className?: string
}
export function Notification({ type, title, message, onClose, className }: NotificationProps) {
const config = {
info: {
icon: Info,
color: 'text-blue-500',
bg: 'bg-blue-500/10',
border: 'border-blue-500/20',
},
success: {
icon: CheckCircle,
color: 'text-accent',
bg: 'bg-accent/10',
border: 'border-accent/20',
},
warning: {
icon: Warning,
color: 'text-yellow-500',
bg: 'bg-yellow-500/10',
border: 'border-yellow-500/20',
},
error: {
icon: XCircle,
color: 'text-destructive',
bg: 'bg-destructive/10',
border: 'border-destructive/20',
},
}
const { icon: Icon, color, bg, border } = config[type]
return (
<div
className={cn(
'flex gap-3 p-4 rounded-lg border',
bg,
border,
className
)}
>
<Icon className={cn('w-5 h-5 flex-shrink-0', color)} weight="fill" />
<div className="flex-1 min-w-0">
<h4 className="font-medium text-sm">{title}</h4>
{message && <p className="text-sm text-muted-foreground mt-1">{message}</p>}
</div>
{onClose && (
<button
onClick={onClose}
className="flex-shrink-0 text-muted-foreground hover:text-foreground transition-colors"
aria-label="Close notification"
>
<XCircle className="w-4 h-4" />
</button>
)}
</div>
)
}

View File

@@ -1,89 +0,0 @@
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Minus, Plus } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
interface NumberInputProps {
value: number
onChange: (value: number) => void
min?: number
max?: number
step?: number
label?: string
disabled?: boolean
className?: string
}
export function NumberInput({
value,
onChange,
min,
max,
step = 1,
label,
disabled,
className,
}: NumberInputProps) {
const handleIncrement = () => {
const newValue = value + step
if (max === undefined || newValue <= max) {
onChange(newValue)
}
}
const handleDecrement = () => {
const newValue = value - step
if (min === undefined || newValue >= min) {
onChange(newValue)
}
}
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = parseFloat(e.target.value)
if (!isNaN(newValue)) {
if ((min === undefined || newValue >= min) && (max === undefined || newValue <= max)) {
onChange(newValue)
}
}
}
return (
<div className={cn('flex flex-col gap-2', className)}>
{label && (
<label className="text-sm font-medium text-foreground">{label}</label>
)}
<div className="flex items-center gap-2">
<Button
type="button"
variant="outline"
size="icon"
onClick={handleDecrement}
disabled={disabled || (min !== undefined && value <= min)}
className="h-9 w-9 shrink-0"
>
<Minus />
</Button>
<Input
type="number"
value={value}
onChange={handleInputChange}
min={min}
max={max}
step={step}
disabled={disabled}
className="text-center"
/>
<Button
type="button"
variant="outline"
size="icon"
onClick={handleIncrement}
disabled={disabled || (max !== undefined && value >= max)}
className="h-9 w-9 shrink-0"
>
<Plus />
</Button>
</div>
</div>
)
}

View File

@@ -1,16 +0,0 @@
interface TabIconProps {
icon: React.ReactNode
variant?: 'default' | 'gradient'
}
export function TabIcon({ icon, variant = 'default' }: TabIconProps) {
if (variant === 'gradient') {
return (
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-primary/20 to-accent/20 flex items-center justify-center text-primary shrink-0">
{icon}
</div>
)
}
return <>{icon}</>
}

View File

@@ -1,28 +0,0 @@
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Warning } from '@phosphor-icons/react'
interface TipsCardProps {
tips: Array<{ message: string; show: boolean }>
}
export function TipsCard({ tips }: TipsCardProps) {
const visibleTips = tips.filter(tip => tip.show)
if (visibleTips.length === 0) return null
return (
<Card className="bg-yellow-500/10 border-yellow-500/20">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Warning size={24} weight="duotone" className="text-yellow-500" />
Quick Tips
</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm">
{visibleTips.map((tip, index) => (
<p key={index}> {tip.message}</p>
))}
</CardContent>
</Card>
)
}

View File

@@ -1,4 +1,7 @@
// Auto-generated exports - DO NOT EDIT MANUALLY
// JSON-based atom imports
export { InfoBox, KeyValue, Label, List, ListItem, LiveIndicator, LoadingSpinner, LoadingState, MetricDisplay, Modal, Notification, NumberInput } from '@/lib/json-ui/json-components'
export { ActionButton } from './ActionButton'
export { ActionCard } from './ActionCard'
export { ActionIcon } from './ActionIcon'
@@ -49,22 +52,10 @@ export { HoverCard } from './HoverCard'
export { IconButton } from './IconButton'
export { IconText } from './IconText'
export { IconWrapper } from './IconWrapper'
export { InfoBox } from './InfoBox'
export { InfoPanel } from './InfoPanel'
export { Kbd } from './Kbd'
export { KeyValue } from './KeyValue'
export { Label } from './Label'
export { Link } from './Link'
export { List } from './List'
export { ListItem } from './ListItem'
export { LiveIndicator } from './LiveIndicator'
export { LoadingSpinner } from './LoadingSpinner'
export { LoadingState } from './LoadingState'
export { MetricCard } from './MetricCard'
export { MetricDisplay } from './MetricDisplay'
export { Modal } from './Modal'
export { Notification } from './Notification'
export { NumberInput } from './NumberInput'
export { BasicPageHeader, BasicPageHeader as PageHeader } from './PageHeader'
export { PanelHeader } from './PanelHeader'
export { ProgressBar } from './ProgressBar'

View File

@@ -0,0 +1,74 @@
{
"id": "binding-indicator-root",
"type": "TooltipProvider",
"children": [
{
"id": "binding-indicator-tooltip",
"type": "Tooltip",
"children": [
{
"id": "binding-indicator-trigger",
"type": "TooltipTrigger",
"props": {
"asChild": true
},
"children": [
{
"id": "binding-indicator-content",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "(() => { const path = $props.path; const sourceId = $props.sourceId; const baseClass = 'inline-flex items-center gap-1 px-2 py-1 rounded text-xs bg-accent/10 text-accent border border-accent/30'; return baseClass + ' ' + (data || ''); })()"
}
},
"children": [
{
"id": "binding-indicator-icon",
"type": "Icon",
"props": {
"name": "Link",
"weight": "bold",
"className": "w-3 h-3"
}
},
{
"id": "binding-indicator-text",
"type": "span",
"props": {
"className": "font-mono"
},
"bindings": {
"children": {
"source": "sourceId",
"transform": "(() => { const path = $props.path; return path ? $props.sourceId + '.' + path : $props.sourceId; })()"
}
}
}
]
}
]
},
{
"id": "binding-indicator-tooltip-content",
"type": "TooltipContent",
"children": [
{
"id": "binding-indicator-tooltip-text",
"type": "p",
"props": {
"className": "text-xs"
},
"bindings": {
"children": {
"source": "sourceId",
"transform": "(() => { const path = $props.path; const bindingText = path ? $props.sourceId + '.' + path : $props.sourceId; return 'Bound to: ' + bindingText; })()"
}
}
}
]
}
]
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "button-group-root",
"type": "div",
"bindings": {
"className": {
"source": "orientation",
"transform": "(() => { const orientation = data || 'horizontal'; const baseClasses = 'inline-flex [&>button]:rounded-none [&>button:not(:last-child)]:border-r-0'; const directionClasses = orientation === 'horizontal' ? 'flex-row [&>button:first-child]:rounded-l-md [&>button:last-child]:rounded-r-md' : 'flex-col [&>button:first-child]:rounded-t-md [&>button:first-child]:rounded-l-none [&>button:last-child]:rounded-b-md [&>button:last-child]:rounded-r-none [&>button:not(:last-child)]:border-b-0 [&>button:not(:last-child)]:border-r'; const userClass = $props.className || ''; return baseClasses + ' ' + directionClasses + ' ' + userClass; })()"
}
},
"children": [
{
"id": "button-group-content",
"bindings": {
"children": "children"
}
}
]
}

View File

@@ -0,0 +1,49 @@
{
"id": "chip-root",
"type": "span",
"bindings": {
"className": {
"source": "variant",
"transform": "(() => { const variant = data || 'default'; const variantMap = { default: 'bg-secondary text-secondary-foreground', primary: 'bg-primary text-primary-foreground', accent: 'bg-accent text-accent-foreground', muted: 'bg-muted text-muted-foreground' }; const variantClass = variantMap[variant] || variantMap.default; const size = $props.size || 'md'; const sizeMap = { sm: 'px-2 py-0.5 text-xs', md: 'px-3 py-1 text-sm' }; const sizeClass = sizeMap[size] || sizeMap.md; const userClass = $props.className || ''; return 'inline-flex items-center gap-1 rounded-full font-medium ' + variantClass + ' ' + sizeClass + ' ' + userClass; })()"
}
},
"children": [
{
"id": "chip-content",
"bindings": {
"children": "children"
}
},
{
"id": "chip-remove-button",
"type": "button",
"props": {
"type": "button",
"className": "inline-flex items-center justify-center hover:bg-black/10 rounded-full transition-colors",
"aria-label": "Remove"
},
"bindings": {
"onClick": "onRemove"
},
"conditional": {
"if": "onRemove"
},
"children": [
{
"id": "chip-remove-icon",
"type": "Icon",
"bindings": {
"name": "X",
"props": {
"weight": "bold",
"className": {
"source": "size",
"transform": "data === 'sm' ? 'w-3 h-3' : 'w-3.5 h-3.5'"
}
}
}
}
]
}
]
}

View File

@@ -0,0 +1,111 @@
{
"id": "circular-progress-root",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "(() => { const userClass = data || ''; return 'relative inline-flex items-center justify-center ' + userClass; })()"
}
},
"children": [
{
"id": "circular-progress-svg",
"type": "svg",
"bindings": {
"width": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 48, md: 64, lg: 96, xl: 128 }; return sizeMap[data || 'md']; })()"
},
"height": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 48, md: 64, lg: 96, xl: 128 }; return sizeMap[data || 'md']; })()"
}
},
"props": {
"className": "transform -rotate-90"
},
"children": [
{
"id": "circular-progress-background-circle",
"type": "circle",
"bindings": {
"cx": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 24, md: 32, lg: 48, xl: 64 }; return sizeMap[data || 'md']; })()"
},
"cy": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 24, md: 32, lg: 48, xl: 64 }; return sizeMap[data || 'md']; })()"
},
"r": {
"source": "size",
"transform": "(() => { const strokeWidth = $props.strokeWidth; const sizeMap = { sm: { dim: 48, stroke: 4 }, md: { dim: 64, stroke: 5 }, lg: { dim: 96, stroke: 6 }, xl: { dim: 128, stroke: 8 } }; const size = sizeMap[data || 'md']; const actualStroke = strokeWidth || size.stroke; return (size.dim - actualStroke) / 2; })()"
},
"strokeWidth": {
"source": "size",
"transform": "(() => { const strokeWidth = $props.strokeWidth; const sizeMap = { sm: 4, md: 5, lg: 6, xl: 8 }; return strokeWidth || sizeMap[data || 'md']; })()"
}
},
"props": {
"stroke": "currentColor",
"fill": "none",
"className": "text-muted opacity-20"
}
},
{
"id": "circular-progress-active-circle",
"type": "circle",
"bindings": {
"cx": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 24, md: 32, lg: 48, xl: 64 }; return sizeMap[data || 'md']; })()"
},
"cy": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 24, md: 32, lg: 48, xl: 64 }; return sizeMap[data || 'md']; })()"
},
"r": {
"source": "size",
"transform": "(() => { const strokeWidth = $props.strokeWidth; const sizeMap = { sm: { dim: 48, stroke: 4 }, md: { dim: 64, stroke: 5 }, lg: { dim: 96, stroke: 6 }, xl: { dim: 128, stroke: 8 } }; const size = sizeMap[data || 'md']; const actualStroke = strokeWidth || size.stroke; return (size.dim - actualStroke) / 2; })()"
},
"strokeWidth": {
"source": "size",
"transform": "(() => { const strokeWidth = $props.strokeWidth; const sizeMap = { sm: 4, md: 5, lg: 6, xl: 8 }; return strokeWidth || sizeMap[data || 'md']; })()"
},
"strokeDasharray": {
"source": "size",
"transform": "(() => { const strokeWidth = $props.strokeWidth; const sizeMap = { sm: { dim: 48, stroke: 4 }, md: { dim: 64, stroke: 5 }, lg: { dim: 96, stroke: 6 }, xl: { dim: 128, stroke: 8 } }; const size = sizeMap[data || 'md']; const actualStroke = strokeWidth || size.stroke; const radius = (size.dim - actualStroke) / 2; return radius * 2 * Math.PI; })()"
},
"strokeDashoffset": {
"source": "value",
"transform": "(() => { const value = data; const max = $props.max || 100; const percentage = Math.min((value / max) * 100, 100); const strokeWidth = $props.strokeWidth; const sizeMap = { sm: { dim: 48, stroke: 4 }, md: { dim: 64, stroke: 5 }, lg: { dim: 96, stroke: 6 }, xl: { dim: 128, stroke: 8 } }; const size = sizeMap[$props.size || 'md']; const actualStroke = strokeWidth || size.stroke; const radius = (size.dim - actualStroke) / 2; const circumference = radius * 2 * Math.PI; return circumference - (percentage / 100) * circumference; })()"
}
},
"props": {
"stroke": "currentColor",
"fill": "none",
"strokeLinecap": "round",
"className": "text-primary transition-all duration-300"
}
}
]
},
{
"id": "circular-progress-label",
"type": "span",
"bindings": {
"children": {
"source": "value",
"transform": "(() => { const value = data; const max = $props.max || 100; const percentage = Math.min((value / max) * 100, 100); return Math.round(percentage) + '%'; })()"
},
"className": {
"source": "size",
"transform": "(() => { const sizeMap = { sm: 'text-xs', md: 'text-sm', lg: 'text-base', xl: 'text-lg' }; return 'absolute font-semibold ' + (sizeMap[data || 'md'] || sizeMap.md); })()"
}
},
"conditional": {
"if": "showLabel"
}
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "code-root",
"type": "code",
"bindings": {
"className": {
"source": "inline",
"transform": "(() => { if (data === false) { return 'p-4 rounded-lg bg-muted text-foreground font-mono text-sm overflow-x-auto'; } return 'px-1.5 py-0.5 rounded bg-muted text-foreground font-mono text-sm ' + ($props.className || ''); })()"
}
},
"children": [
{
"id": "code-content",
"bindings": {
"children": "children"
}
}
]
}

View File

@@ -0,0 +1,85 @@
{
"id": "command-palette-root",
"type": "CommandDialog",
"bindings": {
"open": "open",
"onOpenChange": "onOpenChange"
},
"children": [
{
"id": "command-palette-input",
"type": "CommandInput",
"bindings": {
"placeholder": "placeholder"
}
},
{
"id": "command-palette-list",
"type": "CommandList",
"children": [
{
"id": "command-palette-empty",
"type": "CommandEmpty",
"bindings": {
"children": "emptyMessage"
}
},
{
"id": "command-palette-groups",
"type": "forEach",
"bindings": {
"items": "groups",
"children": {
"id": "command-palette-group",
"type": "CommandGroup",
"bindings": {
"heading": "heading"
},
"children": [
{
"id": "command-palette-items",
"type": "forEach",
"bindings": {
"items": "items",
"children": {
"id": "command-palette-item",
"type": "CommandItem",
"bindings": {
"value": "value",
"onSelect": {
"transform": "(() => { return () => { data.onSelect?.(); $props.onOpenChange(false); }; })()"
}
},
"children": [
{
"id": "command-palette-item-icon",
"type": "span",
"props": {
"className": "mr-2"
},
"bindings": {
"children": "icon"
},
"conditional": {
"if": "icon"
}
},
{
"id": "command-palette-item-label",
"type": "span",
"bindings": {
"children": "label"
}
}
]
}
}
}
]
}
}
}
]
}
]
}

View File

@@ -0,0 +1,118 @@
{
"id": "completion-card-root",
"type": "Card",
"props": {
"className": "bg-gradient-to-br from-primary/10 to-accent/10 border-primary/20"
},
"children": [
{
"id": "completion-card-header",
"type": "CardHeader",
"children": [
{
"id": "completion-card-title",
"type": "CardTitle",
"props": {
"className": "flex items-center gap-2"
},
"children": [
{
"id": "completion-card-icon",
"type": "Icon",
"props": {
"name": "CheckCircle",
"weight": "duotone",
"className": "text-primary w-6 h-6"
}
},
{
"id": "completion-card-title-text",
"type": "span",
"props": {},
"children": [
"Project Completeness"
]
}
]
},
{
"id": "completion-card-description",
"type": "CardDescription",
"children": [
"Overall progress of your application"
]
}
]
},
{
"id": "completion-card-content",
"type": "CardContent",
"props": {
"className": "space-y-4"
},
"children": [
{
"id": "completion-card-score-row",
"type": "div",
"props": {
"className": "flex items-center justify-between"
},
"children": [
{
"id": "completion-card-score",
"type": "span",
"props": {
"className": "text-4xl font-bold"
},
"bindings": {
"children": "completionScore"
}
},
{
"id": "completion-card-badge",
"type": "Badge",
"bindings": {
"variant": {
"source": "isReadyToExport",
"transform": "data ? 'default' : 'secondary'"
},
"className": "text-sm"
},
"children": [
{
"id": "completion-card-badge-text",
"bindings": {
"children": {
"source": "isReadyToExport",
"transform": "data ? 'Ready to Export' : 'In Progress'"
}
}
}
]
}
]
},
{
"id": "completion-card-progress",
"type": "Progress",
"bindings": {
"value": "completionScore"
},
"props": {
"className": "h-3"
}
},
{
"id": "completion-card-message",
"type": "p",
"props": {
"className": "text-sm text-muted-foreground"
},
"bindings": {
"children": "completionMessage"
}
}
]
}
]
}

View File

@@ -0,0 +1,55 @@
{
"id": "component-palette-item-root",
"type": "Card",
"props": {
"draggable": true
},
"bindings": {
"onDragStart": {
"transform": "(() => { return (e) => $props.onDragStart($props.component, e); })()"
},
"className": {
"source": "className",
"transform": "(() => { const userClass = data || ''; return 'p-3 cursor-move hover:bg-accent/50 hover:border-accent transition-all flex flex-col items-center gap-2 text-center hover:scale-105 active:scale-95 ' + userClass; })()"
}
},
"children": [
{
"id": "component-palette-item-icon",
"type": "Icon",
"bindings": {
"name": {
"transform": "(() => { const iconMap = {}; const componentIcon = $props.component?.icon || 'Cube'; return componentIcon; })()"
}
},
"props": {
"weight": "duotone",
"className": "w-6 h-6 text-primary"
}
},
{
"id": "component-palette-item-label",
"type": "span",
"props": {
"className": "text-xs font-medium text-foreground"
},
"bindings": {
"children": {
"transform": "$props.component?.label || 'Component'"
}
}
},
{
"id": "component-palette-item-type",
"type": "span",
"props": {
"className": "text-[10px] text-muted-foreground"
},
"bindings": {
"children": {
"transform": "$props.component?.type || 'unknown'"
}
}
}
]
}

View File

@@ -0,0 +1,22 @@
{
"id": "confirm-button-root",
"type": "Button",
"bindings": {
"onClick": {
"transform": "(() => { return async () => { if (window.confirm($props.confirmText || 'Are you sure?')) { await $props.onConfirm(); } }; })()"
},
"disabled": "isLoading",
"className": "className"
},
"children": [
{
"id": "confirm-button-content",
"bindings": {
"children": {
"source": "isLoading",
"transform": "data ? 'Loading...' : $props.children"
}
}
}
]
}

View File

@@ -0,0 +1,37 @@
{
"id": "data-source-badge-root",
"type": "Badge",
"bindings": {
"variant": "outline",
"className": {
"source": "type",
"transform": "(() => { const typeMap = { kv: 'flex items-center gap-1 bg-accent/20 text-accent border-accent/30', static: 'flex items-center gap-1 bg-muted text-muted-foreground border-border' }; return (typeMap[data] || typeMap.static) + ' ' + ($props.className || ''); })()"
}
},
"children": [
{
"id": "data-source-badge-icon",
"type": "Icon",
"bindings": {
"name": {
"source": "type",
"transform": "data === 'kv' ? 'Database' : 'File'"
}
},
"props": {
"weight": "bold",
"className": "w-3 h-3"
}
},
{
"id": "data-source-badge-text",
"type": "span",
"bindings": {
"children": {
"source": "type",
"transform": "data === 'kv' ? 'KV Storage' : 'Static'"
}
}
}
]
}

View File

@@ -0,0 +1,96 @@
{
"id": "date-picker-wrapper",
"type": "Popover",
"children": [
{
"id": "date-picker-trigger",
"type": "PopoverTrigger",
"bindings": {
"asChild": {
"source": null,
"transform": "true"
}
},
"children": [
{
"id": "date-picker-button",
"type": "Button",
"bindings": {
"variant": {
"source": null,
"transform": "'outline'"
},
"disabled": {
"source": "disabled",
"transform": "data"
},
"className": {
"source": ["value", "className"],
"transform": "const value = data[0]; const className = data[1] || ''; const baseClasses = 'w-full justify-start text-left font-normal'; const valueClass = !value ? 'text-muted-foreground' : ''; return `${baseClasses} ${valueClass} ${className}`.trim()"
},
"children": [
{
"id": "date-picker-icon",
"type": "CalendarBlank",
"bindings": {
"className": {
"source": null,
"transform": "'mr-2'"
},
"size": {
"source": null,
"transform": "16"
}
}
},
{
"id": "date-picker-label",
"type": "span",
"bindings": {
"children": {
"source": ["value", "placeholder"],
"transform": "const value = data[0]; const placeholder = data[1] || 'Pick a date'; return value ? new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' }).format(value) : placeholder"
}
}
}
]
}
}
]
},
{
"id": "date-picker-content",
"type": "PopoverContent",
"bindings": {
"className": {
"source": null,
"transform": "'w-auto p-0'"
},
"align": {
"source": null,
"transform": "'start'"
}
},
"children": [
{
"id": "date-picker-calendar",
"type": "Calendar",
"bindings": {
"mode": {
"source": null,
"transform": "'single'"
},
"selected": {
"source": "value",
"transform": "data"
},
"onSelect": {
"source": "onChange",
"transform": "data"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,66 @@
{
"id": "detail-row-container",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center justify-between py-2 border-b border-border last:border-0'"
}
},
"children": [
{
"id": "detail-row-left",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center gap-2'"
}
},
"children": [
{
"id": "detail-row-icon",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-muted-foreground'"
},
"children": {
"source": "icon",
"transform": "data"
}
}
},
{
"id": "detail-row-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm font-medium'"
},
"children": {
"source": "label",
"transform": "data"
}
}
}
]
},
{
"id": "detail-row-badge",
"type": "Badge",
"bindings": {
"variant": {
"source": null,
"transform": "'secondary'"
},
"children": {
"source": "value",
"transform": "data"
}
}
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "divider",
"type": "div",
"bindings": {
"role": {
"source": "decorative",
"transform": "data ? 'presentation' : 'separator'"
},
"aria-orientation": {
"source": "orientation",
"transform": "data || 'horizontal'"
},
"className": {
"source": ["orientation", "className"],
"transform": "const orientation = data[0] || 'horizontal'; const className = data[1] || ''; const baseClass = 'bg-border'; const sizeClass = orientation === 'horizontal' ? 'h-[1px] w-full' : 'w-[1px] h-full'; return `${baseClass} ${sizeClass} ${className}`.trim()"
}
}
}

View File

@@ -0,0 +1,84 @@
{
"id": "empty-message-container",
"type": "div",
"bindings": {
"className": {
"source": ["className"],
"transform": "const className = data[0] || ''; const baseClasses = 'flex flex-col items-center justify-center text-center p-8 rounded-lg border border-dashed bg-muted/20'; return `${baseClasses} ${className}`.trim()"
}
},
"children": [
{
"id": "empty-message-icon",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'mb-4 text-muted-foreground/50'"
},
"children": {
"source": "icon",
"transform": "data"
},
"_if": {
"source": "icon",
"transform": "!!data"
}
}
},
{
"id": "empty-message-title",
"type": "h3",
"bindings": {
"className": {
"source": null,
"transform": "'text-lg font-semibold mb-2'"
},
"children": {
"source": "title",
"transform": "data"
}
}
},
{
"id": "empty-message-description",
"type": "p",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm text-muted-foreground mb-4 max-w-sm'"
},
"children": {
"source": "description",
"transform": "data"
},
"_if": {
"source": "description",
"transform": "!!data"
}
}
},
{
"id": "empty-message-button",
"type": "Button",
"bindings": {
"size": {
"source": null,
"transform": "'sm'"
},
"onClick": {
"source": "action",
"transform": "data ? data.onClick : null"
},
"children": {
"source": "action",
"transform": "data ? data.label : null"
},
"_if": {
"source": "action",
"transform": "!!data"
}
}
}
]
}

View File

@@ -0,0 +1,22 @@
{
"id": "error-badge",
"type": "Badge",
"bindings": {
"variant": {
"source": "variant",
"transform": "data || 'destructive'"
},
"className": {
"source": ["count", "size"],
"transform": "const count = data[0]; const size = data[1] || 'md'; const sizeClasses = { sm: 'h-5 w-5 text-[10px]', md: 'h-6 w-6 text-xs' }; return `${sizeClasses[size]} p-0 flex items-center justify-center absolute -top-1 -right-1`"
},
"children": {
"source": "count",
"transform": "data"
},
"_if": {
"source": "count",
"transform": "data !== 0"
}
}
}

View File

@@ -0,0 +1,22 @@
{
"id": "file-icon",
"type": "FileIconWrapper",
"bindings": {
"type": {
"source": "type",
"transform": "data || 'code'"
},
"size": {
"source": "size",
"transform": "data || 20"
},
"weight": {
"source": "weight",
"transform": "data || 'regular'"
},
"className": {
"source": "className",
"transform": "data || ''"
}
}
}

View File

@@ -0,0 +1,18 @@
{
"id": "glow-card",
"type": "Card",
"bindings": {
"onClick": {
"source": "onClick",
"transform": "data"
},
"className": {
"source": ["glowColor", "intensity", "className", "onClick"],
"transform": "const glowColor = data[0] || 'primary'; const intensity = data[1] || 'medium'; const className = data[2] || ''; const hasClick = data[3]; const glowClasses = { primary: { low: 'shadow-primary/10', medium: 'shadow-primary/20 hover:shadow-primary/30', high: 'shadow-primary/30 hover:shadow-primary/50' }, accent: { low: 'shadow-accent/10', medium: 'shadow-accent/20 hover:shadow-accent/30', high: 'shadow-accent/30 hover:shadow-accent/50' }, success: { low: 'shadow-green-500/10', medium: 'shadow-green-500/20 hover:shadow-green-500/30', high: 'shadow-green-500/30 hover:shadow-green-500/50' }, warning: { low: 'shadow-yellow-500/10', medium: 'shadow-yellow-500/20 hover:shadow-yellow-500/30', high: 'shadow-yellow-500/30 hover:shadow-yellow-500/50' }, error: { low: 'shadow-red-500/10', medium: 'shadow-red-500/20 hover:shadow-red-500/30', high: 'shadow-red-500/30 hover:shadow-red-500/50' } }; const baseClasses = 'transition-all duration-300 shadow-lg'; const glow = glowClasses[glowColor][intensity]; const clickClass = hasClick ? 'cursor-pointer hover:scale-[1.02]' : ''; return `${baseClasses} ${glow} ${clickClass} ${className}`.trim()"
}
},
"children": {
"source": "children",
"transform": "data"
}
}

View File

@@ -0,0 +1,14 @@
{
"id": "helper-text",
"type": "p",
"bindings": {
"className": {
"source": ["variant", "className"],
"transform": "const variant = data[0] || 'default'; const className = data[1] || ''; const baseClass = 'text-xs mt-1'; const variantClasses = { default: 'text-muted-foreground', error: 'text-destructive', success: 'text-green-600' }; return `${baseClass} ${variantClasses[variant]} ${className}`.trim()"
},
"children": {
"source": "children",
"transform": "data"
}
}
}

View File

@@ -0,0 +1,70 @@
{
"id": "info-box-container",
"type": "div",
"bindings": {
"className": {
"source": ["type", "className"],
"transform": "const type = data[0] || 'info'; const customClass = data[1] || ''; const variantClasses = { info: 'bg-blue-500/10 border-blue-500/20 text-blue-700 dark:text-blue-300', warning: 'bg-yellow-500/10 border-yellow-500/20 text-yellow-700 dark:text-yellow-300', success: 'bg-green-500/10 border-green-500/20 text-green-700 dark:text-green-300', error: 'bg-destructive/10 border-destructive/20 text-destructive' }; return `flex gap-3 p-4 rounded-lg border ${variantClasses[type]} ${customClass}`.trim()"
}
},
"children": [
{
"id": "info-box-icon",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-shrink-0 mt-0.5'"
},
"children": {
"source": "type",
"transform": "const type = data || 'info'; const icons = { info: '<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\"></path></svg>', warning: '<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\"></path></svg>', success: '<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\"></path></svg>', error: '<svg class=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\"></path></svg>' }; return icons[type] || icons.info"
}
}
},
{
"id": "info-box-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-1 min-w-0'"
}
},
"children": [
{
"id": "info-box-title",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'font-semibold mb-1'"
},
"children": {
"source": "title",
"transform": "data"
},
"_if": {
"source": "title",
"transform": "!!data"
}
}
},
{
"id": "info-box-children",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm opacity-90'"
},
"children": {
"source": "children",
"transform": "data"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,40 @@
{
"id": "key-value-container",
"type": "div",
"bindings": {
"className": {
"source": ["orientation", "className"],
"transform": "const orientation = data[0] || 'horizontal'; const customClass = data[1] || ''; const orientationClass = orientation === 'vertical' ? 'flex-col' : 'flex-row items-center justify-between'; return `flex gap-2 ${orientationClass} ${customClass}`.trim()"
}
},
"children": [
{
"id": "key-value-label",
"type": "span",
"bindings": {
"className": {
"source": "labelClassName",
"transform": "const customClass = data || ''; return `text-sm text-muted-foreground ${customClass}`.trim()"
},
"children": {
"source": "label",
"transform": "data"
}
}
},
{
"id": "key-value-value",
"type": "span",
"bindings": {
"className": {
"source": "valueClassName",
"transform": "const customClass = data || ''; return `text-sm font-medium ${customClass}`.trim()"
},
"children": {
"source": "value",
"transform": "data"
}
}
}
]
}

View File

@@ -0,0 +1,74 @@
{
"id": "list-item-container",
"type": "div",
"bindings": {
"className": {
"source": ["onClick", "active", "className"],
"transform": "const onClick = data[0]; const active = data[1]; const customClass = data[2] || ''; const isInteractive = !!onClick; const interactiveClass = isInteractive ? 'cursor-pointer hover:bg-accent' : ''; const activeClass = active ? 'bg-accent' : ''; return `flex items-center gap-3 px-3 py-2 rounded-md transition-colors ${interactiveClass} ${activeClass} ${customClass}`.trim()"
},
"onClick": {
"source": "onClick",
"transform": "data"
},
"role": {
"source": "onClick",
"transform": "data ? 'button' : undefined"
},
"tabIndex": {
"source": "onClick",
"transform": "data ? 0 : undefined"
}
},
"children": [
{
"id": "list-item-icon",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-shrink-0 text-muted-foreground'"
},
"children": {
"source": "icon",
"transform": "data"
},
"_if": {
"source": "icon",
"transform": "!!data"
}
}
},
{
"id": "list-item-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-1 min-w-0 text-sm'"
},
"children": {
"source": "children",
"transform": "data"
}
}
},
{
"id": "list-item-end-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-shrink-0'"
},
"children": {
"source": "endContent",
"transform": "data"
},
"_if": {
"source": "endContent",
"transform": "!!data"
}
}
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "list-container",
"type": "div",
"bindings": {
"className": {
"source": ["items", "className"],
"transform": "const items = data[0] || []; const customClass = data[1] || ''; if (items.length === 0) return 'text-center text-muted-foreground py-8'; return customClass"
},
"_if": {
"source": "items",
"transform": "data && data.length > 0"
}
},
"children": {
"source": "items",
"transform": "(items) => items && items.map((item, index) => ({ id: `list-item-${index}`, type: 'div', bindings: { className: { source: 'itemClassName', transform: 'data || \"\"' } }, children: [{ id: `list-item-content-${index}`, type: 'div', bindings: { children: { source: 'renderItem', transform: `(fn) => fn && fn(item, ${index})` } } }] }))"
}
}

View File

@@ -0,0 +1,62 @@
{
"id": "live-indicator-container",
"type": "div",
"bindings": {
"className": {
"source": ["size", "className"],
"transform": "const size = data[0] || 'md'; const customClass = data[1] || ''; const sizeClasses = { sm: 'text-xs gap-1.5', md: 'text-sm gap-2', lg: 'text-base gap-2.5' }; return `inline-flex items-center font-medium ${sizeClasses[size]} ${customClass}`.trim()"
}
},
"children": [
{
"id": "live-indicator-pulse",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'relative flex'"
}
},
"children": [
{
"id": "live-indicator-ping",
"type": "span",
"bindings": {
"className": {
"source": "size",
"transform": "const size = data || 'md'; const dotSizeClasses = { sm: 'w-2 h-2', md: 'w-2.5 h-2.5', lg: 'w-3 h-3' }; return `absolute inline-flex rounded-full bg-red-500 opacity-75 animate-ping ${dotSizeClasses[size]}`.trim()"
}
}
},
{
"id": "live-indicator-dot",
"type": "span",
"bindings": {
"className": {
"source": "size",
"transform": "const size = data || 'md'; const dotSizeClasses = { sm: 'w-2 h-2', md: 'w-2.5 h-2.5', lg: 'w-3 h-3' }; return `relative inline-flex rounded-full bg-red-500 ${dotSizeClasses[size]}`.trim()"
}
}
}
]
},
{
"id": "live-indicator-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-red-500 font-bold tracking-wider'"
},
"children": {
"source": "label",
"transform": "data"
},
"_if": {
"source": "showLabel",
"transform": "data !== false"
}
}
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "loading-spinner",
"type": "div",
"bindings": {
"className": {
"source": ["size", "className"],
"transform": "const size = data[0] || 'md'; const customClass = data[1] || ''; const sizeClasses = { sm: 'w-4 h-4 border-2', md: 'w-6 h-6 border-2', lg: 'w-8 h-8 border-3' }; return `inline-block ${sizeClasses[size]} border-primary border-t-transparent rounded-full animate-spin ${customClass}`.trim()"
},
"role": {
"source": null,
"transform": "'status'"
},
"aria-label": {
"source": null,
"transform": "'Loading'"
}
}
}

View File

@@ -0,0 +1,40 @@
{
"id": "loading-state-container",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "const customClass = data || ''; return `flex flex-col items-center justify-center gap-3 py-8 ${customClass}`.trim()"
}
},
"children": [
{
"id": "loading-state-spinner",
"type": "div",
"bindings": {
"className": {
"source": "size",
"transform": "const size = data || 'md'; const sizeClasses = { sm: 'w-4 h-4 border-2', md: 'w-8 h-8 border-3', lg: 'w-12 h-12 border-4' }; return `border-primary border-t-transparent rounded-full animate-spin ${sizeClasses[size]}`.trim()"
}
}
},
{
"id": "loading-state-message",
"type": "p",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm text-muted-foreground'"
},
"children": {
"source": "message",
"transform": "data"
},
"_if": {
"source": "message",
"transform": "!!data"
}
}
}
]
}

View File

@@ -0,0 +1,96 @@
{
"id": "metric-display-container",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "const customClass = data || ''; return `flex flex-col gap-1 ${customClass}`.trim()"
}
},
"children": [
{
"id": "metric-display-label",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center gap-2 text-sm text-muted-foreground'"
}
},
"children": [
{
"id": "metric-display-icon",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-muted-foreground'"
},
"children": {
"source": "icon",
"transform": "data"
},
"_if": {
"source": "icon",
"transform": "!!data"
}
}
},
{
"id": "metric-display-label-text",
"type": "span",
"bindings": {
"children": {
"source": "label",
"transform": "data"
}
}
}
]
},
{
"id": "metric-display-value-container",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-baseline gap-2'"
}
},
"children": [
{
"id": "metric-display-value",
"type": "span",
"bindings": {
"className": {
"source": "variant",
"transform": "const variant = data || 'default'; const variantClasses = { default: 'text-foreground', primary: 'text-primary', accent: 'text-accent' }; return `text-2xl font-bold ${variantClasses[variant]}`.trim()"
},
"children": {
"source": "value",
"transform": "data"
}
}
},
{
"id": "metric-display-trend",
"type": "span",
"bindings": {
"className": {
"source": "trend",
"transform": "const trend = data; const direction = trend?.direction; const trendClass = direction === 'up' ? 'text-green-600 dark:text-green-400' : 'text-destructive'; return `flex items-center gap-0.5 text-xs font-medium ${trendClass}`.trim()"
},
"children": {
"source": "trend",
"transform": "const trend = data; const value = Math.abs(trend?.value || 0); const icon = trend?.direction === 'up' ? '↑' : '↓'; return `${icon} ${value}%`"
},
"_if": {
"source": "trend",
"transform": "!!data"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,122 @@
{
"id": "modal-overlay",
"type": "div",
"bindings": {
"className": {
"source": "isOpen",
"transform": "data ? 'fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm animate-in fade-in-0' : 'hidden'"
},
"onClick": {
"source": "onClose",
"transform": "data"
},
"_if": {
"source": "isOpen",
"transform": "data"
}
},
"children": [
{
"id": "modal-content",
"type": "div",
"bindings": {
"className": {
"source": ["size", "className"],
"transform": "const size = data[0] || 'md'; const customClass = data[1] || ''; const sizeStyles = { sm: 'max-w-sm', md: 'max-w-md', lg: 'max-w-lg', xl: 'max-w-xl', full: 'max-w-full m-4' }; return `relative w-full bg-card border border-border rounded-lg shadow-lg animate-in zoom-in-95 ${sizeStyles[size]} ${customClass}`.trim()"
},
"onClick": {
"source": null,
"transform": "(e) => e.stopPropagation()"
}
},
"children": [
{
"id": "modal-header",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center justify-between p-6 border-b border-border'"
},
"_if": {
"source": ["title", "showCloseButton"],
"transform": "!!data[0] || data[1] !== false"
}
},
"children": [
{
"id": "modal-title",
"type": "h2",
"bindings": {
"className": {
"source": null,
"transform": "'text-lg font-semibold'"
},
"children": {
"source": "title",
"transform": "data"
},
"_if": {
"source": "title",
"transform": "!!data"
}
}
},
{
"id": "modal-close-button",
"type": "button",
"bindings": {
"className": {
"source": null,
"transform": "'ml-auto p-1 rounded-md hover:bg-accent transition-colors'"
},
"onClick": {
"source": "onClose",
"transform": "data"
},
"aria-label": {
"source": null,
"transform": "'Close modal'"
},
"_if": {
"source": "showCloseButton",
"transform": "data !== false"
}
},
"children": [
{
"id": "modal-close-icon",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'w-5 h-5'"
},
"children": {
"source": null,
"transform": "'✕'"
}
}
}
]
}
]
},
{
"id": "modal-body",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'p-6'"
},
"children": {
"source": "children",
"transform": "data"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,108 @@
{
"id": "notification-container",
"type": "div",
"bindings": {
"className": {
"source": ["type", "className"],
"transform": "const type = data[0]; const customClass = data[1] || ''; const config = { info: { bg: 'bg-blue-500/10', border: 'border-blue-500/20', color: 'text-blue-500' }, success: { bg: 'bg-accent/10', border: 'border-accent/20', color: 'text-accent' }, warning: { bg: 'bg-yellow-500/10', border: 'border-yellow-500/20', color: 'text-yellow-500' }, error: { bg: 'bg-destructive/10', border: 'border-destructive/20', color: 'text-destructive' } }; const c = config[type]; return `flex gap-3 p-4 rounded-lg border ${c.bg} ${c.border} ${customClass}`.trim()"
}
},
"children": [
{
"id": "notification-icon",
"type": "div",
"bindings": {
"className": {
"source": "type",
"transform": "const type = data; const colors = { info: 'text-blue-500', success: 'text-accent', warning: 'text-yellow-500', error: 'text-destructive' }; return `w-5 h-5 flex-shrink-0 ${colors[type]}`.trim()"
},
"children": {
"source": "type",
"transform": "const type = data; const icons = { info: '', success: '✓', warning: '⚠', error: '✕' }; return icons[type]"
}
}
},
{
"id": "notification-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex-1 min-w-0'"
}
},
"children": [
{
"id": "notification-title",
"type": "h4",
"bindings": {
"className": {
"source": null,
"transform": "'font-medium text-sm'"
},
"children": {
"source": "title",
"transform": "data"
}
}
},
{
"id": "notification-message",
"type": "p",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm text-muted-foreground mt-1'"
},
"children": {
"source": "message",
"transform": "data"
},
"_if": {
"source": "message",
"transform": "!!data"
}
}
}
]
},
{
"id": "notification-close",
"type": "button",
"bindings": {
"className": {
"source": null,
"transform": "'flex-shrink-0 text-muted-foreground hover:text-foreground transition-colors'"
},
"onClick": {
"source": "onClose",
"transform": "data"
},
"aria-label": {
"source": null,
"transform": "'Close notification'"
},
"_if": {
"source": "onClose",
"transform": "!!data"
}
},
"children": [
{
"id": "notification-close-icon",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'w-4 h-4'"
},
"children": {
"source": null,
"transform": "'✕'"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,148 @@
{
"id": "number-input-container",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "const customClass = data || ''; return `flex flex-col gap-2 ${customClass}`.trim()"
}
},
"children": [
{
"id": "number-input-label",
"type": "label",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm font-medium text-foreground'"
},
"children": {
"source": "label",
"transform": "data"
},
"_if": {
"source": "label",
"transform": "!!data"
}
}
},
{
"id": "number-input-controls",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center gap-2'"
}
},
"children": [
{
"id": "number-input-decrement",
"type": "button",
"bindings": {
"type": {
"source": null,
"transform": "'button'"
},
"className": {
"source": ["disabled", "min", "value"],
"transform": "const disabled = data[0]; const min = data[1]; const value = data[2]; const isAtMin = min !== undefined && value <= min; return `h-9 w-9 shrink-0 px-3 py-2 rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed transition-colors ${disabled || isAtMin ? 'opacity-50 cursor-not-allowed' : ''}`.trim()"
},
"onClick": {
"source": null,
"transform": "() => { /* handleDecrement */ }"
},
"disabled": {
"source": ["disabled", "min", "value"],
"transform": "data[0] || (data[1] !== undefined && data[2] <= data[1])"
}
},
"children": [
{
"id": "number-input-decrement-icon",
"type": "span",
"bindings": {
"children": {
"source": null,
"transform": "''"
}
}
}
]
},
{
"id": "number-input-field",
"type": "input",
"bindings": {
"type": {
"source": null,
"transform": "'number'"
},
"value": {
"source": "value",
"transform": "data"
},
"onChange": {
"source": null,
"transform": "(e) => { /* handleInputChange */ }"
},
"min": {
"source": "min",
"transform": "data"
},
"max": {
"source": "max",
"transform": "data"
},
"step": {
"source": "step",
"transform": "data || 1"
},
"disabled": {
"source": "disabled",
"transform": "data || false"
},
"className": {
"source": null,
"transform": "'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-center placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 transition-colors'"
}
}
},
{
"id": "number-input-increment",
"type": "button",
"bindings": {
"type": {
"source": null,
"transform": "'button'"
},
"className": {
"source": ["disabled", "max", "value"],
"transform": "const disabled = data[0]; const max = data[1]; const value = data[2]; const isAtMax = max !== undefined && value >= max; return `h-9 w-9 shrink-0 px-3 py-2 rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground disabled:opacity-50 disabled:cursor-not-allowed transition-colors ${disabled || isAtMax ? 'opacity-50 cursor-not-allowed' : ''}`.trim()"
},
"onClick": {
"source": null,
"transform": "() => { /* handleIncrement */ }"
},
"disabled": {
"source": ["disabled", "max", "value"],
"transform": "data[0] || (data[1] !== undefined && data[2] >= data[1])"
}
},
"children": [
{
"id": "number-input-increment-icon",
"type": "span",
"bindings": {
"children": {
"source": null,
"transform": "'+'"
}
}
}
]
}
]
}
]
}

View File

@@ -0,0 +1,74 @@
{
"id": "page-header-wrapper",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "const baseClass = 'flex items-start justify-between mb-6'; return data ? `${baseClass} ${data}` : baseClass"
}
},
"children": [
{
"id": "page-header-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'space-y-1'"
}
},
"children": [
{
"id": "page-header-title",
"type": "h1",
"bindings": {
"className": {
"source": null,
"transform": "'text-3xl font-bold tracking-tight'"
},
"children": {
"source": "title",
"transform": "data"
}
}
},
{
"id": "page-header-description",
"type": "p",
"bindings": {
"className": {
"source": null,
"transform": "'text-muted-foreground'"
},
"children": {
"source": "description",
"transform": "data"
},
"_if": {
"source": "description",
"transform": "!!data"
}
}
}
]
},
{
"id": "page-header-actions",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex gap-2'"
},
"children": {
"source": "actions",
"transform": "data"
},
"_if": {
"source": "actions",
"transform": "!!data"
}
}
}
]
}

View File

@@ -0,0 +1,72 @@
{
"id": "progress-bar-wrapper",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'w-full'"
}
},
"children": [
{
"id": "progress-bar-container",
"type": "div",
"bindings": {
"className": {
"source": ["value", "max", "size", "variant", "className"],
"transform": "const value = data[0] || 0; const max = data[1] || 100; const size = data[2] || 'md'; const variant = data[3] || 'default'; const className = data[4] || ''; const sizeClasses = { sm: 'h-1', md: 'h-2', lg: 'h-3' }; const variantClasses = { default: 'bg-primary', accent: 'bg-accent', destructive: 'bg-destructive' }; const baseClass = 'relative w-full bg-secondary rounded-full overflow-hidden'; return `${baseClass} ${sizeClasses[size]} ${className}`.trim()"
},
"role": {
"source": null,
"transform": "'progressbar'"
},
"aria-valuenow": {
"source": "value",
"transform": "data"
},
"aria-valuemin": {
"source": null,
"transform": "0"
},
"aria-valuemax": {
"source": "max",
"transform": "data || 100"
}
},
"children": [
{
"id": "progress-bar-fill",
"type": "div",
"bindings": {
"className": {
"source": "variant",
"transform": "const variantClasses = { default: 'bg-primary', accent: 'bg-accent', destructive: 'bg-destructive' }; return `h-full transition-all duration-300 ease-out ${variantClasses[data] || variantClasses['default']}`"
},
"style": {
"source": ["value", "max"],
"transform": "const value = data[0] || 0; const max = data[1] || 100; const percentage = Math.min(Math.max((value / max) * 100, 0), 100); return { width: `${percentage}%` }"
}
}
}
]
},
{
"id": "progress-bar-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-xs text-muted-foreground mt-1 block'"
},
"children": {
"source": ["value", "max"],
"transform": "const value = data[0] || 0; const max = data[1] || 100; const percentage = Math.min(Math.max((value / max) * 100, 0), 100); return `${Math.round(percentage)}%`"
},
"_if": {
"source": "showLabel",
"transform": "!!data"
}
}
}
]
}

View File

@@ -0,0 +1,32 @@
{
"id": "pulse-wrapper",
"type": "div",
"bindings": {
"className": {
"source": ["variant", "size", "speed", "className"],
"transform": "const variant = data[0] || 'primary'; const size = data[1] || 'md'; const speed = data[2] || 'normal'; const className = data[3] || ''; const sizeClasses = { sm: 'w-2 h-2', md: 'w-3 h-3', lg: 'w-4 h-4' }; const variantClasses = { primary: 'bg-primary', accent: 'bg-accent', success: 'bg-green-500', warning: 'bg-yellow-500', error: 'bg-red-500' }; const speedClasses = { slow: 'animate-pulse [animation-duration:3s]', normal: 'animate-pulse', fast: 'animate-pulse [animation-duration:0.5s]' }; const baseClass = 'relative inline-flex'; return `${baseClass} ${className}`.trim()"
}
},
"children": [
{
"id": "pulse-inner-1",
"type": "span",
"bindings": {
"className": {
"source": ["variant", "size", "speed"],
"transform": "const variant = data[0] || 'primary'; const size = data[1] || 'md'; const speed = data[2] || 'normal'; const sizeClasses = { sm: 'w-2 h-2', md: 'w-3 h-3', lg: 'w-4 h-4' }; const variantClasses = { primary: 'bg-primary', accent: 'bg-accent', success: 'bg-green-500', warning: 'bg-yellow-500', error: 'bg-red-500' }; const speedClasses = { slow: 'animate-pulse [animation-duration:3s]', normal: 'animate-pulse', fast: 'animate-pulse [animation-duration:0.5s]' }; return `inline-flex rounded-full opacity-75 ${sizeClasses[size]} ${variantClasses[variant]} ${speedClasses[speed]}`"
}
}
},
{
"id": "pulse-inner-2",
"type": "span",
"bindings": {
"className": {
"source": ["variant", "size", "speed"],
"transform": "const variant = data[0] || 'primary'; const size = data[1] || 'md'; const speed = data[2] || 'normal'; const sizeClasses = { sm: 'w-2 h-2', md: 'w-3 h-3', lg: 'w-4 h-4' }; const variantClasses = { primary: 'bg-primary', accent: 'bg-accent', success: 'bg-green-500', warning: 'bg-yellow-500', error: 'bg-red-500' }; const speedClasses = { slow: 'animate-pulse [animation-duration:3s]', normal: 'animate-pulse', fast: 'animate-pulse [animation-duration:0.5s]' }; return `absolute inline-flex rounded-full opacity-75 ${sizeClasses[size]} ${variantClasses[variant]} ${speedClasses[speed]}`"
}
}
}
]
}

View File

@@ -0,0 +1,74 @@
{
"id": "quick-action-button-card",
"type": "Card",
"bindings": {
"onClick": {
"source": ["onClick", "disabled"],
"transform": "const onClick = data[0]; const disabled = data[1]; return disabled ? undefined : onClick"
},
"className": {
"source": ["variant", "disabled", "className"],
"transform": "const variant = data[0] || 'default'; const disabled = data[1]; const className = data[2] || ''; const variantClasses = { default: 'hover:bg-muted/50 hover:border-border', primary: 'hover:bg-primary/10 hover:border-primary/50', accent: 'hover:bg-accent/10 hover:border-accent/50', muted: 'bg-muted hover:bg-muted/70' }; const baseClass = 'p-6 cursor-pointer transition-all duration-200 flex flex-col items-center justify-center gap-3 text-center hover:scale-105 active:scale-95'; const disabledClass = disabled ? 'opacity-50 cursor-not-allowed hover:scale-100' : ''; return `${baseClass} ${variantClasses[variant]} ${disabledClass} ${className}`.trim()"
}
},
"children": [
{
"id": "quick-action-button-icon",
"type": "div",
"bindings": {
"className": {
"source": "variant",
"transform": "const iconColorClasses = { default: 'text-foreground', primary: 'text-primary', accent: 'text-accent', muted: 'text-muted-foreground' }; return `text-4xl ${iconColorClasses[data] || iconColorClasses['default']}`"
},
"children": {
"source": "icon",
"transform": "data"
}
}
},
{
"id": "quick-action-button-content",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'space-y-1'"
}
},
"children": [
{
"id": "quick-action-button-label",
"type": "h3",
"bindings": {
"className": {
"source": null,
"transform": "'font-semibold text-foreground'"
},
"children": {
"source": "label",
"transform": "data"
}
}
},
{
"id": "quick-action-button-description",
"type": "p",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm text-muted-foreground'"
},
"children": {
"source": "description",
"transform": "data"
},
"_if": {
"source": "description",
"transform": "!!data"
}
}
}
]
}
]
}

View File

@@ -0,0 +1,46 @@
{
"id": "search-input-wrapper",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "data || ''"
}
},
"children": [
{
"id": "search-input-field",
"type": "Input",
"bindings": {
"type": {
"source": null,
"transform": "'text'"
},
"value": {
"source": "value",
"transform": "data"
},
"onChange": {
"source": "onChange",
"transform": "(e) => data(e.target.value)"
},
"placeholder": {
"source": "placeholder",
"transform": "data || 'Search...'"
},
"className": {
"source": null,
"transform": "''"
},
"leftIcon": {
"source": null,
"transform": "{ type: 'MagnifyingGlass', size: 18 }"
},
"rightIcon": {
"source": ["value", "onClear"],
"transform": "const value = data[0]; const onClear = data[1]; if (!value) return null; return { type: 'button', onClick: () => { data[1]?.(); }, className: 'text-muted-foreground hover:text-foreground transition-colors', children: { type: 'X', size: 18 } }"
}
}
}
]
}

View File

@@ -0,0 +1,126 @@
{
"id": "seed-data-status-card",
"type": "Card",
"bindings": {
"className": {
"source": "className",
"transform": "data || ''"
}
},
"children": [
{
"id": "seed-data-status-header",
"type": "CardHeader",
"children": [
{
"id": "seed-data-status-title",
"type": "CardTitle",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center gap-2 text-lg'"
}
},
"children": [
{
"id": "seed-data-status-icon",
"type": "Database",
"bindings": {
"size": {
"source": null,
"transform": "20"
},
"weight": {
"source": null,
"transform": "'duotone'"
}
}
},
{
"id": "seed-data-status-text",
"type": "span",
"bindings": {
"children": {
"source": null,
"transform": "'Seed Data Available'"
}
}
}
]
},
{
"id": "seed-data-status-description",
"type": "CardDescription",
"bindings": {
"children": {
"source": null,
"transform": "'Pre-configured data ready to load from database'"
}
}
}
]
},
{
"id": "seed-data-status-content",
"type": "CardContent",
"children": [
{
"id": "seed-data-status-grid",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'grid grid-cols-2 md:grid-cols-3 gap-3'"
}
},
"children": [
{
"id": "seed-data-status-item",
"type": "div",
"bindings": {
"className": {
"source": null,
"transform": "'flex items-center justify-between p-3 rounded-lg border border-border bg-muted/50'"
}
},
"children": [
{
"id": "seed-data-status-label",
"type": "span",
"bindings": {
"className": {
"source": null,
"transform": "'text-sm font-medium'"
},
"children": {
"source": "label",
"transform": "data"
}
}
},
{
"id": "seed-data-status-badge",
"type": "Badge",
"bindings": {
"variant": {
"source": null,
"transform": "'secondary'"
},
"className": {
"source": null,
"transform": "'ml-2'"
},
"children": {
"source": "count",
"transform": "data"
}
}
}
]
}
]
}
]
}
]
}

View File

@@ -0,0 +1,18 @@
{
"id": "sparkle-icon",
"type": "Sparkle",
"bindings": {
"size": {
"source": "size",
"transform": "data || 16"
},
"weight": {
"source": null,
"transform": "'fill'"
},
"className": {
"source": ["variant", "animate", "className"],
"transform": "const variant = data[0] || 'default'; const animate = data[1]; const className = data[2] || ''; const variantClasses = { default: 'text-foreground', primary: 'text-primary', accent: 'text-accent', gold: 'text-yellow-500' }; const animateClass = animate ? 'animate-pulse' : ''; return `${variantClasses[variant]} ${animateClass} ${className}`.trim()"
}
}
}

View File

@@ -0,0 +1,16 @@
{
"id": "tab-icon",
"type": "div",
"bindings": {
"className": {
"source": "variant",
"transform": "data === 'gradient' ? 'w-10 h-10 rounded-lg bg-gradient-to-br from-primary/20 to-accent/20 flex items-center justify-center text-primary shrink-0' : ''"
}
},
"children": [
{
"type": "slot",
"name": "icon"
}
]
}

View File

@@ -0,0 +1,61 @@
{
"id": "tips-card",
"type": "Card",
"bindings": {
"className": "bg-yellow-500/10 border-yellow-500/20"
},
"children": [
{
"id": "tips-card-header",
"type": "CardHeader",
"children": [
{
"id": "tips-card-title",
"type": "CardTitle",
"bindings": {
"className": "flex items-center gap-2"
},
"children": [
{
"type": "Icon",
"bindings": {
"name": "warning",
"weight": "duotone",
"size": 24,
"className": "text-yellow-500"
}
},
{
"type": "Text",
"bindings": {
"content": "Quick Tips"
}
}
]
}
]
},
{
"id": "tips-card-content",
"type": "CardContent",
"bindings": {
"className": "space-y-2 text-sm"
},
"children": [
{
"type": "forEach",
"source": "tips",
"condition": "item.show",
"children": [
{
"type": "Text",
"bindings": {
"content": "• {item.message}"
}
}
]
}
]
}
]
}

View File

@@ -0,0 +1,5 @@
export interface BindingIndicatorProps {
sourceId: string
path?: string
className?: string
}

View File

@@ -0,0 +1,7 @@
import { ReactNode } from 'react'
export interface ButtonGroupProps {
children: ReactNode
orientation?: 'horizontal' | 'vertical'
className?: string
}

View File

@@ -0,0 +1,9 @@
import { ReactNode } from 'react'
export interface ChipProps {
children: ReactNode
variant?: 'default' | 'primary' | 'accent' | 'muted'
size?: 'sm' | 'md'
onRemove?: () => void
className?: string
}

View File

@@ -0,0 +1,8 @@
export interface CircularProgressProps {
value: number
max?: number
size?: 'sm' | 'md' | 'lg' | 'xl'
showLabel?: boolean
strokeWidth?: number
className?: string
}

View File

@@ -0,0 +1,7 @@
import { ReactNode } from 'react'
export interface CodeProps {
children: ReactNode
inline?: boolean
className?: string
}

View File

@@ -0,0 +1,19 @@
import { ReactNode } from 'react'
export interface CommandOption {
value: string
label: string
icon?: ReactNode
onSelect?: () => void
}
export interface CommandPaletteProps {
open: boolean
onOpenChange: (open: boolean) => void
placeholder?: string
emptyMessage?: string
groups: {
heading?: string
items: CommandOption[]
}[]
}

View File

@@ -0,0 +1,5 @@
export interface CompletionCardProps {
completionScore: number
completionMessage: string
isReadyToExport: boolean
}

View File

@@ -0,0 +1,7 @@
import { ComponentDefinition } from '@/lib/component-definition-types'
export interface ComponentPaletteItemProps {
component: ComponentDefinition
onDragStart: (component: ComponentDefinition, e: React.DragEvent) => void
className?: string
}

View File

@@ -0,0 +1,8 @@
import { ButtonHTMLAttributes, ReactNode } from 'react'
export interface ConfirmButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {
onConfirm: () => void | Promise<void>
confirmText?: string
isLoading?: boolean
children: ReactNode
}

View File

@@ -0,0 +1,6 @@
import { DataSourceType } from '@/types/json-ui'
export interface DataSourceBadgeProps {
type: DataSourceType
className?: string
}

View File

@@ -0,0 +1,17 @@
import { ReactNode } from 'react'
export interface Column<T> {
key: string
header: string | ReactNode
cell?: (item: T) => ReactNode
sortable?: boolean
width?: string
}
export interface DataTableProps<T> {
data: T[]
columns: Column<T>[]
onRowClick?: (item: T) => void
emptyMessage?: string
className?: string
}

View File

@@ -0,0 +1,7 @@
export interface DatePickerProps {
value?: Date
onChange: (date: Date | undefined) => void
placeholder?: string
disabled?: boolean
className?: string
}

View File

@@ -0,0 +1,5 @@
export interface DetailRowProps {
icon: React.ReactNode
label: string
value: number
}

View File

@@ -0,0 +1,5 @@
export interface DividerProps {
orientation?: 'horizontal' | 'vertical'
className?: string
decorative?: boolean
}

View File

@@ -0,0 +1,10 @@
export interface EmptyMessageProps {
icon?: React.ReactNode
title: string
description?: string
action?: {
label: string
onClick: () => void
}
className?: string
}

View File

@@ -0,0 +1,5 @@
export interface ErrorBadgeProps {
count: number
variant?: 'default' | 'destructive'
size?: 'sm' | 'md'
}

View File

@@ -0,0 +1,6 @@
export interface FileIconProps {
type?: 'code' | 'json' | 'plus'
size?: number
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
className?: string
}

View File

@@ -0,0 +1,7 @@
export interface GlowCardProps {
children: React.ReactNode
glowColor?: 'primary' | 'accent' | 'success' | 'warning' | 'error'
intensity?: 'low' | 'medium' | 'high'
className?: string
onClick?: () => void
}

View File

@@ -0,0 +1,5 @@
export interface HelperTextProps {
children: React.ReactNode
variant?: 'default' | 'error' | 'success'
className?: string
}

View File

@@ -1,6 +1,7 @@
export * from './loading-fallback'
export * from './navigation-item'
export * from './page-header-content'
export * from './page-header'
export * from './save-indicator'
export * from './lazy-bar-chart'
export * from './lazy-line-chart'
@@ -43,23 +44,36 @@ export * from './calendar'
export * from './card'
export * from './checkbox'
export * from './context-menu'
export * from './date-picker'
export * from './detail-row'
export * from './dialog'
export * from './divider'
export * from './drawer'
export * from './dropdown-menu'
export * from './empty-message'
export * from './error-badge'
export * from './file-icon'
export * from './form'
export * from './form-field'
export * from './glow-card'
export * from './heading'
export * from './helper-text'
export * from './hover-card'
export * from './icon'
export * from './input-otp'
export * from './label'
export * from './pagination'
export * from './progress'
export * from './progress-bar'
export * from './pulse'
export * from './quick-action-button'
export * from './radio-group'
export * from './range-slider'
export * from './rating'
export * from './scroll-area'
export * from './scroll-area-thumb'
export * from './search-input'
export * from './seed-data-status'
export * from './select'
export * from './separator'
export * from './skeleton'
@@ -79,3 +93,16 @@ export * from './timeline'
export * from './timestamp'
export * from './toggle'
export * from './tooltip'
export * from './tab-icon'
export * from './tips-card'
export * from './info-box'
export * from './key-value'
export * from './live-indicator'
export * from './list'
export * from './list-item'
export * from './loading-spinner'
export * from './loading-state'
export * from './metric-display'
export * from './modal'
export * from './notification'
export * from './number-input'

View File

@@ -0,0 +1,6 @@
export interface InfoBoxProps {
type?: 'info' | 'warning' | 'success' | 'error'
title?: string
children: React.ReactNode
className?: string
}

View File

@@ -0,0 +1,8 @@
export interface KeyValueProps {
label: string
value: React.ReactNode
orientation?: 'horizontal' | 'vertical'
className?: string
labelClassName?: string
valueClassName?: string
}

View File

@@ -0,0 +1,8 @@
export interface ListItemProps {
icon?: React.ReactNode
children: React.ReactNode
onClick?: () => void
active?: boolean
className?: string
endContent?: React.ReactNode
}

View File

@@ -0,0 +1,7 @@
export interface ListProps<T> {
items: T[]
renderItem: (item: T, index: number) => React.ReactNode
emptyMessage?: string
className?: string
itemClassName?: string
}

View File

@@ -0,0 +1,6 @@
export interface LiveIndicatorProps {
label?: string
showLabel?: boolean
size?: 'sm' | 'md' | 'lg'
className?: string
}

View File

@@ -0,0 +1,4 @@
export interface LoadingSpinnerProps {
size?: 'sm' | 'md' | 'lg'
className?: string
}

View File

@@ -0,0 +1,5 @@
export interface LoadingStateProps {
message?: string
size?: 'sm' | 'md' | 'lg'
className?: string
}

View File

@@ -0,0 +1,11 @@
export interface MetricDisplayProps {
label: string
value: string | number
trend?: {
value: number
direction: 'up' | 'down'
}
icon?: React.ReactNode
className?: string
variant?: 'default' | 'primary' | 'accent'
}

View File

@@ -0,0 +1,9 @@
export interface ModalProps {
isOpen: boolean
onClose: () => void
title?: string
children: React.ReactNode
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
showCloseButton?: boolean
className?: string
}

View File

@@ -0,0 +1,7 @@
export interface NotificationProps {
type: 'info' | 'success' | 'warning' | 'error'
title: string
message?: string
onClose?: () => void
className?: string
}

View File

@@ -0,0 +1,10 @@
export interface NumberInputProps {
value: number
onChange: (value: number) => void
min?: number
max?: number
step?: number
label?: string
disabled?: boolean
className?: string
}

View File

@@ -0,0 +1,6 @@
export interface PageHeaderProps {
title: string
description?: string
actions?: React.ReactNode
className?: string
}

View File

@@ -0,0 +1,8 @@
export interface ProgressBarProps {
value: number
max?: number
size?: 'sm' | 'md' | 'lg'
variant?: 'default' | 'accent' | 'destructive'
showLabel?: boolean
className?: string
}

View File

@@ -0,0 +1,6 @@
export interface PulseProps {
variant?: 'primary' | 'accent' | 'success' | 'warning' | 'error'
size?: 'sm' | 'md' | 'lg'
speed?: 'slow' | 'normal' | 'fast'
className?: string
}

View File

@@ -0,0 +1,9 @@
export interface QuickActionButtonProps {
icon: React.ReactNode
label: string
description?: string
onClick: () => void
variant?: 'default' | 'primary' | 'accent' | 'muted'
disabled?: boolean
className?: string
}

View File

@@ -0,0 +1,7 @@
export interface SearchInputProps {
value: string
onChange: (value: string) => void
placeholder?: string
onClear?: () => void
className?: string
}

View File

@@ -0,0 +1,3 @@
export interface SeedDataStatusProps {
className?: string
}

View File

@@ -0,0 +1,6 @@
export interface SparkleProps {
variant?: 'default' | 'primary' | 'accent' | 'gold'
size?: number
animate?: boolean
className?: string
}

View File

@@ -0,0 +1,4 @@
export interface TabIconProps {
icon: React.ReactNode
variant?: 'default' | 'gradient'
}

View File

@@ -0,0 +1,3 @@
export interface TipsCardProps {
tips: Array<{ message: string; show: boolean }>
}

View File

@@ -9,6 +9,7 @@ import type {
LoadingFallbackProps,
NavigationItemProps,
PageHeaderContentProps,
PageHeaderProps,
SaveIndicatorProps,
LazyBarChartProps,
LazyLineChartProps,
@@ -63,15 +64,21 @@ import type {
LabelProps,
PaginationProps,
ProgressProps,
ProgressBarProps,
PulseProps,
QuickActionButtonProps,
RadioGroupProps,
RangeSliderProps,
RatingProps,
ScrollAreaProps,
ScrollAreaThumbProps,
SearchInputProps,
SeedDataStatusProps,
SelectProps,
SeparatorProps,
SkeletonProps,
SliderProps,
SparkleProps,
SpinnerProps,
StatusIconProps,
StepIndicatorProps,
@@ -87,12 +94,26 @@ import type {
TimestampProps,
ToggleProps,
TooltipProps,
TabIconProps,
TipsCardProps,
InfoBoxProps,
KeyValueProps,
LiveIndicatorProps,
ListProps,
ListItemProps,
LoadingSpinnerProps,
LoadingStateProps,
MetricDisplayProps,
ModalProps,
NotificationProps,
NumberInputProps,
} from './interfaces'
// Import JSON definitions
import loadingFallbackDef from '@/components/json-definitions/loading-fallback.json'
import navigationItemDef from '@/components/json-definitions/navigation-item.json'
import pageHeaderContentDef from '@/components/json-definitions/page-header-content.json'
import pageHeaderDef from '@/components/json-definitions/page-header.json'
import componentBindingDialogDef from '@/components/json-definitions/component-binding-dialog.json'
import dataSourceEditorDialogDef from '@/components/json-definitions/data-source-editor-dialog.json'
import githubBuildStatusDef from '@/components/json-definitions/github-build-status.json'
@@ -145,15 +166,21 @@ import inputOtpDef from '@/components/json-definitions/input-otp.json'
import labelDef from '@/components/json-definitions/label.json'
import paginationDef from '@/components/json-definitions/pagination.json'
import progressDef from '@/components/json-definitions/progress.json'
import progressBarDef from '@/components/json-definitions/progress-bar.json'
import pulseDef from '@/components/json-definitions/pulse.json'
import quickActionButtonDef from '@/components/json-definitions/quick-action-button.json'
import radioGroupDef from '@/components/json-definitions/radio-group.json'
import rangeSliderDef from '@/components/json-definitions/range-slider.json'
import ratingDef from '@/components/json-definitions/rating.json'
import scrollAreaDef from '@/components/json-definitions/scroll-area.json'
import scrollAreaThumbDef from '@/components/json-definitions/scroll-area-thumb.json'
import searchInputDef from '@/components/json-definitions/search-input.json'
import seedDataStatusDef from '@/components/json-definitions/seed-data-status.json'
import selectDef from '@/components/json-definitions/select.json'
import separatorDef from '@/components/json-definitions/separator.json'
import skeletonDef from '@/components/json-definitions/skeleton.json'
import sliderDef from '@/components/json-definitions/slider.json'
import sparkleDef from '@/components/json-definitions/sparkle.json'
import spinnerDef from '@/components/json-definitions/spinner.json'
import statusIconDef from '@/components/json-definitions/status-icon.json'
import stepIndicatorDef from '@/components/json-definitions/step-indicator.json'
@@ -169,6 +196,19 @@ import timelineDef from '@/components/json-definitions/timeline.json'
import timestampDef from '@/components/json-definitions/timestamp.json'
import toggleDef from '@/components/json-definitions/toggle.json'
import tooltipDef from '@/components/json-definitions/tooltip.json'
import tabIconDef from '@/components/json-definitions/tab-icon.json'
import tipsCardDef from '@/components/json-definitions/tips-card.json'
import infoBoxDef from '@/components/json-definitions/info-box.json'
import keyValueDef from '@/components/json-definitions/key-value.json'
import liveIndicatorDef from '@/components/json-definitions/live-indicator.json'
import listDef from '@/components/json-definitions/list.json'
import listItemDef from '@/components/json-definitions/list-item.json'
import loadingSpinnerDef from '@/components/json-definitions/loading-spinner.json'
import loadingStateDef from '@/components/json-definitions/loading-state.json'
import metricDisplayDef from '@/components/json-definitions/metric-display.json'
import modalDef from '@/components/json-definitions/modal.json'
import notificationDef from '@/components/json-definitions/notification.json'
import numberInputDef from '@/components/json-definitions/number-input.json'
// Create pure JSON components (no hooks)
export const LoadingFallback = createJsonComponent<LoadingFallbackProps>(loadingFallbackDef)
@@ -230,6 +270,19 @@ export const Timeline = createJsonComponent<TimelineProps>(timelineDef)
export const Timestamp = createJsonComponent<TimestampProps>(timestampDef)
export const Toggle = createJsonComponent<ToggleProps>(toggleDef)
export const Tooltip = createJsonComponent<TooltipProps>(tooltipDef)
export const TabIcon = createJsonComponent<TabIconProps>(tabIconDef)
export const TipsCard = createJsonComponent<TipsCardProps>(tipsCardDef)
export const InfoBox = createJsonComponent<InfoBoxProps>(infoBoxDef)
export const KeyValue = createJsonComponent<KeyValueProps>(keyValueDef)
export const LiveIndicator = createJsonComponent<LiveIndicatorProps>(liveIndicatorDef)
export const List = createJsonComponent<ListProps<any>>(listDef)
export const ListItem = createJsonComponent<ListItemProps>(listItemDef)
export const LoadingSpinner = createJsonComponent<LoadingSpinnerProps>(loadingSpinnerDef)
export const LoadingState = createJsonComponent<LoadingStateProps>(loadingStateDef)
export const MetricDisplay = createJsonComponent<MetricDisplayProps>(metricDisplayDef)
export const Modal = createJsonComponent<ModalProps>(modalDef)
export const Notification = createJsonComponent<NotificationProps>(notificationDef)
export const NumberInput = createJsonComponent<NumberInputProps>(numberInputDef)
// Create JSON components with hooks
export const SaveIndicator = createJsonComponentWithHooks<SaveIndicatorProps>(saveIndicatorDef, {