diff --git a/component-registry.json b/component-registry.json
index 6187ba9..281ba4a 100644
--- a/component-registry.json
+++ b/component-registry.json
@@ -236,6 +236,15 @@
"category": "showcase",
"description": "JSON UI system demonstration"
},
+ {
+ "name": "JSONConversionShowcase",
+ "path": "@/components/JSONConversionShowcase",
+ "export": "JSONConversionShowcase",
+ "type": "feature",
+ "preload": false,
+ "category": "showcase",
+ "description": "JSON conversion showcase overview"
+ },
{
"name": "SchemaEditor",
"path": "@/components/SchemaEditorPage",
diff --git a/e2e/visual-regression.spec.ts b/e2e/visual-regression.spec.ts
new file mode 100644
index 0000000..9ba8ccc
--- /dev/null
+++ b/e2e/visual-regression.spec.ts
@@ -0,0 +1,16 @@
+import { test, expect } from '@playwright/test'
+
+test.describe('visual regression', () => {
+ test('json conversion showcase', async ({ page }) => {
+ await page.goto('/json-conversion-showcase')
+ await page.waitForLoadState('networkidle')
+ await page.waitForFunction(() => {
+ const root = document.querySelector('#root')
+ return root && root.textContent && root.textContent.length > 0
+ })
+ await page.addStyleTag({
+ content: '* { transition: none !important; animation: none !important; }',
+ })
+ await expect(page).toHaveScreenshot('json-conversion-showcase.png', { fullPage: true })
+ })
+})
diff --git a/src/components/JSONConversionShowcase.tsx b/src/components/JSONConversionShowcase.tsx
new file mode 100644
index 0000000..ec08a57
--- /dev/null
+++ b/src/components/JSONConversionShowcase.tsx
@@ -0,0 +1,9 @@
+import { PageRenderer } from '@/lib/json-ui/page-renderer'
+import conversionShowcaseSchema from '@/config/pages/json-conversion-showcase.json'
+import { PageSchema } from '@/types/json-ui'
+
+export function JSONConversionShowcase() {
+ const schema = conversionShowcaseSchema as PageSchema
+
+ return
+}
diff --git a/src/components/molecules/DataSourceEditorDialog.tsx b/src/components/molecules/DataSourceEditorDialog.tsx
index ceec274..20de4ae 100644
--- a/src/components/molecules/DataSourceEditorDialog.tsx
+++ b/src/components/molecules/DataSourceEditorDialog.tsx
@@ -6,9 +6,8 @@ import { DataSourceIdField } from '@/components/molecules/data-source-editor/Dat
import { KvSourceFields } from '@/components/molecules/data-source-editor/KvSourceFields'
import { StaticSourceFields } from '@/components/molecules/data-source-editor/StaticSourceFields'
import { ComputedSourceFields } from '@/components/molecules/data-source-editor/ComputedSourceFields'
-import { useDataSourceEditor } from '@/hooks/data/use-data-source-editor'
import dataSourceEditorCopy from '@/data/data-source-editor-dialog.json'
-import { useDataSourceEditor } from '@/hooks/use-data-source-editor'
+import { useDataSourceEditor } from '@/hooks/data/use-data-source-editor'
interface DataSourceEditorDialogProps {
open: boolean
diff --git a/src/config/default-pages.json b/src/config/default-pages.json
index 10ec0c9..e0cc663 100644
--- a/src/config/default-pages.json
+++ b/src/config/default-pages.json
@@ -235,6 +235,16 @@
"type": "single"
}
},
+ {
+ "id": "json-conversion-showcase",
+ "title": "JSON Conversion Showcase",
+ "description": "JSON conversion showcase overview",
+ "icon": "BookOpen",
+ "component": "JSONConversionShowcase",
+ "layout": {
+ "type": "single"
+ }
+ },
{
"id": "sass",
"title": "Sass Styles",
diff --git a/src/config/orchestration/component-registry.ts b/src/config/orchestration/component-registry.ts
index ff93835..cc58a1c 100644
--- a/src/config/orchestration/component-registry.ts
+++ b/src/config/orchestration/component-registry.ts
@@ -27,6 +27,7 @@ import { PWASettings } from '@/components/PWASettings'
import { FaviconDesigner } from '@/components/FaviconDesigner'
import { FeatureIdeaCloud } from '@/components/FeatureIdeaCloud'
import { JSONUIShowcase } from '@/components/JSONUIShowcase'
+import { JSONConversionShowcase } from '@/components/JSONConversionShowcase'
export const ComponentRegistry: Record> = {
Button,
@@ -61,6 +62,7 @@ export const ComponentRegistry: Record> = {
FaviconDesigner,
FeatureIdeaCloud,
JSONUIShowcase,
+ JSONConversionShowcase,
}
export function getComponent(name: string): ComponentType | null {
diff --git a/src/config/pages.json b/src/config/pages.json
index 99dc30b..6727b1b 100644
--- a/src/config/pages.json
+++ b/src/config/pages.json
@@ -365,6 +365,15 @@
"order": 22,
"props": {}
},
+ {
+ "id": "json-conversion-showcase",
+ "title": "JSON Conversion Showcase",
+ "icon": "BookOpen",
+ "component": "JSONConversionShowcase",
+ "enabled": true,
+ "order": 22.1,
+ "props": {}
+ },
{
"id": "schema-editor",
"title": "Schema Editor",
diff --git a/src/config/pages/json-conversion-showcase.json b/src/config/pages/json-conversion-showcase.json
new file mode 100644
index 0000000..c3acaf1
--- /dev/null
+++ b/src/config/pages/json-conversion-showcase.json
@@ -0,0 +1,341 @@
+{
+ "id": "json-conversion-showcase",
+ "name": "JSON Conversion Showcase",
+ "layout": {
+ "type": "single"
+ },
+ "dataSources": [
+ {
+ "id": "batches",
+ "type": "static",
+ "defaultValue": [
+ {
+ "title": "Phase 1",
+ "summary": "Models, Component Trees, Workflows",
+ "stats": [
+ { "label": "Pages Converted", "value": "3" },
+ { "label": "JSON Schema Lines", "value": "~900" },
+ { "label": "Code Reduction", "value": "~60%" }
+ ],
+ "pages": [
+ {
+ "name": "Models Designer",
+ "pageId": "models-json",
+ "schema": "src/config/pages/model-designer.json",
+ "dataStore": "app-models"
+ },
+ {
+ "name": "Component Trees Manager",
+ "pageId": "component-trees-json",
+ "schema": "src/config/pages/component-tree.json",
+ "dataStore": "app-component-trees"
+ },
+ {
+ "name": "Workflows Designer",
+ "pageId": "workflows-json",
+ "schema": "src/config/pages/workflow-designer.json",
+ "dataStore": "app-workflows"
+ }
+ ],
+ "seedHighlights": [
+ "3 model records (User, Post, Comment)",
+ "2 component trees (Dashboard, Profile)",
+ "3 workflow definitions (Registration, Processing, Payment)"
+ ]
+ },
+ {
+ "title": "Phase 2",
+ "summary": "Lambdas, Styling, Flask API",
+ "stats": [
+ { "label": "Pages Converted", "value": "3" },
+ { "label": "JSON Schema Lines", "value": "~2,100" },
+ { "label": "Seed Records", "value": "8" }
+ ],
+ "pages": [
+ {
+ "name": "Lambda Designer",
+ "pageId": "lambdas-json",
+ "schema": "src/config/pages/lambda-designer.json",
+ "dataStore": "app-lambdas"
+ },
+ {
+ "name": "Style Designer",
+ "pageId": "styling-json",
+ "schema": "src/config/pages/style-designer.json",
+ "dataStore": "app-theme"
+ },
+ {
+ "name": "Flask API Designer",
+ "pageId": "flask-json",
+ "schema": "src/config/pages/flask-designer.json",
+ "dataStore": "app-flask-config"
+ }
+ ],
+ "seedHighlights": [
+ "3 serverless functions seeded with triggers",
+ "2 theme variants with custom palettes",
+ "3 Flask blueprints covering 7 endpoints"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "patterns",
+ "type": "static",
+ "defaultValue": [
+ "Sidebar + detail layout pattern",
+ "Computed counters for live totals",
+ "KV-backed data sources for persistence",
+ "Declarative empty states and actions"
+ ]
+ }
+ ],
+ "components": [
+ {
+ "id": "root",
+ "type": "div",
+ "props": {
+ "className": "h-full overflow-auto bg-background p-6"
+ },
+ "children": [
+ {
+ "id": "header",
+ "type": "div",
+ "props": { "className": "space-y-2" },
+ "children": [
+ {
+ "id": "title",
+ "type": "Heading",
+ "props": {
+ "className": "text-3xl font-bold",
+ "children": "JSON Conversion Showcase"
+ }
+ },
+ {
+ "id": "subtitle",
+ "type": "Text",
+ "props": {
+ "className": "text-muted-foreground",
+ "children": "One-page overview of JSON conversion phases and their deliverables."
+ }
+ }
+ ]
+ },
+ {
+ "id": "phase-grid",
+ "type": "div",
+ "props": { "className": "mt-8 space-y-8" },
+ "loop": {
+ "source": "batches",
+ "itemVar": "batch"
+ },
+ "children": [
+ {
+ "id": "phase-card",
+ "type": "Card",
+ "children": [
+ {
+ "id": "phase-header",
+ "type": "CardHeader",
+ "children": [
+ {
+ "id": "phase-title",
+ "type": "CardTitle",
+ "bindings": {
+ "children": { "source": "batch", "sourceType": "bindings", "path": "title" }
+ }
+ },
+ {
+ "id": "phase-description",
+ "type": "CardDescription",
+ "bindings": {
+ "children": { "source": "batch", "sourceType": "bindings", "path": "summary" }
+ }
+ }
+ ]
+ },
+ {
+ "id": "phase-content",
+ "type": "CardContent",
+ "props": { "className": "space-y-6" },
+ "children": [
+ {
+ "id": "stats-grid",
+ "type": "div",
+ "props": {
+ "className": "grid gap-3 md:grid-cols-3"
+ },
+ "loop": {
+ "source": "batch.stats",
+ "itemVar": "stat"
+ },
+ "children": [
+ {
+ "id": "stat-item",
+ "type": "div",
+ "props": { "className": "rounded-lg border border-border p-3" },
+ "children": [
+ {
+ "id": "stat-label",
+ "type": "Text",
+ "props": { "className": "text-xs text-muted-foreground" },
+ "bindings": {
+ "children": { "source": "stat", "sourceType": "bindings", "path": "label" }
+ }
+ },
+ {
+ "id": "stat-value",
+ "type": "Text",
+ "props": { "className": "text-lg font-semibold" },
+ "bindings": {
+ "children": { "source": "stat", "sourceType": "bindings", "path": "value" }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "pages-section",
+ "type": "div",
+ "props": { "className": "space-y-3" },
+ "children": [
+ {
+ "id": "pages-title",
+ "type": "Heading",
+ "props": { "className": "text-base font-semibold", "children": "Converted Pages" }
+ },
+ {
+ "id": "pages-grid",
+ "type": "div",
+ "props": { "className": "grid gap-3 md:grid-cols-3" },
+ "loop": {
+ "source": "batch.pages",
+ "itemVar": "page"
+ },
+ "children": [
+ {
+ "id": "page-item",
+ "type": "Card",
+ "children": [
+ {
+ "id": "page-item-header",
+ "type": "CardHeader",
+ "children": [
+ {
+ "id": "page-item-title",
+ "type": "CardTitle",
+ "bindings": {
+ "children": { "source": "page", "sourceType": "bindings", "path": "name" }
+ }
+ },
+ {
+ "id": "page-item-description",
+ "type": "CardDescription",
+ "bindings": {
+ "children": { "source": "page", "sourceType": "bindings", "path": "schema" }
+ }
+ }
+ ]
+ },
+ {
+ "id": "page-item-content",
+ "type": "CardContent",
+ "props": { "className": "space-y-2" },
+ "children": [
+ {
+ "id": "page-id",
+ "type": "Badge",
+ "bindings": {
+ "children": { "source": "page", "sourceType": "bindings", "path": "pageId" }
+ }
+ },
+ {
+ "id": "page-store",
+ "type": "Text",
+ "props": { "className": "text-xs text-muted-foreground" },
+ "bindings": {
+ "children": { "source": "page", "sourceType": "bindings", "path": "dataStore" }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "seed-section",
+ "type": "div",
+ "props": { "className": "space-y-2" },
+ "children": [
+ {
+ "id": "seed-title",
+ "type": "Heading",
+ "props": { "className": "text-base font-semibold", "children": "Seed Data Highlights" }
+ },
+ {
+ "id": "seed-list",
+ "type": "div",
+ "props": { "className": "space-y-1" },
+ "loop": {
+ "source": "batch.seedHighlights",
+ "itemVar": "seed"
+ },
+ "children": [
+ {
+ "id": "seed-item",
+ "type": "Text",
+ "props": { "className": "text-sm" },
+ "bindings": {
+ "children": { "source": "seed", "sourceType": "bindings" }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "patterns-section",
+ "type": "div",
+ "props": { "className": "mt-8" },
+ "children": [
+ {
+ "id": "patterns-title",
+ "type": "Heading",
+ "props": { "className": "text-xl font-semibold", "children": "Reusable Patterns" }
+ },
+ {
+ "id": "patterns-list",
+ "type": "div",
+ "props": { "className": "mt-3 space-y-2" },
+ "loop": {
+ "source": "patterns",
+ "itemVar": "pattern"
+ },
+ "children": [
+ {
+ "id": "pattern-item",
+ "type": "Text",
+ "props": { "className": "text-sm" },
+ "bindings": {
+ "children": { "source": "pattern", "sourceType": "bindings" }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "globalActions": []
+}
diff --git a/src/lib/navigation-config.tsx b/src/lib/navigation-config.tsx
index 4a0dd42..306b62a 100644
--- a/src/lib/navigation-config.tsx
+++ b/src/lib/navigation-config.tsx
@@ -153,6 +153,11 @@ export const tabInfo: Record = {
icon: ,
description: 'JSON-driven UI examples',
},
+ 'json-conversion-showcase': {
+ title: 'JSON Conversion Showcase',
+ icon: ,
+ description: 'JSON conversion showcase overview',
+ },
'atomic-library': {
title: 'Atomic Components',
icon: ,
@@ -332,6 +337,12 @@ export const navigationGroups: NavigationGroup[] = [
value: 'docs',
featureKey: 'documentation',
},
+ {
+ id: 'json-conversion-showcase',
+ label: 'JSON Conversion Showcase',
+ icon: ,
+ value: 'json-conversion-showcase',
+ },
{
id: 'settings',
label: 'Settings',