mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 21:54:56 +00:00
Compare commits
6 Commits
tier-1-boo
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a09979250 | ||
| 4bbfc1d577 | |||
| 8f905d6e5e | |||
| 8899983d2a | |||
| c33d4a0bdb | |||
| a6a3ba2042 |
@@ -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
124
package-lock.json
generated
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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}</>
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
74
src/components/json-definitions/binding-indicator.json
Normal file
74
src/components/json-definitions/binding-indicator.json
Normal 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; })()"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/button-group.json
Normal file
18
src/components/json-definitions/button-group.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
49
src/components/json-definitions/chip.json
Normal file
49
src/components/json-definitions/chip.json
Normal 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'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
111
src/components/json-definitions/circular-progress.json
Normal file
111
src/components/json-definitions/circular-progress.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/code.json
Normal file
18
src/components/json-definitions/code.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
85
src/components/json-definitions/command-palette.json
Normal file
85
src/components/json-definitions/command-palette.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
118
src/components/json-definitions/completion-card.json
Normal file
118
src/components/json-definitions/completion-card.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
55
src/components/json-definitions/component-palette-item.json
Normal file
55
src/components/json-definitions/component-palette-item.json
Normal 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'"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
22
src/components/json-definitions/confirm-button.json
Normal file
22
src/components/json-definitions/confirm-button.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
37
src/components/json-definitions/data-source-badge.json
Normal file
37
src/components/json-definitions/data-source-badge.json
Normal 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'"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
143
src/components/json-definitions/data-table.json
Normal file
143
src/components/json-definitions/data-table.json
Normal 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; })()"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
96
src/components/json-definitions/date-picker.json
Normal file
96
src/components/json-definitions/date-picker.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
66
src/components/json-definitions/detail-row.json
Normal file
66
src/components/json-definitions/detail-row.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/divider.json
Normal file
18
src/components/json-definitions/divider.json
Normal 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()"
|
||||
}
|
||||
}
|
||||
}
|
||||
84
src/components/json-definitions/empty-message.json
Normal file
84
src/components/json-definitions/empty-message.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
22
src/components/json-definitions/error-badge.json
Normal file
22
src/components/json-definitions/error-badge.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/components/json-definitions/file-icon.json
Normal file
22
src/components/json-definitions/file-icon.json
Normal 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 || ''"
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/components/json-definitions/glow-card.json
Normal file
18
src/components/json-definitions/glow-card.json
Normal 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"
|
||||
}
|
||||
}
|
||||
14
src/components/json-definitions/helper-text.json
Normal file
14
src/components/json-definitions/helper-text.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/components/json-definitions/info-box.json
Normal file
70
src/components/json-definitions/info-box.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
40
src/components/json-definitions/key-value.json
Normal file
40
src/components/json-definitions/key-value.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
74
src/components/json-definitions/list-item.json
Normal file
74
src/components/json-definitions/list-item.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/list.json
Normal file
18
src/components/json-definitions/list.json
Normal 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})` } } }] }))"
|
||||
}
|
||||
}
|
||||
62
src/components/json-definitions/live-indicator.json
Normal file
62
src/components/json-definitions/live-indicator.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/loading-spinner.json
Normal file
18
src/components/json-definitions/loading-spinner.json
Normal 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'"
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/components/json-definitions/loading-state.json
Normal file
40
src/components/json-definitions/loading-state.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
96
src/components/json-definitions/metric-display.json
Normal file
96
src/components/json-definitions/metric-display.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
122
src/components/json-definitions/modal.json
Normal file
122
src/components/json-definitions/modal.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
108
src/components/json-definitions/notification.json
Normal file
108
src/components/json-definitions/notification.json
Normal 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": "'✕'"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
148
src/components/json-definitions/number-input.json
Normal file
148
src/components/json-definitions/number-input.json
Normal 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": "'+'"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
74
src/components/json-definitions/page-header.json
Normal file
74
src/components/json-definitions/page-header.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
72
src/components/json-definitions/progress-bar.json
Normal file
72
src/components/json-definitions/progress-bar.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
32
src/components/json-definitions/pulse.json
Normal file
32
src/components/json-definitions/pulse.json
Normal 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]}`"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
74
src/components/json-definitions/quick-action-button.json
Normal file
74
src/components/json-definitions/quick-action-button.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
46
src/components/json-definitions/search-input.json
Normal file
46
src/components/json-definitions/search-input.json
Normal 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 } }"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
126
src/components/json-definitions/seed-data-status.json
Normal file
126
src/components/json-definitions/seed-data-status.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/components/json-definitions/sparkle.json
Normal file
18
src/components/json-definitions/sparkle.json
Normal 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()"
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/components/json-definitions/tab-icon.json
Normal file
16
src/components/json-definitions/tab-icon.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
61
src/components/json-definitions/tips-card.json
Normal file
61
src/components/json-definitions/tips-card.json
Normal 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}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
5
src/lib/json-ui/interfaces/binding-indicator.ts
Normal file
5
src/lib/json-ui/interfaces/binding-indicator.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface BindingIndicatorProps {
|
||||
sourceId: string
|
||||
path?: string
|
||||
className?: string
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/button-group.ts
Normal file
7
src/lib/json-ui/interfaces/button-group.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export interface ButtonGroupProps {
|
||||
children: ReactNode
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
className?: string
|
||||
}
|
||||
9
src/lib/json-ui/interfaces/chip.ts
Normal file
9
src/lib/json-ui/interfaces/chip.ts
Normal 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
|
||||
}
|
||||
8
src/lib/json-ui/interfaces/circular-progress.ts
Normal file
8
src/lib/json-ui/interfaces/circular-progress.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface CircularProgressProps {
|
||||
value: number
|
||||
max?: number
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl'
|
||||
showLabel?: boolean
|
||||
strokeWidth?: number
|
||||
className?: string
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/code.ts
Normal file
7
src/lib/json-ui/interfaces/code.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export interface CodeProps {
|
||||
children: ReactNode
|
||||
inline?: boolean
|
||||
className?: string
|
||||
}
|
||||
19
src/lib/json-ui/interfaces/command-palette.ts
Normal file
19
src/lib/json-ui/interfaces/command-palette.ts
Normal 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[]
|
||||
}[]
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/completion-card.ts
Normal file
5
src/lib/json-ui/interfaces/completion-card.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface CompletionCardProps {
|
||||
completionScore: number
|
||||
completionMessage: string
|
||||
isReadyToExport: boolean
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/component-palette-item.ts
Normal file
7
src/lib/json-ui/interfaces/component-palette-item.ts
Normal 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
|
||||
}
|
||||
8
src/lib/json-ui/interfaces/confirm-button.ts
Normal file
8
src/lib/json-ui/interfaces/confirm-button.ts
Normal 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
|
||||
}
|
||||
6
src/lib/json-ui/interfaces/data-source-badge.ts
Normal file
6
src/lib/json-ui/interfaces/data-source-badge.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { DataSourceType } from '@/types/json-ui'
|
||||
|
||||
export interface DataSourceBadgeProps {
|
||||
type: DataSourceType
|
||||
className?: string
|
||||
}
|
||||
17
src/lib/json-ui/interfaces/data-table.ts
Normal file
17
src/lib/json-ui/interfaces/data-table.ts
Normal 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
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/date-picker.ts
Normal file
7
src/lib/json-ui/interfaces/date-picker.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface DatePickerProps {
|
||||
value?: Date
|
||||
onChange: (date: Date | undefined) => void
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/detail-row.ts
Normal file
5
src/lib/json-ui/interfaces/detail-row.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface DetailRowProps {
|
||||
icon: React.ReactNode
|
||||
label: string
|
||||
value: number
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/divider.ts
Normal file
5
src/lib/json-ui/interfaces/divider.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface DividerProps {
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
className?: string
|
||||
decorative?: boolean
|
||||
}
|
||||
10
src/lib/json-ui/interfaces/empty-message.ts
Normal file
10
src/lib/json-ui/interfaces/empty-message.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface EmptyMessageProps {
|
||||
icon?: React.ReactNode
|
||||
title: string
|
||||
description?: string
|
||||
action?: {
|
||||
label: string
|
||||
onClick: () => void
|
||||
}
|
||||
className?: string
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/error-badge.ts
Normal file
5
src/lib/json-ui/interfaces/error-badge.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface ErrorBadgeProps {
|
||||
count: number
|
||||
variant?: 'default' | 'destructive'
|
||||
size?: 'sm' | 'md'
|
||||
}
|
||||
6
src/lib/json-ui/interfaces/file-icon.ts
Normal file
6
src/lib/json-ui/interfaces/file-icon.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface FileIconProps {
|
||||
type?: 'code' | 'json' | 'plus'
|
||||
size?: number
|
||||
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
|
||||
className?: string
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/glow-card.ts
Normal file
7
src/lib/json-ui/interfaces/glow-card.ts
Normal 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
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/helper-text.ts
Normal file
5
src/lib/json-ui/interfaces/helper-text.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface HelperTextProps {
|
||||
children: React.ReactNode
|
||||
variant?: 'default' | 'error' | 'success'
|
||||
className?: string
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
6
src/lib/json-ui/interfaces/info-box.ts
Normal file
6
src/lib/json-ui/interfaces/info-box.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface InfoBoxProps {
|
||||
type?: 'info' | 'warning' | 'success' | 'error'
|
||||
title?: string
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
8
src/lib/json-ui/interfaces/key-value.ts
Normal file
8
src/lib/json-ui/interfaces/key-value.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface KeyValueProps {
|
||||
label: string
|
||||
value: React.ReactNode
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
className?: string
|
||||
labelClassName?: string
|
||||
valueClassName?: string
|
||||
}
|
||||
8
src/lib/json-ui/interfaces/list-item.ts
Normal file
8
src/lib/json-ui/interfaces/list-item.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface ListItemProps {
|
||||
icon?: React.ReactNode
|
||||
children: React.ReactNode
|
||||
onClick?: () => void
|
||||
active?: boolean
|
||||
className?: string
|
||||
endContent?: React.ReactNode
|
||||
}
|
||||
7
src/lib/json-ui/interfaces/list.ts
Normal file
7
src/lib/json-ui/interfaces/list.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface ListProps<T> {
|
||||
items: T[]
|
||||
renderItem: (item: T, index: number) => React.ReactNode
|
||||
emptyMessage?: string
|
||||
className?: string
|
||||
itemClassName?: string
|
||||
}
|
||||
6
src/lib/json-ui/interfaces/live-indicator.ts
Normal file
6
src/lib/json-ui/interfaces/live-indicator.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface LiveIndicatorProps {
|
||||
label?: string
|
||||
showLabel?: boolean
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
className?: string
|
||||
}
|
||||
4
src/lib/json-ui/interfaces/loading-spinner.ts
Normal file
4
src/lib/json-ui/interfaces/loading-spinner.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface LoadingSpinnerProps {
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
className?: string
|
||||
}
|
||||
5
src/lib/json-ui/interfaces/loading-state.ts
Normal file
5
src/lib/json-ui/interfaces/loading-state.ts
Normal 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
Reference in New Issue
Block a user