From d287d6e0b6677360985701a0f424e95fe7c6556e Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Wed, 21 Jan 2026 01:15:12 +0000 Subject: [PATCH] feat: migrate AppLayout to JSON with useAppLayout hook --- json-components-registry.json | 5 ++ .../json-definitions/app-layout.json | 76 +++++++++++++++++++ src/hooks/index.ts | 1 + src/hooks/use-app-layout.ts | 72 ++++++++++++++++++ src/lib/json-ui/hooks-registry.ts | 2 + src/lib/json-ui/interfaces/app-layout.ts | 4 + src/lib/json-ui/interfaces/index.ts | 1 + src/lib/json-ui/json-components.ts | 11 +++ 8 files changed, 172 insertions(+) create mode 100644 src/components/json-definitions/app-layout.json create mode 100644 src/hooks/use-app-layout.ts create mode 100644 src/lib/json-ui/interfaces/app-layout.ts diff --git a/json-components-registry.json b/json-components-registry.json index a36bdb6..1a55800 100644 --- a/json-components-registry.json +++ b/json-components-registry.json @@ -3979,6 +3979,11 @@ "load": { "export": "X" } + }, + { + "type": "AppLayout", + "source": "app", + "jsonCompatible": true } ], "statistics": { diff --git a/src/components/json-definitions/app-layout.json b/src/components/json-definitions/app-layout.json new file mode 100644 index 0000000..bc0c3be --- /dev/null +++ b/src/components/json-definitions/app-layout.json @@ -0,0 +1,76 @@ +{ + "id": "app-layout", + "type": "SidebarProvider", + "props": { + "defaultOpen": true + }, + "children": [ + { + "id": "nav-menu", + "type": "NavigationMenu", + "bindings": { + "activeTab": { "source": "hookData.currentPage" }, + "onTabChange": { "source": "hookData.navigateToPage" }, + "featureToggles": { "source": "hookData.featureToggles" }, + "errorCount": { "source": "hookData.errorCount" } + } + }, + { + "id": "sidebar-inset-wrapper", + "type": "SidebarInset", + "children": [ + { + "id": "app-layout-main", + "type": "div", + "className": "h-screen flex flex-col bg-background", + "children": [ + { + "id": "main-panel", + "type": "AppMainPanel", + "bindings": { + "currentPage": { "source": "hookData.currentPage" }, + "navigateToPage": { "source": "hookData.navigateToPage" }, + "featureToggles": { "source": "hookData.featureToggles" }, + "errorCount": { "source": "hookData.errorCount" }, + "lastSaved": { "source": "hookData.lastSaved" }, + "currentProject": { "source": "hookData.currentProject" }, + "onProjectLoad": { "source": "hookData.handleProjectLoad" }, + "onSearch": { "source": "hookData.setSearchOpen", "transform": "() => setSearchOpen(true)" }, + "onShowShortcuts": { "source": "hookData.setShortcutsOpen", "transform": "() => setShortcutsOpen(true)" }, + "onGenerateAI": { "source": "hookData.onGenerateAI" }, + "onExport": { "source": "hookData.onExport" }, + "onPreview": { "source": "hookData.setPreviewOpen", "transform": "() => setPreviewOpen(true)" }, + "onShowErrors": { "source": "hookData.navigateToPage", "transform": "() => navigateToPage('errors')" }, + "stateContext": { "source": "hookData.stateContext" }, + "actionContext": { "source": "hookData.actionContext" } + } + } + ] + } + ] + }, + { + "id": "dialogs-container", + "type": "AppDialogs", + "bindings": { + "searchOpen": { "source": "hookData.searchOpen" }, + "onSearchOpenChange": { "source": "hookData.setSearchOpen" }, + "shortcutsOpen": { "source": "hookData.shortcutsOpen" }, + "onShortcutsOpenChange": { "source": "hookData.setShortcutsOpen" }, + "previewOpen": { "source": "hookData.previewOpen" }, + "onPreviewOpenChange": { "source": "hookData.setPreviewOpen" }, + "files": { "source": "hookData.files" }, + "models": { "source": "hookData.models" }, + "components": { "source": "hookData.components" }, + "componentTrees": { "source": "hookData.componentTrees" }, + "workflows": { "source": "hookData.workflows" }, + "lambdas": { "source": "hookData.lambdas" }, + "playwrightTests": { "source": "hookData.playwrightTests" }, + "storybookStories": { "source": "hookData.storybookStories" }, + "unitTests": { "source": "hookData.unitTests" }, + "onNavigate": { "source": "hookData.navigateToPage" }, + "onFileSelect": { "source": "hookData.onFileSelect" } + } + } + ] +} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 616b8ac..061efbb 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -37,3 +37,4 @@ export * from './use-menu-state' export * from './use-file-upload' export * from './use-accordion' export * from './use-binding-editor' +export { useAppLayout } from './use-app-layout' diff --git a/src/hooks/use-app-layout.ts b/src/hooks/use-app-layout.ts new file mode 100644 index 0000000..7cb6298 --- /dev/null +++ b/src/hooks/use-app-layout.ts @@ -0,0 +1,72 @@ +import { useState } from 'react' +import useAppNavigation from './use-app-navigation' +import useAppProject from './use-app-project' +import useAppShortcuts from './use-app-shortcuts' + +export function useAppLayout() { + const { currentPage, navigateToPage } = useAppNavigation() + const { + files, + models, + components, + componentTrees, + workflows, + lambdas, + playwrightTests, + storybookStories, + unitTests, + featureToggles, + fileOps, + currentProject, + handleProjectLoad, + stateContext, + actionContext, + } = useAppProject() + const { searchOpen, setSearchOpen, shortcutsOpen, setShortcutsOpen, previewOpen, setPreviewOpen } = + useAppShortcuts({ featureToggles, navigateToPage }) + const [lastSaved] = useState(() => Date.now()) + const [errorCount] = useState(0) + + // Create inline callback handlers for JSON binding + const onGenerateAI = () => { + // This will be defined via toast.info from appStrings + } + const onExport = () => { + // This will be defined via toast.info from appStrings + } + const onFileSelect = (fileId: string) => { + fileOps.setActiveFileId(fileId) + navigateToPage('code') + } + + return { + currentPage, + navigateToPage, + files, + models, + components, + componentTrees, + workflows, + lambdas, + playwrightTests, + storybookStories, + unitTests, + featureToggles, + fileOps, + currentProject, + handleProjectLoad, + stateContext, + actionContext, + searchOpen, + setSearchOpen, + shortcutsOpen, + setShortcutsOpen, + previewOpen, + setPreviewOpen, + lastSaved, + errorCount, + onGenerateAI, + onExport, + onFileSelect, + } +} diff --git a/src/lib/json-ui/hooks-registry.ts b/src/lib/json-ui/hooks-registry.ts index dd9436e..353d388 100644 --- a/src/lib/json-ui/hooks-registry.ts +++ b/src/lib/json-ui/hooks-registry.ts @@ -15,6 +15,7 @@ import { useMenuState } from '@/hooks/use-menu-state' import { useFileUpload } from '@/hooks/use-file-upload' import { useAccordion } from '@/hooks/use-accordion' import { useBindingEditor } from '@/hooks/use-binding-editor' +import { useAppLayout } from '@/hooks/use-app-layout' export interface HookRegistry { [key: string]: (...args: any[]) => any @@ -37,6 +38,7 @@ export const hooksRegistry: HookRegistry = { useFileUpload, useAccordion, useBindingEditor, + useAppLayout, // Add more hooks here as needed } diff --git a/src/lib/json-ui/interfaces/app-layout.ts b/src/lib/json-ui/interfaces/app-layout.ts new file mode 100644 index 0000000..6abfa28 --- /dev/null +++ b/src/lib/json-ui/interfaces/app-layout.ts @@ -0,0 +1,4 @@ +export interface AppLayoutProps { + // Props passed from parent + // Most state comes from hooks, not props +} diff --git a/src/lib/json-ui/interfaces/index.ts b/src/lib/json-ui/interfaces/index.ts index 475b200..c84d113 100644 --- a/src/lib/json-ui/interfaces/index.ts +++ b/src/lib/json-ui/interfaces/index.ts @@ -22,3 +22,4 @@ export * from './menu' export * from './file-upload' export * from './accordion' export * from './binding-editor' +export * from './app-layout' diff --git a/src/lib/json-ui/json-components.ts b/src/lib/json-ui/json-components.ts index 11a3af6..6dcb746 100644 --- a/src/lib/json-ui/json-components.ts +++ b/src/lib/json-ui/json-components.ts @@ -30,6 +30,7 @@ import type { FileUploadProps, AccordionProps, BindingEditorProps, + AppLayoutProps, } from './interfaces' // Import JSON definitions @@ -55,6 +56,7 @@ import menuDef from '@/components/json-definitions/menu.json' import fileUploadDef from '@/components/json-definitions/file-upload.json' import accordionDef from '@/components/json-definitions/accordion.json' import bindingEditorDef from '@/components/json-definitions/binding-editor.json' +import appLayoutDef from '@/components/json-definitions/app-layout.json' // Create pure JSON components (no hooks) export const LoadingFallback = createJsonComponent(loadingFallbackDef) @@ -186,4 +188,13 @@ export const BindingEditor = createJsonComponentWithHooks(bi } }) +export const AppLayout = createJsonComponentWithHooks(appLayoutDef, { + hooks: { + hookData: { + hookName: 'useAppLayout', + args: (props) => [props] + } + } +}) + // All components converted to pure JSON! 🎉