diff --git a/json-components-registry.json b/json-components-registry.json index 7570256..c57afe6 100644 --- a/json-components-registry.json +++ b/json-components-registry.json @@ -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 } } -} +} \ No newline at end of file diff --git a/src/components/atoms/InfoBox.tsx b/src/components/atoms/InfoBox.tsx deleted file mode 100644 index c49e752..0000000 --- a/src/components/atoms/InfoBox.tsx +++ /dev/null @@ -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 ( -
- -
- {title &&
{title}
} -
{children}
-
-
- ) -} diff --git a/src/components/atoms/KeyValue.tsx b/src/components/atoms/KeyValue.tsx deleted file mode 100644 index d00d644..0000000 --- a/src/components/atoms/KeyValue.tsx +++ /dev/null @@ -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 ( -
- - {label} - - - {value} - -
- ) -} diff --git a/src/components/atoms/Label.tsx b/src/components/atoms/Label.tsx deleted file mode 100644 index 97e897c..0000000 --- a/src/components/atoms/Label.tsx +++ /dev/null @@ -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 ( - - ) -} diff --git a/src/components/atoms/List.tsx b/src/components/atoms/List.tsx deleted file mode 100644 index 325a980..0000000 --- a/src/components/atoms/List.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ReactNode } from 'react' - -interface ListProps { - items: T[] - renderItem: (item: T, index: number) => ReactNode - emptyMessage?: string - className?: string - itemClassName?: string -} - -export function List({ - items, - renderItem, - emptyMessage = 'No items to display', - className = '', - itemClassName = '' -}: ListProps) { - if (items.length === 0) { - return ( -
- {emptyMessage} -
- ) - } - - return ( -
- {items.map((item, index) => ( -
- {renderItem(item, index)} -
- ))} -
- ) -} diff --git a/src/components/atoms/ListItem.tsx b/src/components/atoms/ListItem.tsx deleted file mode 100644 index 6042eef..0000000 --- a/src/components/atoms/ListItem.tsx +++ /dev/null @@ -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 ( -
- {icon &&
{icon}
} -
{children}
- {endContent &&
{endContent}
} -
- ) -} diff --git a/src/components/atoms/LiveIndicator.tsx b/src/components/atoms/LiveIndicator.tsx deleted file mode 100644 index a6ec0a6..0000000 --- a/src/components/atoms/LiveIndicator.tsx +++ /dev/null @@ -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 ( -
- - - - - {showLabel && ( - {label} - )} -
- ) -} diff --git a/src/components/atoms/LoadingSpinner.tsx b/src/components/atoms/LoadingSpinner.tsx deleted file mode 100644 index 7420ca7..0000000 --- a/src/components/atoms/LoadingSpinner.tsx +++ /dev/null @@ -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 ( -
- ) -} diff --git a/src/components/atoms/LoadingState.tsx b/src/components/atoms/LoadingState.tsx deleted file mode 100644 index 87ab907..0000000 --- a/src/components/atoms/LoadingState.tsx +++ /dev/null @@ -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 ( -
-
- {message && ( -

{message}

- )} -
- ) -} diff --git a/src/components/atoms/MetricDisplay.tsx b/src/components/atoms/MetricDisplay.tsx deleted file mode 100644 index 29549c9..0000000 --- a/src/components/atoms/MetricDisplay.tsx +++ /dev/null @@ -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 ( -
-
- {icon && {icon}} - {label} -
-
- - {value} - - {trend && ( - - {trend.direction === 'up' ? : } - {Math.abs(trend.value)}% - - )} -
-
- ) -} diff --git a/src/components/atoms/Modal.tsx b/src/components/atoms/Modal.tsx deleted file mode 100644 index 2f2b737..0000000 --- a/src/components/atoms/Modal.tsx +++ /dev/null @@ -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 ( -
-
e.stopPropagation()} - > - {(title || showCloseButton) && ( -
- {title &&

{title}

} - {showCloseButton && ( - - )} -
- )} -
{children}
-
-
- ) -} diff --git a/src/components/atoms/Notification.tsx b/src/components/atoms/Notification.tsx deleted file mode 100644 index 452ae42..0000000 --- a/src/components/atoms/Notification.tsx +++ /dev/null @@ -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 ( -
- -
-

{title}

- {message &&

{message}

} -
- {onClose && ( - - )} -
- ) -} diff --git a/src/components/atoms/NumberInput.tsx b/src/components/atoms/NumberInput.tsx deleted file mode 100644 index e8ed56f..0000000 --- a/src/components/atoms/NumberInput.tsx +++ /dev/null @@ -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) => { - const newValue = parseFloat(e.target.value) - if (!isNaN(newValue)) { - if ((min === undefined || newValue >= min) && (max === undefined || newValue <= max)) { - onChange(newValue) - } - } - } - - return ( -
- {label && ( - - )} -
- - - -
-
- ) -} diff --git a/src/components/atoms/TabIcon.tsx b/src/components/atoms/TabIcon.tsx deleted file mode 100644 index 53e5f82..0000000 --- a/src/components/atoms/TabIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -interface TabIconProps { - icon: React.ReactNode - variant?: 'default' | 'gradient' -} - -export function TabIcon({ icon, variant = 'default' }: TabIconProps) { - if (variant === 'gradient') { - return ( -
- {icon} -
- ) - } - - return <>{icon} -} diff --git a/src/components/atoms/TipsCard.tsx b/src/components/atoms/TipsCard.tsx deleted file mode 100644 index eaa6794..0000000 --- a/src/components/atoms/TipsCard.tsx +++ /dev/null @@ -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 ( - - - - - Quick Tips - - - - {visibleTips.map((tip, index) => ( -

• {tip.message}

- ))} -
-
- ) -} diff --git a/src/components/atoms/index.ts b/src/components/atoms/index.ts index 9549a67..a74292e 100644 --- a/src/components/atoms/index.ts +++ b/src/components/atoms/index.ts @@ -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' diff --git a/src/components/json-definitions/binding-indicator.json b/src/components/json-definitions/binding-indicator.json new file mode 100644 index 0000000..9623774 --- /dev/null +++ b/src/components/json-definitions/binding-indicator.json @@ -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; })()" + } + } + } + ] + } + ] + } + ] +} diff --git a/src/components/json-definitions/button-group.json b/src/components/json-definitions/button-group.json new file mode 100644 index 0000000..a5019f6 --- /dev/null +++ b/src/components/json-definitions/button-group.json @@ -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" + } + } + ] +} diff --git a/src/components/json-definitions/chip.json b/src/components/json-definitions/chip.json new file mode 100644 index 0000000..62f056b --- /dev/null +++ b/src/components/json-definitions/chip.json @@ -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'" + } + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/circular-progress.json b/src/components/json-definitions/circular-progress.json new file mode 100644 index 0000000..5033780 --- /dev/null +++ b/src/components/json-definitions/circular-progress.json @@ -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" + } + } + ] +} diff --git a/src/components/json-definitions/code.json b/src/components/json-definitions/code.json new file mode 100644 index 0000000..7ad235e --- /dev/null +++ b/src/components/json-definitions/code.json @@ -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" + } + } + ] +} diff --git a/src/components/json-definitions/command-palette.json b/src/components/json-definitions/command-palette.json new file mode 100644 index 0000000..c08f6ad --- /dev/null +++ b/src/components/json-definitions/command-palette.json @@ -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" + } + } + ] + } + } + } + ] + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/completion-card.json b/src/components/json-definitions/completion-card.json new file mode 100644 index 0000000..e43c280 --- /dev/null +++ b/src/components/json-definitions/completion-card.json @@ -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" + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/component-palette-item.json b/src/components/json-definitions/component-palette-item.json new file mode 100644 index 0000000..d2740ac --- /dev/null +++ b/src/components/json-definitions/component-palette-item.json @@ -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'" + } + } + } + ] +} diff --git a/src/components/json-definitions/confirm-button.json b/src/components/json-definitions/confirm-button.json new file mode 100644 index 0000000..3b3d5d6 --- /dev/null +++ b/src/components/json-definitions/confirm-button.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/data-source-badge.json b/src/components/json-definitions/data-source-badge.json new file mode 100644 index 0000000..0ce85d3 --- /dev/null +++ b/src/components/json-definitions/data-source-badge.json @@ -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'" + } + } + } + ] +} diff --git a/src/components/json-definitions/date-picker.json b/src/components/json-definitions/date-picker.json new file mode 100644 index 0000000..0de38e7 --- /dev/null +++ b/src/components/json-definitions/date-picker.json @@ -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" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/detail-row.json b/src/components/json-definitions/detail-row.json new file mode 100644 index 0000000..0ff9a85 --- /dev/null +++ b/src/components/json-definitions/detail-row.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/divider.json b/src/components/json-definitions/divider.json new file mode 100644 index 0000000..34ff2cd --- /dev/null +++ b/src/components/json-definitions/divider.json @@ -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()" + } + } +} diff --git a/src/components/json-definitions/empty-message.json b/src/components/json-definitions/empty-message.json new file mode 100644 index 0000000..b868219 --- /dev/null +++ b/src/components/json-definitions/empty-message.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/error-badge.json b/src/components/json-definitions/error-badge.json new file mode 100644 index 0000000..a6b20b9 --- /dev/null +++ b/src/components/json-definitions/error-badge.json @@ -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" + } + } +} diff --git a/src/components/json-definitions/file-icon.json b/src/components/json-definitions/file-icon.json new file mode 100644 index 0000000..669b387 --- /dev/null +++ b/src/components/json-definitions/file-icon.json @@ -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 || ''" + } + } +} diff --git a/src/components/json-definitions/glow-card.json b/src/components/json-definitions/glow-card.json new file mode 100644 index 0000000..e346e12 --- /dev/null +++ b/src/components/json-definitions/glow-card.json @@ -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" + } +} diff --git a/src/components/json-definitions/helper-text.json b/src/components/json-definitions/helper-text.json new file mode 100644 index 0000000..15ebfd4 --- /dev/null +++ b/src/components/json-definitions/helper-text.json @@ -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" + } + } +} diff --git a/src/components/json-definitions/info-box.json b/src/components/json-definitions/info-box.json new file mode 100644 index 0000000..bc3a197 --- /dev/null +++ b/src/components/json-definitions/info-box.json @@ -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: '', warning: '', success: '', error: '' }; 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" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/key-value.json b/src/components/json-definitions/key-value.json new file mode 100644 index 0000000..87e3a58 --- /dev/null +++ b/src/components/json-definitions/key-value.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/list-item.json b/src/components/json-definitions/list-item.json new file mode 100644 index 0000000..8a106e7 --- /dev/null +++ b/src/components/json-definitions/list-item.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/list.json b/src/components/json-definitions/list.json new file mode 100644 index 0000000..b3d2374 --- /dev/null +++ b/src/components/json-definitions/list.json @@ -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})` } } }] }))" + } +} diff --git a/src/components/json-definitions/live-indicator.json b/src/components/json-definitions/live-indicator.json new file mode 100644 index 0000000..ed1658a --- /dev/null +++ b/src/components/json-definitions/live-indicator.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/loading-spinner.json b/src/components/json-definitions/loading-spinner.json new file mode 100644 index 0000000..4760935 --- /dev/null +++ b/src/components/json-definitions/loading-spinner.json @@ -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'" + } + } +} diff --git a/src/components/json-definitions/loading-state.json b/src/components/json-definitions/loading-state.json new file mode 100644 index 0000000..4664e56 --- /dev/null +++ b/src/components/json-definitions/loading-state.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/metric-display.json b/src/components/json-definitions/metric-display.json new file mode 100644 index 0000000..af439ce --- /dev/null +++ b/src/components/json-definitions/metric-display.json @@ -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" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/modal.json b/src/components/json-definitions/modal.json new file mode 100644 index 0000000..17d4016 --- /dev/null +++ b/src/components/json-definitions/modal.json @@ -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" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/notification.json b/src/components/json-definitions/notification.json new file mode 100644 index 0000000..010df8a --- /dev/null +++ b/src/components/json-definitions/notification.json @@ -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": "'✕'" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/number-input.json b/src/components/json-definitions/number-input.json new file mode 100644 index 0000000..594845a --- /dev/null +++ b/src/components/json-definitions/number-input.json @@ -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": "'+'" + } + } + } + ] + } + ] + } + ] +} diff --git a/src/components/json-definitions/page-header.json b/src/components/json-definitions/page-header.json new file mode 100644 index 0000000..951479d --- /dev/null +++ b/src/components/json-definitions/page-header.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/progress-bar.json b/src/components/json-definitions/progress-bar.json new file mode 100644 index 0000000..75d093e --- /dev/null +++ b/src/components/json-definitions/progress-bar.json @@ -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" + } + } + } + ] +} diff --git a/src/components/json-definitions/pulse.json b/src/components/json-definitions/pulse.json new file mode 100644 index 0000000..e94365e --- /dev/null +++ b/src/components/json-definitions/pulse.json @@ -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]}`" + } + } + } + ] +} diff --git a/src/components/json-definitions/quick-action-button.json b/src/components/json-definitions/quick-action-button.json new file mode 100644 index 0000000..7d206f6 --- /dev/null +++ b/src/components/json-definitions/quick-action-button.json @@ -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" + } + } + } + ] + } + ] +} diff --git a/src/components/json-definitions/search-input.json b/src/components/json-definitions/search-input.json new file mode 100644 index 0000000..f1514dd --- /dev/null +++ b/src/components/json-definitions/search-input.json @@ -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 } }" + } + } + } + ] +} diff --git a/src/components/json-definitions/seed-data-status.json b/src/components/json-definitions/seed-data-status.json new file mode 100644 index 0000000..ad38c79 --- /dev/null +++ b/src/components/json-definitions/seed-data-status.json @@ -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" + } + } + } + ] + } + ] + } + ] + } + ] +} diff --git a/src/components/json-definitions/sparkle.json b/src/components/json-definitions/sparkle.json new file mode 100644 index 0000000..1891b89 --- /dev/null +++ b/src/components/json-definitions/sparkle.json @@ -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()" + } + } +} diff --git a/src/components/json-definitions/tab-icon.json b/src/components/json-definitions/tab-icon.json new file mode 100644 index 0000000..e7843e7 --- /dev/null +++ b/src/components/json-definitions/tab-icon.json @@ -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" + } + ] +} diff --git a/src/components/json-definitions/tips-card.json b/src/components/json-definitions/tips-card.json new file mode 100644 index 0000000..e1abfc7 --- /dev/null +++ b/src/components/json-definitions/tips-card.json @@ -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}" + } + } + ] + } + ] + } + ] +} diff --git a/src/lib/json-ui/interfaces/binding-indicator.ts b/src/lib/json-ui/interfaces/binding-indicator.ts new file mode 100644 index 0000000..45e88a5 --- /dev/null +++ b/src/lib/json-ui/interfaces/binding-indicator.ts @@ -0,0 +1,5 @@ +export interface BindingIndicatorProps { + sourceId: string + path?: string + className?: string +} diff --git a/src/lib/json-ui/interfaces/button-group.ts b/src/lib/json-ui/interfaces/button-group.ts new file mode 100644 index 0000000..d5b120e --- /dev/null +++ b/src/lib/json-ui/interfaces/button-group.ts @@ -0,0 +1,7 @@ +import { ReactNode } from 'react' + +export interface ButtonGroupProps { + children: ReactNode + orientation?: 'horizontal' | 'vertical' + className?: string +} diff --git a/src/lib/json-ui/interfaces/chip.ts b/src/lib/json-ui/interfaces/chip.ts new file mode 100644 index 0000000..9825434 --- /dev/null +++ b/src/lib/json-ui/interfaces/chip.ts @@ -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 +} diff --git a/src/lib/json-ui/interfaces/circular-progress.ts b/src/lib/json-ui/interfaces/circular-progress.ts new file mode 100644 index 0000000..8f28381 --- /dev/null +++ b/src/lib/json-ui/interfaces/circular-progress.ts @@ -0,0 +1,8 @@ +export interface CircularProgressProps { + value: number + max?: number + size?: 'sm' | 'md' | 'lg' | 'xl' + showLabel?: boolean + strokeWidth?: number + className?: string +} diff --git a/src/lib/json-ui/interfaces/code.ts b/src/lib/json-ui/interfaces/code.ts new file mode 100644 index 0000000..6d04ac8 --- /dev/null +++ b/src/lib/json-ui/interfaces/code.ts @@ -0,0 +1,7 @@ +import { ReactNode } from 'react' + +export interface CodeProps { + children: ReactNode + inline?: boolean + className?: string +} diff --git a/src/lib/json-ui/interfaces/command-palette.ts b/src/lib/json-ui/interfaces/command-palette.ts new file mode 100644 index 0000000..bb70b0f --- /dev/null +++ b/src/lib/json-ui/interfaces/command-palette.ts @@ -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[] + }[] +} diff --git a/src/lib/json-ui/interfaces/completion-card.ts b/src/lib/json-ui/interfaces/completion-card.ts new file mode 100644 index 0000000..3c71473 --- /dev/null +++ b/src/lib/json-ui/interfaces/completion-card.ts @@ -0,0 +1,5 @@ +export interface CompletionCardProps { + completionScore: number + completionMessage: string + isReadyToExport: boolean +} diff --git a/src/lib/json-ui/interfaces/component-palette-item.ts b/src/lib/json-ui/interfaces/component-palette-item.ts new file mode 100644 index 0000000..0c35645 --- /dev/null +++ b/src/lib/json-ui/interfaces/component-palette-item.ts @@ -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 +} diff --git a/src/lib/json-ui/interfaces/confirm-button.ts b/src/lib/json-ui/interfaces/confirm-button.ts new file mode 100644 index 0000000..d31197d --- /dev/null +++ b/src/lib/json-ui/interfaces/confirm-button.ts @@ -0,0 +1,8 @@ +import { ButtonHTMLAttributes, ReactNode } from 'react' + +export interface ConfirmButtonProps extends Omit, 'onClick'> { + onConfirm: () => void | Promise + confirmText?: string + isLoading?: boolean + children: ReactNode +} diff --git a/src/lib/json-ui/interfaces/data-source-badge.ts b/src/lib/json-ui/interfaces/data-source-badge.ts new file mode 100644 index 0000000..1a5ccfa --- /dev/null +++ b/src/lib/json-ui/interfaces/data-source-badge.ts @@ -0,0 +1,6 @@ +import { DataSourceType } from '@/types/json-ui' + +export interface DataSourceBadgeProps { + type: DataSourceType + className?: string +} diff --git a/src/lib/json-ui/interfaces/data-table.ts b/src/lib/json-ui/interfaces/data-table.ts new file mode 100644 index 0000000..b5daf63 --- /dev/null +++ b/src/lib/json-ui/interfaces/data-table.ts @@ -0,0 +1,17 @@ +import { ReactNode } from 'react' + +export interface Column { + key: string + header: string | ReactNode + cell?: (item: T) => ReactNode + sortable?: boolean + width?: string +} + +export interface DataTableProps { + data: T[] + columns: Column[] + onRowClick?: (item: T) => void + emptyMessage?: string + className?: string +} diff --git a/src/lib/json-ui/interfaces/date-picker.ts b/src/lib/json-ui/interfaces/date-picker.ts new file mode 100644 index 0000000..e76bf34 --- /dev/null +++ b/src/lib/json-ui/interfaces/date-picker.ts @@ -0,0 +1,7 @@ +export interface DatePickerProps { + value?: Date + onChange: (date: Date | undefined) => void + placeholder?: string + disabled?: boolean + className?: string +} diff --git a/src/lib/json-ui/interfaces/detail-row.ts b/src/lib/json-ui/interfaces/detail-row.ts new file mode 100644 index 0000000..cda9881 --- /dev/null +++ b/src/lib/json-ui/interfaces/detail-row.ts @@ -0,0 +1,5 @@ +export interface DetailRowProps { + icon: React.ReactNode + label: string + value: number +} diff --git a/src/lib/json-ui/interfaces/divider.ts b/src/lib/json-ui/interfaces/divider.ts new file mode 100644 index 0000000..be58979 --- /dev/null +++ b/src/lib/json-ui/interfaces/divider.ts @@ -0,0 +1,5 @@ +export interface DividerProps { + orientation?: 'horizontal' | 'vertical' + className?: string + decorative?: boolean +} diff --git a/src/lib/json-ui/interfaces/empty-message.ts b/src/lib/json-ui/interfaces/empty-message.ts new file mode 100644 index 0000000..41a22d1 --- /dev/null +++ b/src/lib/json-ui/interfaces/empty-message.ts @@ -0,0 +1,10 @@ +export interface EmptyMessageProps { + icon?: React.ReactNode + title: string + description?: string + action?: { + label: string + onClick: () => void + } + className?: string +} diff --git a/src/lib/json-ui/interfaces/error-badge.ts b/src/lib/json-ui/interfaces/error-badge.ts new file mode 100644 index 0000000..8868052 --- /dev/null +++ b/src/lib/json-ui/interfaces/error-badge.ts @@ -0,0 +1,5 @@ +export interface ErrorBadgeProps { + count: number + variant?: 'default' | 'destructive' + size?: 'sm' | 'md' +} diff --git a/src/lib/json-ui/interfaces/file-icon.ts b/src/lib/json-ui/interfaces/file-icon.ts new file mode 100644 index 0000000..409daad --- /dev/null +++ b/src/lib/json-ui/interfaces/file-icon.ts @@ -0,0 +1,6 @@ +export interface FileIconProps { + type?: 'code' | 'json' | 'plus' + size?: number + weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone' + className?: string +} diff --git a/src/lib/json-ui/interfaces/glow-card.ts b/src/lib/json-ui/interfaces/glow-card.ts new file mode 100644 index 0000000..2336b96 --- /dev/null +++ b/src/lib/json-ui/interfaces/glow-card.ts @@ -0,0 +1,7 @@ +export interface GlowCardProps { + children: React.ReactNode + glowColor?: 'primary' | 'accent' | 'success' | 'warning' | 'error' + intensity?: 'low' | 'medium' | 'high' + className?: string + onClick?: () => void +} diff --git a/src/lib/json-ui/interfaces/helper-text.ts b/src/lib/json-ui/interfaces/helper-text.ts new file mode 100644 index 0000000..e0d5e0a --- /dev/null +++ b/src/lib/json-ui/interfaces/helper-text.ts @@ -0,0 +1,5 @@ +export interface HelperTextProps { + children: React.ReactNode + variant?: 'default' | 'error' | 'success' + className?: string +} diff --git a/src/lib/json-ui/interfaces/index.ts b/src/lib/json-ui/interfaces/index.ts index 7384c9a..dd2b2ec 100644 --- a/src/lib/json-ui/interfaces/index.ts +++ b/src/lib/json-ui/interfaces/index.ts @@ -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' diff --git a/src/lib/json-ui/interfaces/info-box.ts b/src/lib/json-ui/interfaces/info-box.ts new file mode 100644 index 0000000..f4dbdc9 --- /dev/null +++ b/src/lib/json-ui/interfaces/info-box.ts @@ -0,0 +1,6 @@ +export interface InfoBoxProps { + type?: 'info' | 'warning' | 'success' | 'error' + title?: string + children: React.ReactNode + className?: string +} diff --git a/src/lib/json-ui/interfaces/key-value.ts b/src/lib/json-ui/interfaces/key-value.ts new file mode 100644 index 0000000..6c9c465 --- /dev/null +++ b/src/lib/json-ui/interfaces/key-value.ts @@ -0,0 +1,8 @@ +export interface KeyValueProps { + label: string + value: React.ReactNode + orientation?: 'horizontal' | 'vertical' + className?: string + labelClassName?: string + valueClassName?: string +} diff --git a/src/lib/json-ui/interfaces/list-item.ts b/src/lib/json-ui/interfaces/list-item.ts new file mode 100644 index 0000000..f4cff2c --- /dev/null +++ b/src/lib/json-ui/interfaces/list-item.ts @@ -0,0 +1,8 @@ +export interface ListItemProps { + icon?: React.ReactNode + children: React.ReactNode + onClick?: () => void + active?: boolean + className?: string + endContent?: React.ReactNode +} diff --git a/src/lib/json-ui/interfaces/list.ts b/src/lib/json-ui/interfaces/list.ts new file mode 100644 index 0000000..0f919cc --- /dev/null +++ b/src/lib/json-ui/interfaces/list.ts @@ -0,0 +1,7 @@ +export interface ListProps { + items: T[] + renderItem: (item: T, index: number) => React.ReactNode + emptyMessage?: string + className?: string + itemClassName?: string +} diff --git a/src/lib/json-ui/interfaces/live-indicator.ts b/src/lib/json-ui/interfaces/live-indicator.ts new file mode 100644 index 0000000..23d0673 --- /dev/null +++ b/src/lib/json-ui/interfaces/live-indicator.ts @@ -0,0 +1,6 @@ +export interface LiveIndicatorProps { + label?: string + showLabel?: boolean + size?: 'sm' | 'md' | 'lg' + className?: string +} diff --git a/src/lib/json-ui/interfaces/loading-spinner.ts b/src/lib/json-ui/interfaces/loading-spinner.ts new file mode 100644 index 0000000..518ce1e --- /dev/null +++ b/src/lib/json-ui/interfaces/loading-spinner.ts @@ -0,0 +1,4 @@ +export interface LoadingSpinnerProps { + size?: 'sm' | 'md' | 'lg' + className?: string +} diff --git a/src/lib/json-ui/interfaces/loading-state.ts b/src/lib/json-ui/interfaces/loading-state.ts new file mode 100644 index 0000000..78b7a44 --- /dev/null +++ b/src/lib/json-ui/interfaces/loading-state.ts @@ -0,0 +1,5 @@ +export interface LoadingStateProps { + message?: string + size?: 'sm' | 'md' | 'lg' + className?: string +} diff --git a/src/lib/json-ui/interfaces/metric-display.ts b/src/lib/json-ui/interfaces/metric-display.ts new file mode 100644 index 0000000..df41a99 --- /dev/null +++ b/src/lib/json-ui/interfaces/metric-display.ts @@ -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' +} diff --git a/src/lib/json-ui/interfaces/modal.ts b/src/lib/json-ui/interfaces/modal.ts new file mode 100644 index 0000000..546d4d3 --- /dev/null +++ b/src/lib/json-ui/interfaces/modal.ts @@ -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 +} diff --git a/src/lib/json-ui/interfaces/notification.ts b/src/lib/json-ui/interfaces/notification.ts new file mode 100644 index 0000000..ec7c40a --- /dev/null +++ b/src/lib/json-ui/interfaces/notification.ts @@ -0,0 +1,7 @@ +export interface NotificationProps { + type: 'info' | 'success' | 'warning' | 'error' + title: string + message?: string + onClose?: () => void + className?: string +} diff --git a/src/lib/json-ui/interfaces/number-input.ts b/src/lib/json-ui/interfaces/number-input.ts new file mode 100644 index 0000000..cad3677 --- /dev/null +++ b/src/lib/json-ui/interfaces/number-input.ts @@ -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 +} diff --git a/src/lib/json-ui/interfaces/page-header.ts b/src/lib/json-ui/interfaces/page-header.ts new file mode 100644 index 0000000..114b732 --- /dev/null +++ b/src/lib/json-ui/interfaces/page-header.ts @@ -0,0 +1,6 @@ +export interface PageHeaderProps { + title: string + description?: string + actions?: React.ReactNode + className?: string +} diff --git a/src/lib/json-ui/interfaces/progress-bar.ts b/src/lib/json-ui/interfaces/progress-bar.ts new file mode 100644 index 0000000..ab70b4e --- /dev/null +++ b/src/lib/json-ui/interfaces/progress-bar.ts @@ -0,0 +1,8 @@ +export interface ProgressBarProps { + value: number + max?: number + size?: 'sm' | 'md' | 'lg' + variant?: 'default' | 'accent' | 'destructive' + showLabel?: boolean + className?: string +} diff --git a/src/lib/json-ui/interfaces/pulse.ts b/src/lib/json-ui/interfaces/pulse.ts new file mode 100644 index 0000000..5ab1f5c --- /dev/null +++ b/src/lib/json-ui/interfaces/pulse.ts @@ -0,0 +1,6 @@ +export interface PulseProps { + variant?: 'primary' | 'accent' | 'success' | 'warning' | 'error' + size?: 'sm' | 'md' | 'lg' + speed?: 'slow' | 'normal' | 'fast' + className?: string +} diff --git a/src/lib/json-ui/interfaces/quick-action-button.ts b/src/lib/json-ui/interfaces/quick-action-button.ts new file mode 100644 index 0000000..899e1bf --- /dev/null +++ b/src/lib/json-ui/interfaces/quick-action-button.ts @@ -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 +} diff --git a/src/lib/json-ui/interfaces/search-input.ts b/src/lib/json-ui/interfaces/search-input.ts new file mode 100644 index 0000000..568dbcc --- /dev/null +++ b/src/lib/json-ui/interfaces/search-input.ts @@ -0,0 +1,7 @@ +export interface SearchInputProps { + value: string + onChange: (value: string) => void + placeholder?: string + onClear?: () => void + className?: string +} diff --git a/src/lib/json-ui/interfaces/seed-data-status.ts b/src/lib/json-ui/interfaces/seed-data-status.ts new file mode 100644 index 0000000..d80ef62 --- /dev/null +++ b/src/lib/json-ui/interfaces/seed-data-status.ts @@ -0,0 +1,3 @@ +export interface SeedDataStatusProps { + className?: string +} diff --git a/src/lib/json-ui/interfaces/sparkle.ts b/src/lib/json-ui/interfaces/sparkle.ts new file mode 100644 index 0000000..63e488c --- /dev/null +++ b/src/lib/json-ui/interfaces/sparkle.ts @@ -0,0 +1,6 @@ +export interface SparkleProps { + variant?: 'default' | 'primary' | 'accent' | 'gold' + size?: number + animate?: boolean + className?: string +} diff --git a/src/lib/json-ui/interfaces/tab-icon.ts b/src/lib/json-ui/interfaces/tab-icon.ts new file mode 100644 index 0000000..c991d0f --- /dev/null +++ b/src/lib/json-ui/interfaces/tab-icon.ts @@ -0,0 +1,4 @@ +export interface TabIconProps { + icon: React.ReactNode + variant?: 'default' | 'gradient' +} diff --git a/src/lib/json-ui/interfaces/tips-card.ts b/src/lib/json-ui/interfaces/tips-card.ts new file mode 100644 index 0000000..1c4c1e0 --- /dev/null +++ b/src/lib/json-ui/interfaces/tips-card.ts @@ -0,0 +1,3 @@ +export interface TipsCardProps { + tips: Array<{ message: string; show: boolean }> +} diff --git a/src/lib/json-ui/json-components.ts b/src/lib/json-ui/json-components.ts index e7c6b80..869d88e 100644 --- a/src/lib/json-ui/json-components.ts +++ b/src/lib/json-ui/json-components.ts @@ -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(loadingFallbackDef) @@ -230,6 +270,19 @@ export const Timeline = createJsonComponent(timelineDef) export const Timestamp = createJsonComponent(timestampDef) export const Toggle = createJsonComponent(toggleDef) export const Tooltip = createJsonComponent(tooltipDef) +export const TabIcon = createJsonComponent(tabIconDef) +export const TipsCard = createJsonComponent(tipsCardDef) +export const InfoBox = createJsonComponent(infoBoxDef) +export const KeyValue = createJsonComponent(keyValueDef) +export const LiveIndicator = createJsonComponent(liveIndicatorDef) +export const List = createJsonComponent>(listDef) +export const ListItem = createJsonComponent(listItemDef) +export const LoadingSpinner = createJsonComponent(loadingSpinnerDef) +export const LoadingState = createJsonComponent(loadingStateDef) +export const MetricDisplay = createJsonComponent(metricDisplayDef) +export const Modal = createJsonComponent(modalDef) +export const Notification = createJsonComponent(notificationDef) +export const NumberInput = createJsonComponent(numberInputDef) // Create JSON components with hooks export const SaveIndicator = createJsonComponentWithHooks(saveIndicatorDef, {