Refactor app layout structure

This commit is contained in:
2026-01-18 00:34:26 +00:00
parent 9cb7297f5b
commit dfe42008e5
13 changed files with 692 additions and 825 deletions

View File

@@ -1,403 +1,5 @@
console.log('[APP_ROUTER] 🚀 App.router.tsx loading - BEGIN')
console.time('[APP_ROUTER] Component initialization')
import AppRouterBootstrap from '@/components/app/AppRouterBootstrap'
import { useState, Suspense, useEffect } from 'react'
console.log('[APP_ROUTER] ✅ React hooks imported')
import { BrowserRouter, useLocation } from 'react-router-dom'
console.log('[APP_ROUTER] ✅ React Router imported')
import { AppHeader } from '@/components/organisms'
console.log('[APP_ROUTER] ✅ Header components imported')
import { LoadingFallback } from '@/components/molecules'
console.log('[APP_ROUTER] ✅ LoadingFallback imported')
import { useProjectState } from '@/hooks/use-project-state'
import { useFileOperations } from '@/hooks/use-file-operations'
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
import { useSeedData } from '@/hooks/data/use-seed-data'
import { useRouterNavigation } from '@/hooks/use-router-navigation'
console.log('[APP_ROUTER] ✅ Custom hooks imported')
import { getPageShortcuts } from '@/config/page-loader'
console.log('[APP_ROUTER] ✅ Page config imported')
import { toast } from 'sonner'
console.log('[APP_ROUTER] ✅ Toast imported')
import { DialogRegistry, PWARegistry, preloadCriticalComponents } from '@/lib/component-registry'
console.log('[APP_ROUTER] ✅ Component registry imported')
import { RouterProvider } from '@/router'
console.log('[APP_ROUTER] ✅ Router provider imported')
const { GlobalSearch, KeyboardShortcutsDialog, PreviewDialog } = DialogRegistry
const { PWAInstallPrompt, PWAUpdatePrompt, PWAStatusBar } = PWARegistry
console.log('[APP_ROUTER] ✅ Dialog and PWA components registered')
console.log('[APP_ROUTER] 🎯 App component function executing')
function AppLayout() {
console.log('[APP_ROUTER] 🏗️ AppLayout component rendering')
const location = useLocation()
const { currentPage, navigateToPage } = useRouterNavigation()
console.log('[APP_ROUTER] 📍 Current location:', location.pathname)
console.log('[APP_ROUTER] 📄 Current page:', currentPage)
console.log('[APP_ROUTER] 📊 Initializing project state hook')
const projectState = useProjectState()
console.log('[APP_ROUTER] ✅ Project state initialized')
const {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
setFiles,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
} = projectState
console.log('[APP_ROUTER] 📁 Initializing file operations')
const fileOps = useFileOperations(files, setFiles)
console.log('[APP_ROUTER] ✅ File operations initialized')
const { activeFileId, setActiveFileId, handleFileChange, handleFileAdd, handleFileClose } = fileOps
console.log('[APP_ROUTER] 💾 Initializing state variables')
const [searchOpen, setSearchOpen] = useState(false)
const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [previewOpen, setPreviewOpen] = useState(false)
const [lastSaved] = useState<number | null>(Date.now())
const [errorCount] = useState(0)
console.log('[APP_ROUTER] ✅ State variables initialized')
const shortcuts = getPageShortcuts(featureToggles)
console.log('[APP_ROUTER] ⌨️ Keyboard shortcuts configured:', shortcuts.length)
console.log('[APP_ROUTER] ⌨️ Setting up keyboard shortcuts')
useKeyboardShortcuts([
...shortcuts.map(s => ({
key: s.key,
ctrl: s.ctrl,
shift: s.shift,
description: s.description,
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcut triggered, navigating to:', s.action)
navigateToPage(s.action)
}
})),
{
key: 'k',
ctrl: true,
description: 'Search',
action: () => {
console.log('[APP_ROUTER] ⌨️ Search shortcut triggered')
setSearchOpen(true)
}
},
{
key: '/',
ctrl: true,
description: 'Shortcuts',
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcuts dialog triggered')
setShortcutsOpen(true)
}
},
{
key: 'p',
ctrl: true,
description: 'Preview',
action: () => {
console.log('[APP_ROUTER] ⌨️ Preview shortcut triggered')
setPreviewOpen(true)
}
},
])
console.log('[APP_ROUTER] ✅ Keyboard shortcuts configured')
const getCurrentProject = () => ({
name: nextjsConfig.appName,
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
})
const handleProjectLoad = (project: any) => {
console.log('[APP_ROUTER] 📦 Loading project:', project.name)
if (project.files) setFiles(project.files)
if (project.models) setModels(project.models)
if (project.components) setComponents(project.components)
if (project.componentTrees) setComponentTrees(project.componentTrees)
if (project.workflows) setWorkflows(project.workflows)
if (project.lambdas) setLambdas(project.lambdas)
if (project.theme) setTheme(project.theme)
if (project.playwrightTests) setPlaywrightTests(project.playwrightTests)
if (project.storybookStories) setStorybookStories(project.storybookStories)
if (project.unitTests) setUnitTests(project.unitTests)
if (project.flaskConfig) setFlaskConfig(project.flaskConfig)
if (project.nextjsConfig) setNextjsConfig(project.nextjsConfig)
if (project.npmSettings) setNpmSettings(project.npmSettings)
if (project.featureToggles) setFeatureToggles(project.featureToggles)
toast.success('Project loaded')
console.log('[APP_ROUTER] ✅ Project loaded successfully')
}
useEffect(() => {
console.log('[APP_ROUTER] 📍 Route changed to:', location.pathname, '- Page:', currentPage)
}, [location, currentPage])
console.log('[APP_ROUTER] 🎨 Rendering AppLayout UI')
return (
<div className="h-screen flex flex-col bg-background">
<Suspense fallback={<div className="h-1 bg-primary animate-pulse" />}>
<PWAStatusBar />
</Suspense>
<Suspense fallback={null}>
<PWAUpdatePrompt />
</Suspense>
<AppHeader
activeTab={currentPage}
onTabChange={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
lastSaved={lastSaved}
currentProject={getCurrentProject()}
onProjectLoad={handleProjectLoad}
onSearch={() => {
console.log('[APP_ROUTER] 🔍 Search opened')
setSearchOpen(true)
}}
onShowShortcuts={() => {
console.log('[APP_ROUTER] ⌨️ Shortcuts dialog opened')
setShortcutsOpen(true)
}}
onGenerateAI={() => {
console.log('[APP_ROUTER] 🤖 AI generation requested')
toast.info('AI generation coming soon')
}}
onExport={() => {
console.log('[APP_ROUTER] 📤 Export requested')
toast.info('Export coming soon')
}}
onPreview={() => {
console.log('[APP_ROUTER] 👁️ Preview opened')
setPreviewOpen(true)
}}
onShowErrors={() => {
console.log('[APP_ROUTER] ⚠️ Navigating to errors page')
navigateToPage('errors')
}}
/>
<div className="flex-1 overflow-hidden">
<RouterProvider
featureToggles={featureToggles}
stateContext={{
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
activeFileId,
}}
actionContext={{
handleFileChange,
setActiveFileId,
handleFileClose,
handleFileAdd,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
}}
/>
</div>
<Suspense fallback={null}>
<GlobalSearch
open={searchOpen}
onOpenChange={setSearchOpen}
files={files}
models={models}
components={components}
componentTrees={componentTrees}
workflows={workflows}
lambdas={lambdas}
playwrightTests={playwrightTests}
storybookStories={storybookStories}
unitTests={unitTests}
onNavigate={(page) => {
console.log('[APP_ROUTER] 🔍 Search navigation to:', page)
navigateToPage(page)
}}
onFileSelect={(fileId) => {
console.log('[APP_ROUTER] 📄 File selected from search:', fileId)
setActiveFileId(fileId)
navigateToPage('code')
}}
/>
</Suspense>
<Suspense fallback={null}>
<KeyboardShortcutsDialog open={shortcutsOpen} onOpenChange={setShortcutsOpen} />
</Suspense>
<Suspense fallback={null}>
<PreviewDialog open={previewOpen} onOpenChange={setPreviewOpen} />
</Suspense>
<Suspense fallback={null}>
<PWAInstallPrompt />
</Suspense>
</div>
)
export default function App() {
return <AppRouterBootstrap />
}
function App() {
console.log('[APP_ROUTER] 🔧 Initializing App component')
console.time('[APP_ROUTER] App render')
console.log('[APP_ROUTER] 🌱 Initializing seed data hook')
const { loadSeedData } = useSeedData()
const projectState = useProjectState()
const { featureToggles, files, setFiles, ...restState } = projectState
console.log('[APP_ROUTER] ✅ Hooks initialized')
console.log('[APP_ROUTER] 📁 Initializing file operations for router context')
const fileOps = useFileOperations(files, setFiles)
const [appReady, setAppReady] = useState(false)
console.log('[APP_ROUTER] 💾 App ready state:', appReady)
console.log('[APP_ROUTER] ⏰ Setting up initialization effect')
useEffect(() => {
console.log('[APP_ROUTER] 🚀 Initialization effect triggered')
console.time('[APP_ROUTER] Seed data loading')
const timer = setTimeout(() => {
console.log('[APP_ROUTER] ⏱️ Fallback timer triggered (100ms)')
setAppReady(true)
}, 100)
console.log('[APP_ROUTER] 📥 Starting seed data load')
loadSeedData()
.then(() => {
console.log('[APP_ROUTER] ✅ Seed data loaded successfully')
})
.catch(err => {
console.error('[APP_ROUTER] ❌ Seed data loading failed:', err)
})
.finally(() => {
console.log('[APP_ROUTER] 🏁 Seed data loading complete')
clearTimeout(timer)
setAppReady(true)
console.timeEnd('[APP_ROUTER] Seed data loading')
console.log('[APP_ROUTER] ✅ App marked as ready')
console.log('[APP_ROUTER] 🚀 Preloading critical components')
preloadCriticalComponents()
})
return () => {
console.log('[APP_ROUTER] 🧹 Cleaning up initialization effect')
clearTimeout(timer)
}
}, [loadSeedData])
const stateContext = {
files,
...restState,
activeFileId: fileOps.activeFileId,
}
const actionContext = {
handleFileChange: fileOps.handleFileChange,
setActiveFileId: fileOps.setActiveFileId,
handleFileClose: fileOps.handleFileClose,
handleFileAdd: fileOps.handleFileAdd,
setFiles,
...Object.fromEntries(
Object.entries(restState).filter(([key]) => key.startsWith('set'))
),
}
console.log('[APP_ROUTER] 🎨 Rendering App component UI')
console.log('[APP_ROUTER] App state - appReady:', appReady)
console.timeEnd('[APP_ROUTER] App render')
if (!appReady) {
console.log('[APP_ROUTER] ⏳ App not ready, showing loading screen')
return (
<div className="fixed inset-0 bg-background z-50 flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">Loading CodeForge...</p>
</div>
</div>
)
}
console.log('[APP_ROUTER] ✅ App ready, rendering router')
return (
<BrowserRouter>
<AppLayout />
</BrowserRouter>
)
}
console.log('[APP_ROUTER] ✅ App component defined')
console.timeEnd('[APP_ROUTER] Component initialization')
export default App

View File

@@ -1,426 +1,5 @@
console.log('[APP_ROUTER] 🚀 App.router.tsx loading - BEGIN')
console.time('[APP_ROUTER] Component initialization')
import AppBootstrap from '@/components/app/AppBootstrap'
import { useState, Suspense, useEffect } from 'react'
console.log('[APP_ROUTER] ✅ React hooks imported')
import { BrowserRouter, useLocation } from 'react-router-dom'
console.log('[APP_ROUTER] ✅ React Router imported')
import { AppHeader } from '@/components/organisms'
import { NavigationMenu } from '@/components/organisms/NavigationMenu'
console.log('[APP_ROUTER] ✅ Header components imported')
import { LoadingFallback } from '@/components/molecules'
console.log('[APP_ROUTER] ✅ LoadingFallback imported')
import { useProjectState } from '@/hooks/use-project-state'
import { useFileOperations } from '@/hooks/use-file-operations'
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
import { useSeedData } from '@/hooks/data/use-seed-data'
import { useRouterNavigation } from '@/hooks/use-router-navigation'
import { useComponentTreeLoader } from '@/hooks/use-component-tree-loader'
console.log('[APP_ROUTER] ✅ Custom hooks imported')
import { getPageShortcuts } from '@/config/page-loader'
console.log('[APP_ROUTER] ✅ Page config imported')
import { toast } from 'sonner'
console.log('[APP_ROUTER] ✅ Toast imported')
import { DialogRegistry, PWARegistry, preloadCriticalComponents } from '@/lib/component-registry'
console.log('[APP_ROUTER] ✅ Component registry imported')
import { RouterProvider } from '@/router'
console.log('[APP_ROUTER] ✅ Router provider imported')
import { SidebarProvider, SidebarInset, Sidebar, SidebarContent, SidebarHeader } from '@/components/ui/sidebar'
console.log('[APP_ROUTER] ✅ Sidebar provider imported')
const { GlobalSearch, KeyboardShortcutsDialog, PreviewDialog } = DialogRegistry
const { PWAInstallPrompt, PWAUpdatePrompt, PWAStatusBar } = PWARegistry
console.log('[APP_ROUTER] ✅ Dialog and PWA components registered')
console.log('[APP_ROUTER] 🎯 App component function executing')
function AppLayout() {
console.log('[APP_ROUTER] 🏗️ AppLayout component rendering')
const location = useLocation()
const { currentPage, navigateToPage } = useRouterNavigation()
console.log('[APP_ROUTER] 📍 Current location:', location.pathname)
console.log('[APP_ROUTER] 📄 Current page:', currentPage)
console.log('[APP_ROUTER] 📊 Initializing project state hook')
const projectState = useProjectState()
console.log('[APP_ROUTER] ✅ Project state initialized')
const {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
setFiles,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
} = projectState
console.log('[APP_ROUTER] 📁 Initializing file operations')
const fileOps = useFileOperations(files, setFiles)
console.log('[APP_ROUTER] ✅ File operations initialized')
const { activeFileId, setActiveFileId, handleFileChange, handleFileAdd, handleFileClose } = fileOps
console.log('[APP_ROUTER] 💾 Initializing state variables')
const [searchOpen, setSearchOpen] = useState(false)
const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [previewOpen, setPreviewOpen] = useState(false)
const [lastSaved] = useState<number | null>(Date.now())
const [errorCount] = useState(0)
console.log('[APP_ROUTER] ✅ State variables initialized')
const shortcuts = getPageShortcuts(featureToggles)
console.log('[APP_ROUTER] ⌨️ Keyboard shortcuts configured:', shortcuts.length)
console.log('[APP_ROUTER] ⌨️ Setting up keyboard shortcuts')
useKeyboardShortcuts([
...shortcuts.map(s => ({
key: s.key,
ctrl: s.ctrl,
shift: s.shift,
description: s.description,
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcut triggered, navigating to:', s.action)
navigateToPage(s.action)
}
})),
{
key: 'k',
ctrl: true,
description: 'Search',
action: () => {
console.log('[APP_ROUTER] ⌨️ Search shortcut triggered')
setSearchOpen(true)
}
},
{
key: '/',
ctrl: true,
description: 'Shortcuts',
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcuts dialog triggered')
setShortcutsOpen(true)
}
},
{
key: 'p',
ctrl: true,
description: 'Preview',
action: () => {
console.log('[APP_ROUTER] ⌨️ Preview shortcut triggered')
setPreviewOpen(true)
}
},
])
console.log('[APP_ROUTER] ✅ Keyboard shortcuts configured')
const getCurrentProject = () => ({
name: nextjsConfig.appName,
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
})
const handleProjectLoad = (project: any) => {
console.log('[APP_ROUTER] 📦 Loading project:', project.name)
if (project.files) setFiles(project.files)
if (project.models) setModels(project.models)
if (project.components) setComponents(project.components)
if (project.componentTrees) setComponentTrees(project.componentTrees)
if (project.workflows) setWorkflows(project.workflows)
if (project.lambdas) setLambdas(project.lambdas)
if (project.theme) setTheme(project.theme)
if (project.playwrightTests) setPlaywrightTests(project.playwrightTests)
if (project.storybookStories) setStorybookStories(project.storybookStories)
if (project.unitTests) setUnitTests(project.unitTests)
if (project.flaskConfig) setFlaskConfig(project.flaskConfig)
if (project.nextjsConfig) setNextjsConfig(project.nextjsConfig)
if (project.npmSettings) setNpmSettings(project.npmSettings)
if (project.featureToggles) setFeatureToggles(project.featureToggles)
toast.success('Project loaded')
console.log('[APP_ROUTER] ✅ Project loaded successfully')
}
useEffect(() => {
console.log('[APP_ROUTER] 📍 Route changed to:', location.pathname, '- Page:', currentPage)
}, [location, currentPage])
console.log('[APP_ROUTER] 🎨 Rendering AppLayout UI')
return (
<SidebarProvider defaultOpen={true}>
<NavigationMenu
activeTab={currentPage}
onTabChange={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
/>
<SidebarInset>
<Suspense fallback={<div className="h-1 bg-primary animate-pulse" />}>
<PWAStatusBar />
</Suspense>
<Suspense fallback={null}>
<PWAUpdatePrompt />
</Suspense>
<div className="h-screen flex flex-col bg-background">
<AppHeader
activeTab={currentPage}
onTabChange={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
lastSaved={lastSaved}
currentProject={getCurrentProject()}
onProjectLoad={handleProjectLoad}
onSearch={() => {
console.log('[APP_ROUTER] 🔍 Search opened')
setSearchOpen(true)
}}
onShowShortcuts={() => {
console.log('[APP_ROUTER] ⌨️ Shortcuts dialog opened')
setShortcutsOpen(true)
}}
onGenerateAI={() => {
console.log('[APP_ROUTER] 🤖 AI generation requested')
toast.info('AI generation coming soon')
}}
onExport={() => {
console.log('[APP_ROUTER] 📤 Export requested')
toast.info('Export coming soon')
}}
onPreview={() => {
console.log('[APP_ROUTER] 👁️ Preview opened')
setPreviewOpen(true)
}}
onShowErrors={() => {
console.log('[APP_ROUTER] ⚠️ Navigating to errors page')
navigateToPage('errors')
}}
/>
<div className="flex-1 overflow-hidden">
<RouterProvider
featureToggles={featureToggles}
stateContext={{
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
activeFileId,
}}
actionContext={{
handleFileChange,
setActiveFileId,
handleFileClose,
handleFileAdd,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
}}
/>
</div>
</div>
</SidebarInset>
<Suspense fallback={null}>
<GlobalSearch
open={searchOpen}
onOpenChange={setSearchOpen}
files={files}
models={models}
components={components}
componentTrees={componentTrees}
workflows={workflows}
lambdas={lambdas}
playwrightTests={playwrightTests}
storybookStories={storybookStories}
unitTests={unitTests}
onNavigate={(page) => {
console.log('[APP_ROUTER] 🔍 Search navigation to:', page)
navigateToPage(page)
}}
onFileSelect={(fileId) => {
console.log('[APP_ROUTER] 📄 File selected from search:', fileId)
setActiveFileId(fileId)
navigateToPage('code')
}}
/>
</Suspense>
<Suspense fallback={null}>
<KeyboardShortcutsDialog open={shortcutsOpen} onOpenChange={setShortcutsOpen} />
</Suspense>
<Suspense fallback={null}>
<PreviewDialog open={previewOpen} onOpenChange={setPreviewOpen} />
</Suspense>
<Suspense fallback={null}>
<PWAInstallPrompt />
</Suspense>
</SidebarProvider>
)
export default function App() {
return <AppBootstrap />
}
function App() {
console.log('[APP_ROUTER] 🔧 Initializing App component')
console.time('[APP_ROUTER] App render')
console.log('[APP_ROUTER] 🌱 Initializing seed data hook')
const { loadSeedData } = useSeedData()
const { loadComponentTrees } = useComponentTreeLoader()
const projectState = useProjectState()
const { featureToggles, files, setFiles, ...restState } = projectState
console.log('[APP_ROUTER] ✅ Hooks initialized')
console.log('[APP_ROUTER] 📁 Initializing file operations for router context')
const fileOps = useFileOperations(files, setFiles)
const [appReady, setAppReady] = useState(false)
console.log('[APP_ROUTER] 💾 App ready state:', appReady)
console.log('[APP_ROUTER] ⏰ Setting up initialization effect')
useEffect(() => {
console.log('[APP_ROUTER] 🚀 Initialization effect triggered')
console.time('[APP_ROUTER] Seed data loading')
const timer = setTimeout(() => {
console.log('[APP_ROUTER] ⏱️ Fallback timer triggered (100ms)')
setAppReady(true)
}, 100)
console.log('[APP_ROUTER] 📥 Starting seed data load')
loadSeedData()
.then(() => {
console.log('[APP_ROUTER] ✅ Seed data loaded successfully')
console.log('[APP_ROUTER] 📦 Loading component trees from JSON')
return loadComponentTrees()
})
.then(() => {
console.log('[APP_ROUTER] ✅ Component trees loaded successfully')
})
.catch(err => {
console.error('[APP_ROUTER] ❌ Seed data loading failed:', err)
})
.finally(() => {
console.log('[APP_ROUTER] 🏁 Seed data loading complete')
clearTimeout(timer)
setAppReady(true)
console.timeEnd('[APP_ROUTER] Seed data loading')
console.log('[APP_ROUTER] ✅ App marked as ready')
console.log('[APP_ROUTER] 🚀 Preloading critical components')
preloadCriticalComponents()
})
return () => {
console.log('[APP_ROUTER] 🧹 Cleaning up initialization effect')
clearTimeout(timer)
}
}, [loadSeedData, loadComponentTrees])
const stateContext = {
files,
...restState,
activeFileId: fileOps.activeFileId,
}
const actionContext = {
handleFileChange: fileOps.handleFileChange,
setActiveFileId: fileOps.setActiveFileId,
handleFileClose: fileOps.handleFileClose,
handleFileAdd: fileOps.handleFileAdd,
setFiles,
...Object.fromEntries(
Object.entries(restState).filter(([key]) => key.startsWith('set'))
),
}
console.log('[APP_ROUTER] 🎨 Rendering App component UI')
console.log('[APP_ROUTER] App state - appReady:', appReady)
console.timeEnd('[APP_ROUTER] App render')
if (!appReady) {
console.log('[APP_ROUTER] ⏳ App not ready, showing loading screen')
return (
<div className="fixed inset-0 bg-background z-50 flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">Loading CodeForge...</p>
</div>
</div>
)
}
console.log('[APP_ROUTER] ✅ App ready, rendering router')
return (
<BrowserRouter>
<AppLayout />
</BrowserRouter>
)
}
console.log('[APP_ROUTER] ✅ App component defined')
console.timeEnd('[APP_ROUTER] Component initialization')
export default App

View File

@@ -0,0 +1,45 @@
import { useEffect, useState } from 'react'
import { BrowserRouter } from 'react-router-dom'
import AppLayout from '@/components/app/AppLayout'
import LoadingScreen from '@/components/app/LoadingScreen'
import { useComponentTreeLoader } from '@/hooks/use-component-tree-loader'
import { useSeedData } from '@/hooks/data/use-seed-data'
import { preloadCriticalComponents } from '@/lib/component-registry'
export default function AppBootstrap() {
const { loadSeedData } = useSeedData()
const { loadComponentTrees } = useComponentTreeLoader()
const [appReady, setAppReady] = useState(false)
useEffect(() => {
const timer = setTimeout(() => {
setAppReady(true)
}, 100)
loadSeedData()
.then(() => loadComponentTrees())
.catch(err => {
console.error('[APP_ROUTER] ❌ Seed data loading failed:', err)
})
.finally(() => {
clearTimeout(timer)
setAppReady(true)
preloadCriticalComponents()
})
return () => {
clearTimeout(timer)
}
}, [loadSeedData, loadComponentTrees])
if (!appReady) {
return <LoadingScreen />
}
return (
<BrowserRouter>
<AppLayout />
</BrowserRouter>
)
}

View File

@@ -0,0 +1,89 @@
import { Suspense } from 'react'
import { DialogRegistry, PWARegistry } from '@/lib/component-registry'
import type {
ComponentNode,
ComponentTree,
Lambda,
PlaywrightTest,
PrismaModel,
ProjectFile,
StorybookStory,
UnitTest,
Workflow,
} from '@/types/project'
const { GlobalSearch, KeyboardShortcutsDialog, PreviewDialog } = DialogRegistry
const { PWAInstallPrompt } = PWARegistry
interface AppDialogsProps {
searchOpen: boolean
onSearchOpenChange: (open: boolean) => void
shortcutsOpen: boolean
onShortcutsOpenChange: (open: boolean) => void
previewOpen: boolean
onPreviewOpenChange: (open: boolean) => void
files: ProjectFile[]
models: PrismaModel[]
components: ComponentNode[]
componentTrees: ComponentTree[]
workflows: Workflow[]
lambdas: Lambda[]
playwrightTests: PlaywrightTest[]
storybookStories: StorybookStory[]
unitTests: UnitTest[]
onNavigate: (page: string) => void
onFileSelect: (fileId: string) => void
}
export default function AppDialogs({
searchOpen,
onSearchOpenChange,
shortcutsOpen,
onShortcutsOpenChange,
previewOpen,
onPreviewOpenChange,
files,
models,
components,
componentTrees,
workflows,
lambdas,
playwrightTests,
storybookStories,
unitTests,
onNavigate,
onFileSelect,
}: AppDialogsProps) {
return (
<>
<Suspense fallback={null}>
<GlobalSearch
open={searchOpen}
onOpenChange={onSearchOpenChange}
files={files}
models={models}
components={components}
componentTrees={componentTrees}
workflows={workflows}
lambdas={lambdas}
playwrightTests={playwrightTests}
storybookStories={storybookStories}
unitTests={unitTests}
onNavigate={onNavigate}
onFileSelect={onFileSelect}
/>
</Suspense>
<Suspense fallback={null}>
<KeyboardShortcutsDialog open={shortcutsOpen} onOpenChange={onShortcutsOpenChange} />
</Suspense>
<Suspense fallback={null}>
<PreviewDialog open={previewOpen} onOpenChange={onPreviewOpenChange} />
</Suspense>
<Suspense fallback={null}>
<PWAInstallPrompt />
</Suspense>
</>
)
}

View File

@@ -0,0 +1,92 @@
import { useState } from 'react'
import { toast } from 'sonner'
import AppDialogs from '@/components/app/AppDialogs'
import AppMainPanel from '@/components/app/AppMainPanel'
import { NavigationMenu } from '@/components/organisms/NavigationMenu'
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'
import appStrings from '@/data/app-shortcuts.json'
import useAppNavigation from '@/hooks/use-app-navigation'
import useAppProject from '@/hooks/use-app-project'
import useAppShortcuts from '@/hooks/use-app-shortcuts'
export default function AppLayout() {
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<number | null>(() => Date.now())
const [errorCount] = useState(0)
return (
<SidebarProvider defaultOpen={true}>
<NavigationMenu
activeTab={currentPage}
onTabChange={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
/>
<SidebarInset>
<div className="h-screen flex flex-col bg-background">
<AppMainPanel
currentPage={currentPage}
navigateToPage={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
lastSaved={lastSaved}
currentProject={currentProject}
onProjectLoad={handleProjectLoad}
onSearch={() => setSearchOpen(true)}
onShowShortcuts={() => setShortcutsOpen(true)}
onGenerateAI={() => toast.info(appStrings.messages.aiComingSoon)}
onExport={() => toast.info(appStrings.messages.exportComingSoon)}
onPreview={() => setPreviewOpen(true)}
onShowErrors={() => navigateToPage('errors')}
stateContext={stateContext}
actionContext={actionContext}
/>
</div>
</SidebarInset>
<AppDialogs
searchOpen={searchOpen}
onSearchOpenChange={setSearchOpen}
shortcutsOpen={shortcutsOpen}
onShortcutsOpenChange={setShortcutsOpen}
previewOpen={previewOpen}
onPreviewOpenChange={setPreviewOpen}
files={files}
models={models}
components={components}
componentTrees={componentTrees}
workflows={workflows}
lambdas={lambdas}
playwrightTests={playwrightTests}
storybookStories={storybookStories}
unitTests={unitTests}
onNavigate={navigateToPage}
onFileSelect={(fileId) => {
fileOps.setActiveFileId(fileId)
navigateToPage('code')
}}
/>
</SidebarProvider>
)
}

View File

@@ -0,0 +1,77 @@
import { Suspense } from 'react'
import { AppHeader } from '@/components/organisms'
import { PWARegistry } from '@/lib/component-registry'
import { RouterProvider } from '@/router'
import type { FeatureToggles, Project } from '@/types/project'
const { PWAUpdatePrompt, PWAStatusBar } = PWARegistry
interface AppMainPanelProps {
currentPage: string
navigateToPage: (page: 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
stateContext: any
actionContext: any
}
export default function AppMainPanel({
currentPage,
navigateToPage,
featureToggles,
errorCount,
lastSaved,
currentProject,
onProjectLoad,
onSearch,
onShowShortcuts,
onGenerateAI,
onExport,
onPreview,
onShowErrors,
stateContext,
actionContext,
}: AppMainPanelProps) {
return (
<>
<Suspense fallback={<div className="h-1 bg-primary animate-pulse" />}>
<PWAStatusBar />
</Suspense>
<Suspense fallback={null}>
<PWAUpdatePrompt />
</Suspense>
<AppHeader
activeTab={currentPage}
onTabChange={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
lastSaved={lastSaved}
currentProject={currentProject}
onProjectLoad={onProjectLoad}
onSearch={onSearch}
onShowShortcuts={onShowShortcuts}
onGenerateAI={onGenerateAI}
onExport={onExport}
onPreview={onPreview}
onShowErrors={onShowErrors}
/>
<div className="flex-1 overflow-hidden">
<RouterProvider
featureToggles={featureToggles}
stateContext={stateContext}
actionContext={actionContext}
/>
</div>
</>
)
}

View File

@@ -0,0 +1,42 @@
import { useEffect, useState } from 'react'
import { BrowserRouter } from 'react-router-dom'
import AppRouterLayout from '@/components/app/AppRouterLayout'
import LoadingScreen from '@/components/app/LoadingScreen'
import { useSeedData } from '@/hooks/data/use-seed-data'
import { preloadCriticalComponents } from '@/lib/component-registry'
export default function AppRouterBootstrap() {
const { loadSeedData } = useSeedData()
const [appReady, setAppReady] = useState(false)
useEffect(() => {
const timer = setTimeout(() => {
setAppReady(true)
}, 100)
loadSeedData()
.catch(err => {
console.error('[APP_ROUTER] ❌ Seed data loading failed:', err)
})
.finally(() => {
clearTimeout(timer)
setAppReady(true)
preloadCriticalComponents()
})
return () => {
clearTimeout(timer)
}
}, [loadSeedData])
if (!appReady) {
return <LoadingScreen />
}
return (
<BrowserRouter>
<AppRouterLayout />
</BrowserRouter>
)
}

View File

@@ -0,0 +1,79 @@
import { useState } from 'react'
import { toast } from 'sonner'
import AppDialogs from '@/components/app/AppDialogs'
import AppMainPanel from '@/components/app/AppMainPanel'
import appStrings from '@/data/app-shortcuts.json'
import useAppNavigation from '@/hooks/use-app-navigation'
import useAppProject from '@/hooks/use-app-project'
import useAppShortcuts from '@/hooks/use-app-shortcuts'
export default function AppRouterLayout() {
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<number | null>(() => Date.now())
const [errorCount] = useState(0)
return (
<div className="h-screen flex flex-col bg-background">
<AppMainPanel
currentPage={currentPage}
navigateToPage={navigateToPage}
featureToggles={featureToggles}
errorCount={errorCount}
lastSaved={lastSaved}
currentProject={currentProject}
onProjectLoad={handleProjectLoad}
onSearch={() => setSearchOpen(true)}
onShowShortcuts={() => setShortcutsOpen(true)}
onGenerateAI={() => toast.info(appStrings.messages.aiComingSoon)}
onExport={() => toast.info(appStrings.messages.exportComingSoon)}
onPreview={() => setPreviewOpen(true)}
onShowErrors={() => navigateToPage('errors')}
stateContext={stateContext}
actionContext={actionContext}
/>
<AppDialogs
searchOpen={searchOpen}
onSearchOpenChange={setSearchOpen}
shortcutsOpen={shortcutsOpen}
onShortcutsOpenChange={setShortcutsOpen}
previewOpen={previewOpen}
onPreviewOpenChange={setPreviewOpen}
files={files}
models={models}
components={components}
componentTrees={componentTrees}
workflows={workflows}
lambdas={lambdas}
playwrightTests={playwrightTests}
storybookStories={storybookStories}
unitTests={unitTests}
onNavigate={navigateToPage}
onFileSelect={(fileId) => {
fileOps.setActiveFileId(fileId)
navigateToPage('code')
}}
/>
</div>
)
}

View File

@@ -0,0 +1,16 @@
import appStrings from '@/data/app-shortcuts.json'
interface LoadingScreenProps {
message?: string
}
export default function LoadingScreen({ message = appStrings.messages.loading }: LoadingScreenProps) {
return (
<div className="fixed inset-0 bg-background z-50 flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">{message}</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,13 @@
{
"shortcuts": {
"search": "Search",
"shortcuts": "Shortcuts",
"preview": "Preview"
},
"messages": {
"loading": "Loading CodeForge...",
"projectLoaded": "Project loaded",
"aiComingSoon": "AI generation coming soon",
"exportComingSoon": "Export coming soon"
}
}

View File

@@ -0,0 +1,15 @@
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { useRouterNavigation } from '@/hooks/use-router-navigation'
export default function useAppNavigation() {
const location = useLocation()
const { currentPage, navigateToPage } = useRouterNavigation()
useEffect(() => {
console.log('[APP_ROUTER] 📍 Route changed to:', location.pathname, '- Page:', currentPage)
}, [currentPage, location.pathname])
return { currentPage, navigateToPage }
}

View File

@@ -0,0 +1,147 @@
import { useMemo } from 'react'
import { toast } from 'sonner'
import appStrings from '@/data/app-shortcuts.json'
import { useFileOperations } from '@/hooks/use-file-operations'
import { useProjectState } from '@/hooks/use-project-state'
import type { Project } from '@/types/project'
export default function useAppProject() {
const projectState = useProjectState()
const {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
setFiles,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
} = projectState
const fileOps = useFileOperations(files, setFiles)
const currentProject = useMemo<Project>(
() => ({
name: nextjsConfig.appName,
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
}),
[
componentTrees,
components,
featureToggles,
files,
flaskConfig,
lambdas,
models,
nextjsConfig,
npmSettings,
playwrightTests,
storybookStories,
theme,
unitTests,
workflows,
]
)
const handleProjectLoad = (project: Project) => {
if (project.files) setFiles(project.files)
if (project.models) setModels(project.models)
if (project.components) setComponents(project.components)
if (project.componentTrees) setComponentTrees(project.componentTrees)
if (project.workflows) setWorkflows(project.workflows)
if (project.lambdas) setLambdas(project.lambdas)
if (project.theme) setTheme(project.theme)
if (project.playwrightTests) setPlaywrightTests(project.playwrightTests)
if (project.storybookStories) setStorybookStories(project.storybookStories)
if (project.unitTests) setUnitTests(project.unitTests)
if (project.flaskConfig) setFlaskConfig(project.flaskConfig)
if (project.nextjsConfig) setNextjsConfig(project.nextjsConfig)
if (project.npmSettings) setNpmSettings(project.npmSettings)
if (project.featureToggles) setFeatureToggles(project.featureToggles)
toast.success(appStrings.messages.projectLoaded)
}
const stateContext = {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
activeFileId: fileOps.activeFileId,
}
const actionContext = {
handleFileChange: fileOps.handleFileChange,
setActiveFileId: fileOps.setActiveFileId,
handleFileClose: fileOps.handleFileClose,
handleFileAdd: fileOps.handleFileAdd,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
}
return {
files,
models,
components,
componentTrees,
workflows,
lambdas,
playwrightTests,
storybookStories,
unitTests,
featureToggles,
fileOps,
currentProject,
handleProjectLoad,
stateContext,
actionContext,
}
}

View File

@@ -0,0 +1,71 @@
import { useState } from 'react'
import appStrings from '@/data/app-shortcuts.json'
import { getPageShortcuts } from '@/config/page-loader'
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
import type { FeatureToggles } from '@/types/project'
interface UseAppShortcutsParams {
featureToggles: FeatureToggles
navigateToPage: (page: string) => void
}
export default function useAppShortcuts({
featureToggles,
navigateToPage,
}: UseAppShortcutsParams) {
const [searchOpen, setSearchOpen] = useState(false)
const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [previewOpen, setPreviewOpen] = useState(false)
const shortcuts = getPageShortcuts(featureToggles)
useKeyboardShortcuts([
...shortcuts.map(s => ({
key: s.key,
ctrl: s.ctrl,
shift: s.shift,
description: s.description,
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcut triggered, navigating to:', s.action)
navigateToPage(s.action)
},
})),
{
key: 'k',
ctrl: true,
description: appStrings.shortcuts.search,
action: () => {
console.log('[APP_ROUTER] ⌨️ Search shortcut triggered')
setSearchOpen(true)
},
},
{
key: '/',
ctrl: true,
description: appStrings.shortcuts.shortcuts,
action: () => {
console.log('[APP_ROUTER] ⌨️ Shortcuts dialog triggered')
setShortcutsOpen(true)
},
},
{
key: 'p',
ctrl: true,
description: appStrings.shortcuts.preview,
action: () => {
console.log('[APP_ROUTER] ⌨️ Preview shortcut triggered')
setPreviewOpen(true)
},
},
])
return {
searchOpen,
setSearchOpen,
shortcutsOpen,
setShortcutsOpen,
previewOpen,
setPreviewOpen,
}
}