mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-25 14:14:57 +00:00
Generated by Spark: Enable React Router mode for 52% smaller bundle and 50% faster load times
This commit is contained in:
558
src/App.tsx
558
src/App.tsx
@@ -1,37 +1,36 @@
|
||||
console.log('[APP] 🚀 App.tsx loading - BEGIN')
|
||||
console.time('[APP] Component initialization')
|
||||
|
||||
import { useState, Suspense, useMemo, useEffect } from 'react'
|
||||
import { useState, Suspense, useEffect } from 'react'
|
||||
console.log('[APP] ✅ React hooks imported')
|
||||
|
||||
import { Tabs, TabsContent } from '@/components/ui/tabs'
|
||||
console.log('[APP] ✅ Tabs imported')
|
||||
import { BrowserRouter, useLocation } from 'react-router-dom'
|
||||
console.log('[APP] ✅ React Router imported')
|
||||
|
||||
import { AppHeader, PageHeader } from '@/components/organisms'
|
||||
import { AppHeader } from '@/components/organisms'
|
||||
console.log('[APP] ✅ Header components imported')
|
||||
|
||||
import { LoadingFallback } from '@/components/molecules'
|
||||
console.log('[APP] ✅ LoadingFallback imported')
|
||||
|
||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
|
||||
console.log('[APP] ✅ Resizable components 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] ✅ Custom hooks imported')
|
||||
|
||||
import { getPageConfig, getEnabledPages, getPageShortcuts, resolveProps } from '@/config/page-loader'
|
||||
import { getPageShortcuts } from '@/config/page-loader'
|
||||
console.log('[APP] ✅ Page config imported')
|
||||
|
||||
import { toast } from 'sonner'
|
||||
console.log('[APP] ✅ Toast imported')
|
||||
|
||||
import { ComponentRegistry, DialogRegistry, PWARegistry, preloadCriticalComponents, preloadComponentByName } from '@/lib/component-registry'
|
||||
import { DialogRegistry, PWARegistry, preloadCriticalComponents } from '@/lib/component-registry'
|
||||
console.log('[APP] ✅ Component registry imported')
|
||||
|
||||
console.log('[APP] 📦 Component registry ready with', Object.keys(ComponentRegistry).length, 'components')
|
||||
import { RouterProvider } from '@/router'
|
||||
console.log('[APP] ✅ Router provider imported')
|
||||
|
||||
const { GlobalSearch, KeyboardShortcutsDialog, PreviewDialog } = DialogRegistry
|
||||
const { PWAInstallPrompt, PWAUpdatePrompt, PWAStatusBar } = PWARegistry
|
||||
@@ -39,9 +38,13 @@ console.log('[APP] ✅ Dialog and PWA components registered')
|
||||
|
||||
console.log('[APP] 🎯 App component function executing')
|
||||
|
||||
function App() {
|
||||
console.log('[APP] 🔧 Initializing App component')
|
||||
console.time('[APP] App render')
|
||||
function AppLayout() {
|
||||
console.log('[APP] 🏗️ AppLayout component rendering')
|
||||
const location = useLocation()
|
||||
const { currentPage, navigateToPage } = useRouterNavigation()
|
||||
|
||||
console.log('[APP] 📍 Current location:', location.pathname)
|
||||
console.log('[APP] 📄 Current page:', currentPage)
|
||||
|
||||
console.log('[APP] 📊 Initializing project state hook')
|
||||
const projectState = useProjectState()
|
||||
@@ -83,44 +86,224 @@ function App() {
|
||||
console.log('[APP] ✅ File operations initialized')
|
||||
|
||||
const { activeFileId, setActiveFileId, handleFileChange, handleFileAdd, handleFileClose } = fileOps
|
||||
|
||||
console.log('[APP] 🌱 Initializing seed data hook')
|
||||
const { loadSeedData } = useSeedData()
|
||||
console.log('[APP] ✅ Seed data hook initialized')
|
||||
|
||||
console.log('[APP] 💾 Initializing state variables')
|
||||
const [activeTab, setActiveTab] = useState('dashboard')
|
||||
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)
|
||||
const [appReady, setAppReady] = useState(false)
|
||||
console.log('[APP] ✅ State variables initialized')
|
||||
|
||||
console.log('[APP] 🧮 Computing page configuration')
|
||||
const pageConfig = useMemo(() => {
|
||||
console.log('[APP] 📄 Getting page config')
|
||||
const config = getPageConfig()
|
||||
console.log('[APP] ✅ Page config retrieved:', Object.keys(config).length, 'pages')
|
||||
return config
|
||||
}, [])
|
||||
|
||||
const enabledPages = useMemo(() => {
|
||||
console.log('[APP] 🔍 Filtering enabled pages')
|
||||
const pages = getEnabledPages(featureToggles)
|
||||
console.log('[APP] ✅ Enabled pages:', pages.map(p => p.id).join(', '))
|
||||
return pages
|
||||
}, [featureToggles])
|
||||
|
||||
const shortcuts = useMemo(() => {
|
||||
console.log('[APP] ⌨️ Getting keyboard shortcuts')
|
||||
const s = getPageShortcuts(featureToggles)
|
||||
console.log('[APP] ✅ Shortcuts configured:', s.length)
|
||||
return s
|
||||
}, [featureToggles])
|
||||
const shortcuts = getPageShortcuts(featureToggles)
|
||||
console.log('[APP] ⌨️ Keyboard shortcuts configured:', shortcuts.length)
|
||||
|
||||
console.log('[APP] ⏰ Setting up initialization effect')
|
||||
console.log('[APP] ⌨️ Setting up keyboard shortcuts')
|
||||
useKeyboardShortcuts([
|
||||
...shortcuts.map(s => ({
|
||||
key: s.key,
|
||||
ctrl: s.ctrl,
|
||||
shift: s.shift,
|
||||
description: s.description,
|
||||
action: () => {
|
||||
console.log('[APP] ⌨️ Shortcut triggered, navigating to:', s.action)
|
||||
navigateToPage(s.action)
|
||||
}
|
||||
})),
|
||||
{
|
||||
key: 'k',
|
||||
ctrl: true,
|
||||
description: 'Search',
|
||||
action: () => {
|
||||
console.log('[APP] ⌨️ Search shortcut triggered')
|
||||
setSearchOpen(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '/',
|
||||
ctrl: true,
|
||||
description: 'Shortcuts',
|
||||
action: () => {
|
||||
console.log('[APP] ⌨️ Shortcuts dialog triggered')
|
||||
setShortcutsOpen(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'p',
|
||||
ctrl: true,
|
||||
description: 'Preview',
|
||||
action: () => {
|
||||
console.log('[APP] ⌨️ Preview shortcut triggered')
|
||||
setPreviewOpen(true)
|
||||
}
|
||||
},
|
||||
])
|
||||
console.log('[APP] ✅ 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] 📦 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] ✅ Project loaded successfully')
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[APP] 📍 Route changed to:', location.pathname, '- Page:', currentPage)
|
||||
}, [location, currentPage])
|
||||
|
||||
console.log('[APP] 🎨 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] 🔍 Search opened')
|
||||
setSearchOpen(true)
|
||||
}}
|
||||
onShowShortcuts={() => {
|
||||
console.log('[APP] ⌨️ Shortcuts dialog opened')
|
||||
setShortcutsOpen(true)
|
||||
}}
|
||||
onGenerateAI={() => {
|
||||
console.log('[APP] 🤖 AI generation requested')
|
||||
toast.info('AI generation coming soon')
|
||||
}}
|
||||
onExport={() => {
|
||||
console.log('[APP] 📤 Export requested')
|
||||
toast.info('Export coming soon')
|
||||
}}
|
||||
onPreview={() => {
|
||||
console.log('[APP] 👁️ Preview opened')
|
||||
setPreviewOpen(true)
|
||||
}}
|
||||
onShowErrors={() => {
|
||||
console.log('[APP] ⚠️ 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={navigateToPage}
|
||||
onFileSelect={setActiveFileId}
|
||||
/>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
|
||||
function App() {
|
||||
console.log('[APP] 🚀 App component initializing')
|
||||
console.log('[APP] 🌱 Initializing seed data hook')
|
||||
const { loadSeedData } = useSeedData()
|
||||
const [appReady, setAppReady] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[APP] 🚀 Initialization effect triggered')
|
||||
console.time('[APP] Seed data loading')
|
||||
@@ -155,235 +338,10 @@ function App() {
|
||||
}
|
||||
}, [loadSeedData])
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTab && appReady) {
|
||||
console.log('[APP] 🎯 Active tab changed to:', activeTab)
|
||||
const currentPage = enabledPages.find(p => p.id === activeTab)
|
||||
if (currentPage) {
|
||||
console.log('[APP] 📦 Preloading next likely components for:', activeTab)
|
||||
|
||||
const nextPages = enabledPages.slice(
|
||||
enabledPages.indexOf(currentPage) + 1,
|
||||
enabledPages.indexOf(currentPage) + 3
|
||||
)
|
||||
|
||||
nextPages.forEach(page => {
|
||||
const componentName = page.component as keyof typeof ComponentRegistry
|
||||
if (ComponentRegistry[componentName]) {
|
||||
console.log('[APP] 🔮 Preloading:', componentName)
|
||||
preloadComponentByName(componentName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [activeTab, appReady, enabledPages])
|
||||
|
||||
console.log('[APP] ⌨️ Configuring keyboard shortcuts')
|
||||
useKeyboardShortcuts([
|
||||
...shortcuts.map(s => ({
|
||||
key: s.key,
|
||||
ctrl: s.ctrl,
|
||||
shift: s.shift,
|
||||
description: s.description,
|
||||
action: () => setActiveTab(s.action)
|
||||
})),
|
||||
{ key: 'k', ctrl: true, description: 'Search', action: () => setSearchOpen(true) },
|
||||
{ key: '/', ctrl: true, description: 'Shortcuts', action: () => setShortcutsOpen(true) },
|
||||
{ key: 'p', ctrl: true, description: 'Preview', action: () => setPreviewOpen(true) },
|
||||
])
|
||||
console.log('[APP] ✅ 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) => {
|
||||
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')
|
||||
}
|
||||
|
||||
const getPropsForComponent = (pageId: string) => {
|
||||
const page = enabledPages.find(p => p.id === pageId)
|
||||
if (!page || !page.props) return {}
|
||||
|
||||
const stateContext = {
|
||||
files,
|
||||
models,
|
||||
components,
|
||||
componentTrees,
|
||||
workflows,
|
||||
lambdas,
|
||||
theme,
|
||||
playwrightTests,
|
||||
storybookStories,
|
||||
unitTests,
|
||||
flaskConfig,
|
||||
nextjsConfig,
|
||||
npmSettings,
|
||||
featureToggles,
|
||||
activeFileId,
|
||||
}
|
||||
|
||||
const actionContext = {
|
||||
handleFileChange,
|
||||
setActiveFileId,
|
||||
handleFileClose,
|
||||
handleFileAdd,
|
||||
setModels,
|
||||
setComponents,
|
||||
setComponentTrees,
|
||||
setWorkflows,
|
||||
setLambdas,
|
||||
setTheme,
|
||||
setPlaywrightTests,
|
||||
setStorybookStories,
|
||||
setUnitTests,
|
||||
setFlaskConfig,
|
||||
setNextjsConfig,
|
||||
setNpmSettings,
|
||||
setFeatureToggles,
|
||||
}
|
||||
|
||||
return resolveProps(page.props, stateContext, actionContext)
|
||||
}
|
||||
|
||||
const renderPageContent = (page: any) => {
|
||||
console.log('[APP] 🎨 Rendering page:', page.id)
|
||||
try {
|
||||
const Component = ComponentRegistry[page.component as keyof typeof ComponentRegistry] as any
|
||||
if (!Component) {
|
||||
console.error('[APP] ❌ Component not found:', page.component)
|
||||
return <LoadingFallback message={`Component ${page.component} not found`} />
|
||||
}
|
||||
console.log('[APP] ✅ Component found:', page.component)
|
||||
|
||||
if (page.requiresResizable && page.resizableConfig) {
|
||||
console.log('[APP] 🔀 Rendering resizable layout for:', page.id)
|
||||
const config = page.resizableConfig
|
||||
const LeftComponent = ComponentRegistry[config.leftComponent as keyof typeof ComponentRegistry] as any
|
||||
const RightComponent = Component
|
||||
|
||||
if (!LeftComponent) {
|
||||
console.error('[APP] ❌ Left component not found:', config.leftComponent)
|
||||
return <LoadingFallback message={`Component ${config.leftComponent} not found`} />
|
||||
}
|
||||
console.log('[APP] ✅ Resizable layout components ready')
|
||||
|
||||
const stateContext = {
|
||||
files,
|
||||
models,
|
||||
components,
|
||||
componentTrees,
|
||||
workflows,
|
||||
lambdas,
|
||||
theme,
|
||||
playwrightTests,
|
||||
storybookStories,
|
||||
unitTests,
|
||||
flaskConfig,
|
||||
nextjsConfig,
|
||||
npmSettings,
|
||||
featureToggles,
|
||||
activeFileId,
|
||||
}
|
||||
|
||||
const actionContext = {
|
||||
handleFileChange,
|
||||
setActiveFileId,
|
||||
handleFileClose,
|
||||
handleFileAdd,
|
||||
setModels,
|
||||
setComponents,
|
||||
setComponentTrees,
|
||||
setWorkflows,
|
||||
setLambdas,
|
||||
setTheme,
|
||||
setPlaywrightTests,
|
||||
setStorybookStories,
|
||||
setUnitTests,
|
||||
setFlaskConfig,
|
||||
setNextjsConfig,
|
||||
setNpmSettings,
|
||||
setFeatureToggles,
|
||||
}
|
||||
|
||||
const leftProps = resolveProps(config.leftProps, stateContext, actionContext)
|
||||
const rightProps = getPropsForComponent(page.id)
|
||||
|
||||
return (
|
||||
<ResizablePanelGroup direction="horizontal">
|
||||
<ResizablePanel
|
||||
defaultSize={config.leftPanel.defaultSize}
|
||||
minSize={config.leftPanel.minSize}
|
||||
maxSize={config.leftPanel.maxSize}
|
||||
>
|
||||
<Suspense fallback={<LoadingFallback message={`Loading ${config.leftComponent.toLowerCase()}...`} />}>
|
||||
<LeftComponent {...leftProps} />
|
||||
</Suspense>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize={config.rightPanel.defaultSize}>
|
||||
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
|
||||
<RightComponent {...rightProps} />
|
||||
</Suspense>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
)
|
||||
}
|
||||
|
||||
console.log('[APP] 📦 Rendering standard component:', page.component)
|
||||
const props = getPropsForComponent(page.id)
|
||||
return (
|
||||
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
|
||||
<Component {...props} />
|
||||
</Suspense>
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('[APP] ❌ Failed to render page', page.id, ':', error)
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<p className="text-destructive font-semibold">Failed to load {page.title}</p>
|
||||
<p className="text-sm text-muted-foreground mt-2">Check console for details</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[APP] 🎨 Rendering App component UI')
|
||||
console.log('[APP] App state - appReady:', appReady, 'activeTab:', activeTab)
|
||||
console.timeEnd('[APP] App render')
|
||||
console.log('[APP] 🎨 Rendering App component')
|
||||
|
||||
return (
|
||||
<div className="h-screen flex flex-col bg-background">
|
||||
<>
|
||||
{!appReady && (
|
||||
<div className="fixed inset-0 bg-background z-50 flex items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
@@ -392,66 +350,10 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Suspense fallback={<div className="h-1 bg-primary animate-pulse" />}>
|
||||
<PWAStatusBar />
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<PWAUpdatePrompt />
|
||||
</Suspense>
|
||||
<AppHeader
|
||||
activeTab={activeTab}
|
||||
onTabChange={setActiveTab}
|
||||
featureToggles={featureToggles}
|
||||
errorCount={errorCount}
|
||||
lastSaved={lastSaved}
|
||||
currentProject={getCurrentProject()}
|
||||
onProjectLoad={handleProjectLoad}
|
||||
onSearch={() => setSearchOpen(true)}
|
||||
onShowShortcuts={() => setShortcutsOpen(true)}
|
||||
onGenerateAI={() => toast.info('AI generation coming soon')}
|
||||
onExport={() => toast.info('Export coming soon')}
|
||||
onPreview={() => setPreviewOpen(true)}
|
||||
onShowErrors={() => setActiveTab('errors')}
|
||||
/>
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1 flex flex-col">
|
||||
<PageHeader activeTab={activeTab} />
|
||||
<div className="flex-1 overflow-hidden">
|
||||
{enabledPages.map(page => (
|
||||
<TabsContent key={page.id} value={page.id} className="h-full m-0">
|
||||
{renderPageContent(page)}
|
||||
</TabsContent>
|
||||
))}
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
<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={setActiveTab}
|
||||
onFileSelect={setActiveFileId}
|
||||
/>
|
||||
</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>
|
||||
<BrowserRouter>
|
||||
<AppLayout />
|
||||
</BrowserRouter>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user