mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
feat: Migrate 4 key organisms to JSON architecture
Migrated EmptyCanvasState, SchemaCodeViewer, ToolbarActions, and AppHeader from TSX to JSON-based components. These are display-focused organisms with no complex state management requirements. Changes: - Create JSON definitions for 4 organisms in src/components/json-definitions/ - Create TypeScript interfaces in src/lib/json-ui/interfaces/ - Add exports to src/lib/json-ui/json-components.ts - Update interfaces/index.ts to export new interfaces - Registry entries already marked as jsonCompatible: true All organisms are pure JSON components (no custom hooks needed): - EmptyCanvasState: Display component with optional action buttons - SchemaCodeViewer: Display component showing JSON schema with tabs - ToolbarActions: Flex container with conditional toolbar buttons - AppHeader: Complex header layout with multiple sub-components Build passing with no errors. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
146
src/components/json-definitions/app-header.json
Normal file
146
src/components/json-definitions/app-header.json
Normal file
@@ -0,0 +1,146 @@
|
||||
{
|
||||
"id": "app-header",
|
||||
"type": "header",
|
||||
"bindings": {
|
||||
"className": { "value": "border-b border-border bg-card" }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "header-stack",
|
||||
"type": "Stack",
|
||||
"props": {
|
||||
"direction": "vertical",
|
||||
"spacing": "none"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "header-top",
|
||||
"type": "Stack",
|
||||
"props": {
|
||||
"className": "px-4 sm:px-6 py-3 sm:py-4"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "header-flex",
|
||||
"type": "Flex",
|
||||
"props": {
|
||||
"justify": "between",
|
||||
"align": "center",
|
||||
"gap": "sm"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "header-left",
|
||||
"type": "Flex",
|
||||
"props": {
|
||||
"align": "center",
|
||||
"gap": "sm",
|
||||
"className": "flex-1 min-w-0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "sidebar-trigger",
|
||||
"type": "SidebarTrigger"
|
||||
},
|
||||
{
|
||||
"id": "app-branding",
|
||||
"type": "AppBranding"
|
||||
},
|
||||
{
|
||||
"id": "save-indicator",
|
||||
"type": "SaveIndicator",
|
||||
"bindings": {
|
||||
"lastSaved": { "source": "lastSaved" }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "header-right",
|
||||
"type": "Flex",
|
||||
"props": {
|
||||
"gap": "xs",
|
||||
"shrink": true,
|
||||
"className": "shrink-0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "project-manager",
|
||||
"type": "ProjectManager",
|
||||
"bindings": {
|
||||
"currentProject": { "source": "currentProject" }
|
||||
},
|
||||
"events": {
|
||||
"onProjectLoad": {
|
||||
"type": "callback",
|
||||
"name": "onProjectLoad"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "toolbar-actions",
|
||||
"type": "ToolbarActions",
|
||||
"bindings": {
|
||||
"errorCount": { "source": "errorCount" },
|
||||
"showErrorButton": {
|
||||
"source": "featureToggles,errorCount",
|
||||
"transform": "data && data.featureToggles && data.featureToggles.errorRepair && data.errorCount > 0"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"onSearch": {
|
||||
"type": "callback",
|
||||
"name": "onSearch"
|
||||
},
|
||||
"onShowShortcuts": {
|
||||
"type": "callback",
|
||||
"name": "onShowShortcuts"
|
||||
},
|
||||
"onGenerateAI": {
|
||||
"type": "callback",
|
||||
"name": "onGenerateAI"
|
||||
},
|
||||
"onExport": {
|
||||
"type": "callback",
|
||||
"name": "onExport"
|
||||
},
|
||||
"onPreview": {
|
||||
"type": "callback",
|
||||
"name": "onPreview"
|
||||
},
|
||||
"onShowErrors": {
|
||||
"type": "callback",
|
||||
"name": "onShowErrors"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "separator",
|
||||
"type": "Separator",
|
||||
"props": {
|
||||
"className": "opacity-50"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "header-bottom",
|
||||
"type": "Stack",
|
||||
"props": {
|
||||
"className": "px-4 sm:px-6 py-2"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "breadcrumb",
|
||||
"type": "Breadcrumb"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
94
src/components/json-definitions/empty-canvas-state.json
Normal file
94
src/components/json-definitions/empty-canvas-state.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"id": "empty-canvas-state",
|
||||
"type": "Stack",
|
||||
"bindings": {
|
||||
"direction": { "value": "vertical" },
|
||||
"spacing": { "value": "none" },
|
||||
"className": { "value": "h-full flex flex-col items-center justify-center p-8 bg-muted/20" }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "empty-state",
|
||||
"type": "EmptyState",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Folder",
|
||||
"size": 64,
|
||||
"weight": "duotone"
|
||||
}
|
||||
},
|
||||
"title": "Empty Canvas",
|
||||
"description": "Start building your UI by dragging components from the left panel, or import an existing schema."
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "actions-container",
|
||||
"type": "Stack",
|
||||
"props": {
|
||||
"direction": "horizontal",
|
||||
"spacing": "md",
|
||||
"className": "mt-4"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "import-button",
|
||||
"type": "ActionButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Folder",
|
||||
"size": 16
|
||||
}
|
||||
},
|
||||
"label": "Import Schema",
|
||||
"variant": "outline"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onImportSchema"
|
||||
}
|
||||
},
|
||||
"bindings": {
|
||||
"hidden": {
|
||||
"source": "!onImportSchema",
|
||||
"transform": "!data"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "add-button",
|
||||
"type": "ActionButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Plus",
|
||||
"size": 16
|
||||
}
|
||||
},
|
||||
"label": "Add Component",
|
||||
"variant": "default"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onAddFirstComponent"
|
||||
}
|
||||
},
|
||||
"bindings": {
|
||||
"hidden": {
|
||||
"source": "!onAddFirstComponent",
|
||||
"transform": "!data"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
118
src/components/json-definitions/schema-code-viewer.json
Normal file
118
src/components/json-definitions/schema-code-viewer.json
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"id": "schema-code-viewer",
|
||||
"type": "Stack",
|
||||
"bindings": {
|
||||
"direction": { "value": "vertical" },
|
||||
"spacing": { "value": "none" },
|
||||
"className": { "value": "h-full flex flex-col bg-card" }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "panel-header",
|
||||
"type": "PanelHeader",
|
||||
"props": {
|
||||
"title": "Schema Output",
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Code",
|
||||
"size": 20,
|
||||
"weight": "duotone"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tabs",
|
||||
"type": "Tabs",
|
||||
"props": {
|
||||
"defaultValue": "json",
|
||||
"className": "flex-1 flex flex-col"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "tabs-list",
|
||||
"type": "TabsList",
|
||||
"props": {
|
||||
"className": "w-full justify-start px-4 pt-2"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "json-trigger",
|
||||
"type": "TabsTrigger",
|
||||
"props": {
|
||||
"value": "json",
|
||||
"children": "JSON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "preview-trigger",
|
||||
"type": "TabsTrigger",
|
||||
"props": {
|
||||
"value": "preview",
|
||||
"children": "Preview"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "json-content",
|
||||
"type": "TabsContent",
|
||||
"props": {
|
||||
"value": "json",
|
||||
"className": "flex-1 m-0 mt-2"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "scroll-area",
|
||||
"type": "ScrollArea",
|
||||
"props": {
|
||||
"className": "h-full"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "code-block",
|
||||
"type": "Code",
|
||||
"bindings": {
|
||||
"children": {
|
||||
"source": "schema",
|
||||
"transform": "data ? JSON.stringify(data, null, 2) : ''"
|
||||
},
|
||||
"className": { "value": "p-4 text-xs font-mono text-foreground" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "preview-content",
|
||||
"type": "TabsContent",
|
||||
"props": {
|
||||
"value": "preview",
|
||||
"className": "flex-1 m-0 mt-2"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "preview-text",
|
||||
"type": "Stack",
|
||||
"props": {
|
||||
"className": "p-4"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "preview-message",
|
||||
"type": "Text",
|
||||
"props": {
|
||||
"variant": "muted",
|
||||
"children": "Live preview coming soon"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
172
src/components/json-definitions/toolbar-actions.json
Normal file
172
src/components/json-definitions/toolbar-actions.json
Normal file
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"id": "toolbar-actions",
|
||||
"type": "Flex",
|
||||
"bindings": {
|
||||
"gap": { "value": "xs" },
|
||||
"shrink": { "value": true },
|
||||
"className": { "value": "shrink-0" }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "search-button",
|
||||
"type": "ToolbarButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "MagnifyingGlass",
|
||||
"size": 18
|
||||
}
|
||||
},
|
||||
"label": "Search (Ctrl+K)",
|
||||
"data-search-trigger": true
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onSearch"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "error-button-wrapper",
|
||||
"type": "Stack",
|
||||
"bindings": {
|
||||
"hidden": {
|
||||
"source": "showErrorButton,errorCount",
|
||||
"transform": "!(data.showErrorButton && data.errorCount > 0)"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "error-button",
|
||||
"type": "ToolbarButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Wrench",
|
||||
"size": 18
|
||||
}
|
||||
},
|
||||
"variant": "outline",
|
||||
"className": "border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground relative"
|
||||
},
|
||||
"bindings": {
|
||||
"label": {
|
||||
"source": "errorCount",
|
||||
"transform": "data ? `${data} ${data === 1 ? 'Error' : 'Errors'}` : 'Errors'"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onShowErrors"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "error-badge",
|
||||
"type": "ErrorBadge",
|
||||
"bindings": {
|
||||
"count": { "source": "errorCount" }
|
||||
},
|
||||
"props": {
|
||||
"size": "sm"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "preview-button",
|
||||
"type": "ToolbarButton",
|
||||
"bindings": {
|
||||
"hidden": {
|
||||
"source": "!onPreview",
|
||||
"transform": "!data"
|
||||
}
|
||||
},
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Eye",
|
||||
"size": 18
|
||||
}
|
||||
},
|
||||
"label": "Preview (Ctrl+P)",
|
||||
"variant": "outline"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onPreview"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "shortcuts-button",
|
||||
"type": "ToolbarButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Keyboard",
|
||||
"size": 18
|
||||
}
|
||||
},
|
||||
"label": "Keyboard Shortcuts (Ctrl+/)",
|
||||
"variant": "ghost",
|
||||
"className": "hidden sm:flex"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onShowShortcuts"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ai-button",
|
||||
"type": "ToolbarButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Sparkle",
|
||||
"size": 18,
|
||||
"weight": "duotone"
|
||||
}
|
||||
},
|
||||
"label": "AI Generate (Ctrl+Shift+G)"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onGenerateAI"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export-button",
|
||||
"type": "ToolbarButton",
|
||||
"props": {
|
||||
"icon": {
|
||||
"type": "Icon",
|
||||
"props": {
|
||||
"name": "Download",
|
||||
"size": 18
|
||||
}
|
||||
},
|
||||
"label": "Export Project (Ctrl+E)",
|
||||
"variant": "default"
|
||||
},
|
||||
"events": {
|
||||
"onClick": {
|
||||
"type": "callback",
|
||||
"name": "onExport"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
17
src/lib/json-ui/interfaces/app-header.ts
Normal file
17
src/lib/json-ui/interfaces/app-header.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { FeatureToggles, Project } from '@/types/project'
|
||||
|
||||
export interface AppHeaderProps {
|
||||
activeTab: string
|
||||
onTabChange: (tab: string) => void
|
||||
featureToggles: FeatureToggles
|
||||
errorCount: number
|
||||
lastSaved: number | null
|
||||
currentProject: Project
|
||||
onProjectLoad: (project: Project) => void
|
||||
onSearch: () => void
|
||||
onShowShortcuts: () => void
|
||||
onGenerateAI: () => void
|
||||
onExport: () => void
|
||||
onPreview?: () => void
|
||||
onShowErrors: () => void
|
||||
}
|
||||
4
src/lib/json-ui/interfaces/empty-canvas-state.ts
Normal file
4
src/lib/json-ui/interfaces/empty-canvas-state.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface EmptyCanvasStateProps {
|
||||
onAddFirstComponent?: () => void
|
||||
onImportSchema?: () => void
|
||||
}
|
||||
@@ -122,3 +122,7 @@ export * from './data-source-card'
|
||||
export * from './code-explanation-dialog'
|
||||
export * from './component-palette'
|
||||
export * from './canvas-renderer'
|
||||
export * from './empty-canvas-state'
|
||||
export * from './schema-code-viewer'
|
||||
export * from './toolbar-actions'
|
||||
export * from './app-header'
|
||||
|
||||
6
src/lib/json-ui/interfaces/schema-code-viewer.ts
Normal file
6
src/lib/json-ui/interfaces/schema-code-viewer.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { UIComponent } from '@/types/json-ui'
|
||||
|
||||
export interface SchemaCodeViewerProps {
|
||||
components: UIComponent[]
|
||||
schema: any
|
||||
}
|
||||
10
src/lib/json-ui/interfaces/toolbar-actions.ts
Normal file
10
src/lib/json-ui/interfaces/toolbar-actions.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface ToolbarActionsProps {
|
||||
onSearch: () => void
|
||||
onShowShortcuts: () => void
|
||||
onGenerateAI: () => void
|
||||
onExport: () => void
|
||||
onPreview?: () => void
|
||||
onShowErrors?: () => void
|
||||
errorCount?: number
|
||||
showErrorButton?: boolean
|
||||
}
|
||||
@@ -131,6 +131,10 @@ import type {
|
||||
CodeExplanationDialogProps,
|
||||
ComponentPaletteProps,
|
||||
CanvasRendererProps,
|
||||
EmptyCanvasStateProps,
|
||||
SchemaCodeViewerProps,
|
||||
ToolbarActionsProps,
|
||||
AppHeaderProps,
|
||||
} from './interfaces'
|
||||
|
||||
// Import JSON definitions
|
||||
@@ -258,6 +262,10 @@ import dataSourceCardDef from '@/components/json-definitions/data-source-card.js
|
||||
import codeExplanationDialogDef from '@/components/json-definitions/code-explanation-dialog.json'
|
||||
import componentPaletteDef from '@/components/json-definitions/component-palette.json'
|
||||
import canvasRendererDef from '@/components/json-definitions/canvas-renderer.json'
|
||||
import emptyCanvasStateDef from '@/components/json-definitions/empty-canvas-state.json'
|
||||
import schemaCodeViewerDef from '@/components/json-definitions/schema-code-viewer.json'
|
||||
import toolbarActionsDef from '@/components/json-definitions/toolbar-actions.json'
|
||||
import appHeaderDef from '@/components/json-definitions/app-header.json'
|
||||
|
||||
// Create pure JSON components (no hooks)
|
||||
export const BindingIndicator = createJsonComponent<BindingIndicatorProps>(bindingIndicatorDef)
|
||||
@@ -363,6 +371,10 @@ export const DataSourceCard = createJsonComponent<DataSourceCardProps>(dataSourc
|
||||
export const CodeExplanationDialog = createJsonComponent<CodeExplanationDialogProps>(codeExplanationDialogDef)
|
||||
export const ComponentPalette = createJsonComponent<ComponentPaletteProps>(componentPaletteDef)
|
||||
export const CanvasRenderer = createJsonComponent<CanvasRendererProps>(canvasRendererDef)
|
||||
export const EmptyCanvasState = createJsonComponent<EmptyCanvasStateProps>(emptyCanvasStateDef)
|
||||
export const SchemaCodeViewer = createJsonComponent<SchemaCodeViewerProps>(schemaCodeViewerDef)
|
||||
export const ToolbarActions = createJsonComponent<ToolbarActionsProps>(toolbarActionsDef)
|
||||
export const AppHeader = createJsonComponent<AppHeaderProps>(appHeaderDef)
|
||||
|
||||
// Create JSON components with hooks
|
||||
export const SaveIndicator = createJsonComponentWithHooks<SaveIndicatorProps>(saveIndicatorDef, {
|
||||
|
||||
Reference in New Issue
Block a user