Compare commits

...

6 Commits

Author SHA1 Message Date
dependabot[bot]
9a09979250 Bump react-resizable-panels from 2.1.9 to 4.4.1
Bumps [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) from 2.1.9 to 4.4.1.
- [Release notes](https://github.com/bvaughn/react-resizable-panels/releases)
- [Changelog](https://github.com/bvaughn/react-resizable-panels/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bvaughn/react-resizable-panels/compare/2.1.9...4.4.1)

---
updated-dependencies:
- dependency-name: react-resizable-panels
  dependency-version: 4.4.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-21 02:15:57 +00:00
4bbfc1d577 fix: update component imports to use JSON-based exports and fix missing re-exports
- Updated DisplayTab.tsx to use Breadcrumb instead of BreadcrumbNav
- Updated atoms/index.ts to re-export JSON components that were previously unavailable from atoms module (Notification, ProgressBar, Pulse, etc.)
- Fixed build errors from missing component exports by consolidating exports from json-components module

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-21 02:12:23 +00:00
8f905d6e5e feat: migrate remaining atoms batch 4 - PageHeader through Sparkle (12 components)
- Created JSON interface files: PageHeader, ProgressBar, Pulse, QuickActionButton, SearchInput, SeedDataStatus, Sparkle
- Created JSON definitions for all 12 components with full bindings
- Updated json-components.ts with imports and exports for new components
- Updated interfaces/index.ts to export new interface types
- Updated json-components-registry.json marking components as migrated and jsonCompatible
- Deleted 12 legacy TSX files from src/components/atoms/
- Updated atom imports where the deleted components were used

This completes the migration of the second batch of atoms, moving stateless UI components to JSON-driven architecture.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-21 02:06:37 +00:00
8899983d2a feat: migrate remaining atoms batch 2 - DatePicker through HelperText (12 components)
Migrated the following 12 atoms to JSON:
- DatePicker
- DetailRow
- Divider
- Drawer
- EmptyMessage
- ErrorBadge
- FileIcon
- Form
- FormField
- GlowCard
- Heading
- HelperText

Created JSON definitions in src/components/json-definitions/
Created TypeScript interfaces in src/lib/json-ui/interfaces/
Exported all 12 components from src/lib/json-ui/json-components.ts
Updated src/lib/json-ui/interfaces/index.ts with new exports
2026-01-21 02:06:04 +00:00
c33d4a0bdb fix: update atoms/index.ts to export TabIcon and TipsCard from JSON components 2026-01-21 01:59:15 +00:00
a6a3ba2042 feat: migrate remaining atoms batch 3 - InfoBox through NumberInput (12 components) 2026-01-21 01:58:10 +00:00
114 changed files with 3022 additions and 1356 deletions

View File

@@ -2,7 +2,7 @@
"$schema": "./schemas/json-components-registry-schema.json",
"version": "2.0.0",
"description": "Registry of all components in the application",
"lastUpdated": "2026-01-18T13:03:47Z",
"lastUpdated": "2026-01-21T01:57:14.374Z",
"categories": {
"layout": "Layout and container components",
"input": "Form inputs and interactive controls",
@@ -348,7 +348,8 @@
"canHaveChildren": true,
"description": "BindingIndicator component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "breadcrumb",
@@ -460,7 +461,8 @@
"canHaveChildren": true,
"description": "Group of related buttons",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "buttonVariants",
@@ -903,7 +905,8 @@
"canHaveChildren": true,
"description": "Compact element for tags or selections",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "CircularProgress",
@@ -912,7 +915,8 @@
"canHaveChildren": false,
"description": "Circular progress indicator",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "Clock",
@@ -933,7 +937,8 @@
"canHaveChildren": true,
"description": "Inline or block code display",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "CodeEditor",
@@ -1039,7 +1044,8 @@
"canHaveChildren": true,
"description": "Command search and execution",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "CompletionCard",
@@ -1048,7 +1054,8 @@
"canHaveChildren": true,
"description": "CompletionCard component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ComponentBindingDialog",
@@ -1091,7 +1098,8 @@
"canHaveChildren": true,
"description": "ComponentPaletteItem component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ComponentTree",
@@ -1169,7 +1177,8 @@
"canHaveChildren": true,
"description": "ConfirmButton component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ConflictResolutionPage",
@@ -1286,7 +1295,8 @@
"canHaveChildren": true,
"description": "DataSourceBadge component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "DataSourceCard",
@@ -1339,7 +1349,8 @@
"canHaveChildren": false,
"description": "Advanced data table with sorting and filtering",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true
},
{
"type": "DatePicker",
@@ -2556,12 +2567,9 @@
"category": "custom",
"canHaveChildren": true,
"description": "PageHeader component",
"status": "supported",
"status": "migrated",
"source": "atoms",
"load": {
"path": "@/components/atoms/PageHeader.tsx",
"export": "BasicPageHeader"
}
"jsonCompatible": true
},
{
"type": "PageHeaderContent",
@@ -2716,8 +2724,9 @@
"category": "display",
"canHaveChildren": false,
"description": "Linear progress bar",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "ProjectDashboard",
@@ -2762,8 +2771,9 @@
"category": "custom",
"canHaveChildren": true,
"description": "Pulse component",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "PWASettings",
@@ -2789,8 +2799,9 @@
"category": "input",
"canHaveChildren": true,
"description": "QuickActionButton component",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "Radio",
@@ -2798,8 +2809,9 @@
"category": "input",
"canHaveChildren": false,
"description": "Radio button selection",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "radio-group",
@@ -2831,7 +2843,7 @@
"category": "input",
"canHaveChildren": true,
"description": "RangeSlider component",
"status": "supported",
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
@@ -2841,7 +2853,7 @@
"category": "custom",
"canHaveChildren": true,
"description": "Star rating component",
"status": "supported",
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
@@ -3037,7 +3049,7 @@
"category": "custom",
"canHaveChildren": true,
"description": "Scrollable container area",
"status": "supported",
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
@@ -3079,12 +3091,9 @@
"category": "custom",
"canHaveChildren": false,
"description": "Search input with icon",
"status": "supported",
"status": "migrated",
"source": "atoms",
"load": {
"path": "@/components/atoms/SearchInput.tsx",
"export": "BasicSearchInput"
}
"jsonCompatible": true
},
{
"type": "section",
@@ -3134,8 +3143,9 @@
"category": "feedback",
"canHaveChildren": true,
"description": "SeedDataStatus component",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "Select",
@@ -3143,7 +3153,7 @@
"category": "input",
"canHaveChildren": false,
"description": "Dropdown select control",
"status": "supported",
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
@@ -3360,8 +3370,9 @@
"category": "custom",
"canHaveChildren": true,
"description": "Sparkle component",
"status": "supported",
"source": "atoms"
"status": "migrated",
"source": "atoms",
"jsonCompatible": true
},
{
"type": "Spinner",
@@ -3549,7 +3560,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 +3896,12 @@
"canHaveChildren": true,
"description": "TipsCard component",
"status": "supported",
"source": "atoms"
"source": "atoms",
"jsonCompatible": true,
"metadata": {
"conversionDate": "2026-01-21",
"autoGenerated": true
}
},
{
"type": "toggle",

124
package-lock.json generated
View File

@@ -63,7 +63,7 @@
"react-error-boundary": "^6.0.0",
"react-hook-form": "^7.54.2",
"react-redux": "^9.2.0",
"react-resizable-panels": "^2.1.7",
"react-resizable-panels": "^4.4.1",
"react-router-dom": "^7.12.0",
"reactflow": "^11.11.4",
"recharts": "^2.15.1",
@@ -3785,6 +3785,60 @@
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
"version": "1.6.0",
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.1.0",
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
"version": "1.6.0",
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
"version": "1.1.0",
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
"version": "1.0.7",
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.5.0",
"@emnapi/runtime": "^1.5.0",
"@tybys/wasm-util": "^0.10.1"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
"version": "2.8.1",
"inBundle": true,
"license": "0BSD",
"optional": true
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.17",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz",
@@ -4044,6 +4098,66 @@
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
"version": "1.7.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.1.0",
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
"version": "1.7.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
"version": "1.1.0",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.0",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1",
"@tybys/wasm-util": "^0.10.1"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
"version": "2.8.1",
"dev": true,
"inBundle": true,
"license": "0BSD",
"optional": true
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.18",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
@@ -6644,11 +6758,13 @@
}
},
"node_modules/react-resizable-panels": {
"version": "2.1.9",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.4.1.tgz",
"integrity": "sha512-dpM9oI6rGlAq7VYDeafSRA1JmkJv8aNuKySR+tZLQQLfaeqTnQLSM52EcoI/QdowzsjVUCk6jViKS0xHWITVRQ==",
"license": "MIT",
"peerDependencies": {
"react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/react-router": {

View File

@@ -86,7 +86,7 @@
"react-error-boundary": "^6.0.0",
"react-hook-form": "^7.54.2",
"react-redux": "^9.2.0",
"react-resizable-panels": "^2.1.7",
"react-resizable-panels": "^4.4.1",
"react-router-dom": "^7.12.0",
"reactflow": "^11.11.4",
"recharts": "^2.15.1",

View File

@@ -1,5 +1,6 @@
import { useState } from 'react'
import { BasicPageHeader, Container, Stack } from '@/components/atoms'
import { Container, Stack } from '@/components/atoms'
import { PageHeader } from '@/lib/json-ui/json-components'
import data from '@/data/atomic-library-showcase.json'
import { AvatarsUserElementsSection } from '@/components/atomic-library/AvatarsUserElementsSection'
import { BadgesIndicatorsSection } from '@/components/atomic-library/BadgesIndicatorsSection'
@@ -26,7 +27,7 @@ export function AtomicLibraryShowcase() {
return (
<Container size="xl" className="py-8">
<BasicPageHeader title={pageHeader.title} description={pageHeader.description} />
<PageHeader title={pageHeader.title} description={pageHeader.description} />
<Stack direction="vertical" spacing="xl">
<ButtonsActionsSection content={sections.buttonsActions} />

View File

@@ -1,12 +1,11 @@
import displayCopy from '@/data/atomic-showcase/display.json'
import {
Avatar,
BreadcrumbNav,
Breadcrumb,
Card,
ColorSwatch,
Divider,
Heading,
Rating,
Stack,
StatusBadge,
Stepper,
@@ -15,7 +14,7 @@ import {
Timeline,
Timestamp,
} from '@/components/atoms'
import { Accordion } from '@/lib/json-ui/json-components'
import { Accordion, Rating } from '@/lib/json-ui/json-components'
type DisplayTabProps = {
ratingValue: number
@@ -112,7 +111,7 @@ export function DisplayTab({ ratingValue, selectedColor, onRatingChange, onColor
<Stack spacing="md">
<Heading level={2}>{displayCopy.navigationTitle}</Heading>
<Divider />
<BreadcrumbNav
<Breadcrumb
items={displayCopy.breadcrumbs.map((item, index) => ({
label: item.label,
onClick: index < displayCopy.breadcrumbs.length - 1 ? () => {} : undefined,

View File

@@ -2,15 +2,11 @@ import { Envelope, Heart, Share, Trash } from '@phosphor-icons/react'
import formsCopy from '@/data/atomic-showcase/forms.json'
import {
ActionButton,
BasicSearchInput,
Card,
Checkbox,
Divider,
Heading,
IconButton,
RadioGroup,
Select,
Slider,
Stack,
TextArea,
Toggle,
@@ -20,6 +16,10 @@ import {
CopyButton,
FileUpload,
PasswordInput,
SearchInput,
Slider,
Select,
RadioGroup,
} from '@/lib/json-ui/json-components'
type FormsTabProps = {
@@ -83,7 +83,7 @@ export function FormsTab(props: FormsTabProps) {
helperText={formsCopy.email.helperText}
/>
<PasswordInput label={formsCopy.password.label} value={passwordValue} onChange={onPasswordChange} helperText={formsCopy.password.helperText} />
<BasicSearchInput value={searchValue} onChange={onSearchChange} placeholder={formsCopy.search.placeholder} />
<SearchInput value={searchValue} onChange={onSearchChange} placeholder={formsCopy.search.placeholder} />
<TextArea
label={formsCopy.textArea.label}
placeholder={formsCopy.textArea.placeholder}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,24 +0,0 @@
import { cn } from '@/lib/utils'
interface BasicPageHeaderProps {
title: string
description?: string
actions?: React.ReactNode
className?: string
}
export function BasicPageHeader({ title, description, actions, className }: BasicPageHeaderProps) {
return (
<div className={cn('flex items-start justify-between mb-6', className)}>
<div className="space-y-1">
<h1 className="text-3xl font-bold tracking-tight">{title}</h1>
{description && (
<p className="text-muted-foreground">{description}</p>
)}
</div>
{actions && (
<div className="flex gap-2">{actions}</div>
)}
</div>
)
}

View File

@@ -1,62 +0,0 @@
import { cn } from '@/lib/utils'
interface ProgressBarProps {
value: number
max?: number
size?: 'sm' | 'md' | 'lg'
variant?: 'default' | 'accent' | 'destructive'
showLabel?: boolean
className?: string
}
const sizeClasses = {
sm: 'h-1',
md: 'h-2',
lg: 'h-3',
}
const variantClasses = {
default: 'bg-primary',
accent: 'bg-accent',
destructive: 'bg-destructive',
}
export function ProgressBar({
value,
max = 100,
size = 'md',
variant = 'default',
showLabel = false,
className
}: ProgressBarProps) {
const percentage = Math.min(Math.max((value / max) * 100, 0), 100)
return (
<div className="w-full">
<div
className={cn(
'relative w-full bg-secondary rounded-full overflow-hidden',
sizeClasses[size],
className
)}
role="progressbar"
aria-valuenow={value}
aria-valuemin={0}
aria-valuemax={max}
>
<div
className={cn(
'h-full transition-all duration-300 ease-out',
variantClasses[variant]
)}
style={{ width: `${percentage}%` }}
/>
</div>
{showLabel && (
<span className="text-xs text-muted-foreground mt-1 block">
{Math.round(percentage)}%
</span>
)}
</div>
)
}

View File

@@ -1,56 +0,0 @@
import { cn } from '@/lib/utils'
interface PulseProps {
variant?: 'primary' | 'accent' | 'success' | 'warning' | 'error'
size?: 'sm' | 'md' | 'lg'
speed?: 'slow' | 'normal' | 'fast'
className?: string
}
export function Pulse({
variant = 'primary',
size = 'md',
speed = 'normal',
className,
}: PulseProps) {
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 (
<div className={cn('relative inline-flex', className)}>
<span
className={cn(
'inline-flex rounded-full opacity-75',
sizeClasses[size],
variantClasses[variant],
speedClasses[speed]
)}
/>
<span
className={cn(
'absolute inline-flex rounded-full opacity-75',
sizeClasses[size],
variantClasses[variant],
speedClasses[speed]
)}
/>
</div>
)
}

View File

@@ -1,61 +0,0 @@
import { Card } from '@/components/ui/card'
import { cn } from '@/lib/utils'
import { ReactNode } from 'react'
interface QuickActionButtonProps {
icon: ReactNode
label: string
description?: string
onClick: () => void
variant?: 'default' | 'primary' | 'accent' | 'muted'
disabled?: boolean
className?: string
}
export function QuickActionButton({
icon,
label,
description,
onClick,
variant = 'default',
disabled,
className,
}: QuickActionButtonProps) {
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 iconColorClasses = {
default: 'text-foreground',
primary: 'text-primary',
accent: 'text-accent',
muted: 'text-muted-foreground',
}
return (
<Card
onClick={disabled ? undefined : onClick}
className={cn(
'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',
variantClasses[variant],
disabled && 'opacity-50 cursor-not-allowed hover:scale-100',
className
)}
>
<div className={cn('text-4xl', iconColorClasses[variant])}>
{icon}
</div>
<div className="space-y-1">
<h3 className="font-semibold text-foreground">{label}</h3>
{description && (
<p className="text-sm text-muted-foreground">{description}</p>
)}
</div>
</Card>
)
}

View File

@@ -1,69 +0,0 @@
import { cn } from '@/lib/utils'
interface RadioOption {
value: string
label: string
disabled?: boolean
}
interface RadioGroupProps {
options: RadioOption[]
value: string
onChange: (value: string) => void
name: string
orientation?: 'horizontal' | 'vertical'
className?: string
}
export function RadioGroup({
options,
value,
onChange,
name,
orientation = 'vertical',
className
}: RadioGroupProps) {
return (
<div
role="radiogroup"
className={cn(
'flex gap-3',
orientation === 'vertical' ? 'flex-col' : 'flex-row flex-wrap',
className
)}
>
{options.map((option) => (
<label
key={option.value}
className={cn(
'flex items-center gap-2 cursor-pointer',
option.disabled && 'opacity-50 cursor-not-allowed'
)}
>
<input
type="radio"
name={name}
value={option.value}
checked={value === option.value}
onChange={(e) => !option.disabled && onChange(e.target.value)}
disabled={option.disabled}
className="sr-only"
/>
<span
className={cn(
'w-4 h-4 rounded-full border-2 flex items-center justify-center transition-colors',
value === option.value
? 'border-primary bg-primary'
: 'border-input bg-background'
)}
>
{value === option.value && (
<span className="w-2 h-2 rounded-full bg-primary-foreground" />
)}
</span>
<span className="text-sm font-medium">{option.label}</span>
</label>
))}
</div>
)
}

View File

@@ -1,47 +0,0 @@
import { Slider } from '@/components/ui/slider'
import { cn } from '@/lib/utils'
interface RangeSliderProps {
value: [number, number]
onChange: (value: [number, number]) => void
min?: number
max?: number
step?: number
label?: string
showValue?: boolean
className?: string
}
export function RangeSlider({
value,
onChange,
min = 0,
max = 100,
step = 1,
label,
showValue = true,
className,
}: RangeSliderProps) {
return (
<div className={cn('space-y-2', className)}>
{(label || showValue) && (
<div className="flex items-center justify-between">
{label && <span className="text-sm font-medium">{label}</span>}
{showValue && (
<span className="text-sm text-muted-foreground">
{value[0]} - {value[1]}
</span>
)}
</div>
)}
<Slider
value={value}
onValueChange={onChange as any}
min={min}
max={max}
step={step}
minStepsBetweenThumbs={1}
/>
</div>
)
}

View File

@@ -1,71 +0,0 @@
import { Star } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
interface RatingProps {
value: number
onChange?: (value: number) => void
max?: number
size?: 'sm' | 'md' | 'lg'
readonly?: boolean
showValue?: boolean
className?: string
}
export function Rating({
value,
onChange,
max = 5,
size = 'md',
readonly = false,
showValue = false,
className
}: RatingProps) {
const sizeStyles = {
sm: 16,
md: 20,
lg: 24,
}
const iconSize = sizeStyles[size]
return (
<div className={cn('flex items-center gap-2', className)}>
<div className="flex items-center gap-0.5">
{Array.from({ length: max }, (_, index) => {
const starValue = index + 1
const isFilled = starValue <= value
const isHalfFilled = starValue - 0.5 === value
return (
<button
key={index}
type="button"
onClick={() => !readonly && onChange?.(starValue)}
disabled={readonly}
className={cn(
'transition-colors',
!readonly && 'cursor-pointer hover:scale-110',
readonly && 'cursor-default'
)}
aria-label={`Rate ${starValue} out of ${max}`}
>
<Star
size={iconSize}
weight={isFilled ? 'fill' : 'regular'}
className={cn(
'transition-colors',
isFilled ? 'text-accent fill-accent' : 'text-muted'
)}
/>
</button>
)
})}
</div>
{showValue && (
<span className="text-sm font-medium text-muted-foreground">
{value.toFixed(1)} / {max}
</span>
)}
</div>
)
}

View File

@@ -1,35 +0,0 @@
import { ReactNode } from 'react'
import { cn } from '@/lib/utils'
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
interface ScrollAreaProps {
children: ReactNode
className?: string
maxHeight?: string | number
}
export function ScrollArea({ children, className, maxHeight }: ScrollAreaProps) {
return (
<ScrollAreaPrimitive.Root
className={cn('relative overflow-hidden', className)}
style={{ maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight }}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollAreaPrimitive.Scrollbar
className="flex touch-none select-none transition-colors p-0.5 bg-transparent hover:bg-muted"
orientation="vertical"
>
<ScrollAreaPrimitive.Thumb className="flex-1 bg-border rounded-full relative" />
</ScrollAreaPrimitive.Scrollbar>
<ScrollAreaPrimitive.Scrollbar
className="flex touch-none select-none transition-colors p-0.5 bg-transparent hover:bg-muted"
orientation="horizontal"
>
<ScrollAreaPrimitive.Thumb className="flex-1 bg-border rounded-full relative" />
</ScrollAreaPrimitive.Scrollbar>
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
)
}

View File

@@ -1,46 +0,0 @@
import { MagnifyingGlass, X } from '@phosphor-icons/react'
import { Input } from '@/lib/json-ui/json-components'
interface BasicSearchInputProps {
value: string
onChange: (value: string) => void
placeholder?: string
onClear?: () => void
className?: string
}
export function BasicSearchInput({
value,
onChange,
placeholder = 'Search...',
onClear,
className,
}: BasicSearchInputProps) {
const handleClear = () => {
onChange('')
onClear?.()
}
return (
<Input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className={className}
leftIcon={<MagnifyingGlass size={18} />}
rightIcon={
value && (
<button
type="button"
onClick={handleClear}
className="text-muted-foreground hover:text-foreground transition-colors"
aria-label="Clear search"
>
<X size={18} />
</button>
)
}
/>
)
}

View File

@@ -1,60 +0,0 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Database, Check, X } from '@phosphor-icons/react'
import seedDataConfig from '@/config/seed-data.json'
export function SeedDataStatus() {
const dataKeys = Object.keys(seedDataConfig)
const getDataCount = (key: string): number => {
const data = seedDataConfig[key as keyof typeof seedDataConfig]
return Array.isArray(data) ? data.length : 0
}
const getLabelForKey = (key: string): string => {
const labels: Record<string, string> = {
'project-files': 'Files',
'project-models': 'Models',
'project-components': 'Components',
'project-workflows': 'Workflows',
'project-lambdas': 'Lambdas',
'project-playwright-tests': 'Playwright Tests',
'project-storybook-stories': 'Storybook Stories',
'project-unit-tests': 'Unit Tests',
'project-component-trees': 'Component Trees',
}
return labels[key] || key
}
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Database size={20} weight="duotone" />
Seed Data Available
</CardTitle>
<CardDescription>
Pre-configured data ready to load from database
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
{dataKeys.map((key) => {
const count = getDataCount(key)
return (
<div
key={key}
className="flex items-center justify-between p-3 rounded-lg border border-border bg-muted/50"
>
<span className="text-sm font-medium">{getLabelForKey(key)}</span>
<Badge variant="secondary" className="ml-2">
{count}
</Badge>
</div>
)
})}
</div>
</CardContent>
</Card>
)
}

View File

@@ -1,69 +0,0 @@
import { cn } from '@/lib/utils'
interface SelectOption {
value: string
label: string
disabled?: boolean
}
interface SelectProps {
value: string
onChange: (value: string) => void
options: SelectOption[]
label?: string
placeholder?: string
error?: boolean
helperText?: string
disabled?: boolean
className?: string
}
export function Select({
value,
onChange,
options,
label,
placeholder = 'Select an option',
error,
helperText,
disabled,
className,
}: SelectProps) {
return (
<div className={cn('w-full', className)}>
{label && (
<label className="block text-sm font-medium mb-1.5 text-foreground">
{label}
</label>
)}
<select
value={value}
onChange={(e) => onChange(e.target.value)}
disabled={disabled}
className={cn(
'flex h-10 w-full rounded-md border bg-background px-3 py-2 text-sm',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
'disabled:cursor-not-allowed disabled:opacity-50',
'transition-colors',
error ? 'border-destructive focus-visible:ring-destructive' : 'border-input'
)}
>
{placeholder && (
<option value="" disabled>
{placeholder}
</option>
)}
{options.map((option) => (
<option key={option.value} value={option.value} disabled={option.disabled}>
{option.label}
</option>
))}
</select>
{helperText && (
<p className={cn('text-xs mt-1.5', error ? 'text-destructive' : 'text-muted-foreground')}>
{helperText}
</p>
)}
</div>
)
}

View File

@@ -1,35 +0,0 @@
import { cn } from '@/lib/utils'
import { Sparkle as SparkleIcon } from '@phosphor-icons/react'
interface SparkleProps {
variant?: 'default' | 'primary' | 'accent' | 'gold'
size?: number
animate?: boolean
className?: string
}
export function Sparkle({
variant = 'default',
size = 16,
animate = true,
className,
}: SparkleProps) {
const variantClasses = {
default: 'text-foreground',
primary: 'text-primary',
accent: 'text-accent',
gold: 'text-yellow-500',
}
return (
<SparkleIcon
size={size}
weight="fill"
className={cn(
variantClasses[variant],
animate && 'animate-pulse',
className
)}
/>
)
}

View File

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

View File

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

View File

@@ -1,108 +1,31 @@
// Auto-generated exports - DO NOT EDIT MANUALLY
export { ActionButton } from './ActionButton'
export { ActionCard } from './ActionCard'
export { ActionIcon } from './ActionIcon'
export { Alert } from './Alert'
export { AppLogo } from './AppLogo'
export { Avatar } from './Avatar'
export { AvatarGroup } from './AvatarGroup'
export { Badge } from './Badge'
export { BindingIndicator } from './BindingIndicator'
export { BreadcrumbNav as Breadcrumb, BreadcrumbNav } from './Breadcrumb'
export { Button } from './Button'
export { ButtonGroup } from './ButtonGroup'
export { Calendar } from './Calendar'
export { Card } from './Card'
export { Checkbox } from './Checkbox'
export { Chip } from './Chip'
export { CircularProgress } from './CircularProgress'
export { Code } from './Code'
// JSON-based atom imports
export { ActionButton, ActionCard, ActionIcon, Alert, AppLogo, Avatar, AvatarGroup, Badge, BindingIndicator, Breadcrumb, Button, ButtonGroup, Calendar, Card, Checkbox, Chip, CircularProgress, Code, CommandPalette, CompletionCard, ComponentPaletteItem, ConfirmButton, ContextMenu, DataSourceBadge, DataTable, DatePicker, DetailRow, Divider, Drawer, EmptyMessage, ErrorBadge, FileIcon, Form, GlowCard, Heading, HelperText, HoverCard, InputOTP, LiveIndicator, LoadingSpinner, LoadingState, Menu, MetricDisplay, Modal, Notification, NumberInput, ProgressBar, Pulse, QuickActionButton, RadioGroup, RangeSlider, Rating, ScrollArea, SearchInput, SeedDataStatus, Select, Separator, Skeleton, Slider, Sparkle, Spinner, StatusIcon, StepIndicator, Stepper, Switch, Table, Tabs, Tag, TextArea, TextGradient, TextHighlight, Timeline, Timestamp, Toggle, Tooltip } from '@/lib/json-ui/json-components'
export { ColorSwatch } from './ColorSwatch'
export { CommandPalette } from './CommandPalette'
export { CompletionCard } from './CompletionCard'
export { ConfirmButton } from './ConfirmButton'
export { ComponentTreeNode } from './ComponentTreeNode'
export { Container } from './Container'
export { ContextMenu } from './ContextMenu'
export type { ContextMenuItemType } from './ContextMenu'
export { CountBadge } from './CountBadge'
export { DataList } from './DataList'
export { DataSourceBadge } from './DataSourceBadge'
export { DataTable } from './DataTable'
export type { Column } from './DataTable'
export { DatePicker } from './DatePicker'
export { DetailRow } from './DetailRow'
export { Divider } from './Divider'
export { Dot } from './Dot'
export { Drawer } from './Drawer'
export { EmptyMessage } from './EmptyMessage'
export { EmptyState } from './EmptyState'
export { EmptyStateIcon } from './EmptyStateIcon'
export { ErrorBadge } from './ErrorBadge'
export { FileIcon } from './FileIcon'
export { Flex } from './Flex'
export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from './Form'
export { GlowCard } from './GlowCard'
export { Grid } from './Grid'
export { Heading } from './Heading'
export { HelperText } from './HelperText'
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'
export { Pulse } from './Pulse'
export { QuickActionButton } from './QuickActionButton'
export { RadioGroup as Radio, RadioGroup } from './Radio'
export { RangeSlider } from './RangeSlider'
export { Rating } from './Rating'
export { PropertyEditorField } from './PropertyEditorField'
export { ResponsiveGrid } from './ResponsiveGrid'
export { ScrollArea } from './ScrollArea'
export { BasicSearchInput as SearchInput, BasicSearchInput } from './SearchInput'
export { Section } from './Section'
export { SeedDataStatus } from './SeedDataStatus'
export { Select } from './Select'
export { Separator } from './Separator'
export { Skeleton } from './Skeleton'
export { Slider } from './Slider'
export { Spacer } from './Spacer'
export { Sparkle } from './Sparkle'
export { Spinner } from './Spinner'
export { Stack } from './Stack'
export { StatCard } from './StatCard'
export { StatusBadge } from './StatusBadge'
export { StatusIcon } from './StatusIcon'
export { StepIndicator } from './StepIndicator'
export { Stepper } from './Stepper'
export { Switch } from './Switch'
export { TabIcon } from './TabIcon'
export { Table } from './Table'
export { Tabs } from './Tabs'
export { Tag } from './Tag'
export { Text } from './Text'
export { TextArea } from './TextArea'
export { TextGradient } from './TextGradient'
export { TextHighlight } from './TextHighlight'
export { Timeline } from './Timeline'
export { Timestamp } from './Timestamp'
export { TipsCard } from './TipsCard'
export { Toggle } from './Toggle'
export { Tooltip } from './Tooltip'
export { TreeIcon } from './TreeIcon'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,143 @@
{
"id": "data-table-root",
"type": "div",
"bindings": {
"className": {
"source": "className",
"transform": "(() => { return 'rounded-md border ' + (data || ''); })()"
}
},
"children": [
{
"id": "data-table-wrapper",
"type": "Table",
"children": [
{
"id": "data-table-header",
"type": "TableHeader",
"children": [
{
"id": "data-table-header-row",
"type": "TableRow",
"children": [
{
"id": "data-table-header-columns",
"type": "forEach",
"bindings": {
"items": "columns",
"children": {
"id": "data-table-header-cell",
"type": "TableHead",
"bindings": {
"style": {
"transform": "(() => { return { width: data.width || 'auto' }; })()"
},
"className": {
"transform": "(() => { return data.sortable ? 'cursor-pointer select-none' : ''; })()"
}
},
"children": [
{
"id": "data-table-header-cell-content",
"bindings": {
"children": "header"
}
}
]
}
}
}
]
}
]
},
{
"id": "data-table-body",
"type": "TableBody",
"children": [
{
"id": "data-table-rows",
"type": "conditional",
"conditional": {
"if": {
"source": "data",
"transform": "data.length === 0"
}
},
"children": [
{
"id": "data-table-empty-row",
"type": "TableRow",
"children": [
{
"id": "data-table-empty-cell",
"type": "TableCell",
"bindings": {
"colSpan": {
"transform": "$props.columns.length"
}
},
"props": {
"className": "text-center py-8 text-muted-foreground"
},
"children": [
{
"id": "data-table-empty-message",
"bindings": {
"children": "emptyMessage"
}
}
]
}
]
}
]
},
{
"id": "data-table-data-rows",
"type": "forEach",
"bindings": {
"items": "data"
},
"children": {
"id": "data-table-data-row",
"type": "TableRow",
"bindings": {
"onClick": {
"transform": "(() => { return () => $props.onRowClick?.(data); })()"
},
"className": {
"transform": "$props.onRowClick ? 'cursor-pointer' : ''"
}
},
"children": [
{
"id": "data-table-data-cells",
"type": "forEach",
"bindings": {
"items": "columns"
},
"children": {
"id": "data-table-data-cell",
"type": "TableCell",
"children": [
{
"id": "data-table-data-cell-content",
"bindings": {
"children": {
"transform": "(() => { const column = data; const rowData = $root.data; const cellValue = rowData[column.key]; return column.cell ? column.cell(rowData) : cellValue; })()"
}
}
}
]
}
}
]
}
}
]
}
]
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
import { Stack, Container, TabIcon } from '@/components/atoms'
import { Stack, Container } from '@/components/atoms'
import { TabIcon } from '@/lib/json-ui/json-components'
import { tabInfo } from '@/lib/navigation-config'
interface PageHeaderProps {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,18 @@
export * from './binding-indicator'
export * from './button-group'
export * from './chip'
export * from './circular-progress'
export * from './code'
export * from './command-palette'
export * from './completion-card'
export * from './component-palette-item'
export * from './confirm-button'
export * from './data-source-badge'
export * from './data-table'
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 +55,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 +104,16 @@ export * from './timeline'
export * from './timestamp'
export * from './toggle'
export * from './tooltip'
export * from './tab-icon'
export * from './tips-card'
export * from './info-box'
export * from './key-value'
export * from './live-indicator'
export * from './list'
export * from './list-item'
export * from './loading-spinner'
export * from './loading-state'
export * from './metric-display'
export * from './modal'
export * from './notification'
export * from './number-input'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More