+
+
+
+
-
-
CodeForge
-
+
+
CodeForge
+
Low-Code Next.js App Builder
-
+
setSearchDialogOpen(true)}
- className="gap-2"
+ className="shrink-0"
+ title="Search (Ctrl+K)"
>
-
- Search
-
- ⌘ K
-
+
0 && (
setActiveTab('errors')}
- className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground"
+ className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground shrink-0 relative"
+ title={`${autoDetectedErrors.length} ${autoDetectedErrors.length === 1 ? 'Error' : 'Errors'}`}
>
-
- {autoDetectedErrors.length} {autoDetectedErrors.length === 1 ? 'Error' : 'Errors'}
+
+
+ {autoDetectedErrors.length}
+
)}
- setActiveTab('features')}
- title="Toggle Features"
- >
-
-
setShortcutsDialogOpen(true)}
title="Keyboard Shortcuts (Ctrl+/)"
+ className="hidden sm:flex shrink-0"
>
-
+
-
+
AI Generate
-
+
+
+
+
- Export Project
+ Export
+
+
+
-
-
-
-
- Dashboard
-
- {safeFeatureToggles.codeEditor && (
-
-
- Code Editor
-
- )}
- {safeFeatureToggles.models && (
-
-
- Models
-
- )}
- {safeFeatureToggles.components && (
-
-
- Components
-
- )}
- {safeFeatureToggles.componentTrees && (
-
-
- Component Trees
-
- )}
- {safeFeatureToggles.workflows && (
-
-
- Workflows
-
- )}
- {safeFeatureToggles.lambdas && (
-
-
- Lambdas
-
- )}
- {safeFeatureToggles.styling && (
-
-
- Styling
-
- )}
- {safeFeatureToggles.flaskApi && (
-
-
- Flask API
-
- )}
-
-
- Settings
-
-
-
- PWA
-
- {safeFeatureToggles.faviconDesigner && (
-
-
- Favicon
-
- )}
-
-
- Features
-
- {safeFeatureToggles.playwright && (
-
-
- Playwright
-
- )}
- {safeFeatureToggles.storybook && (
-
-
- Storybook
-
- )}
- {safeFeatureToggles.unitTests && (
-
-
- Unit Tests
-
- )}
- {safeFeatureToggles.errorRepair && (
-
-
- Error Repair
- {autoDetectedErrors.length > 0 && (
-
- {autoDetectedErrors.length}
-
- )}
-
- )}
- {safeFeatureToggles.documentation && (
-
-
- Documentation
-
- )}
- {safeFeatureToggles.sassStyles && (
-
-
- Sass Styles
-
- )}
-
-
-
+
+
@@ -63,18 +79,18 @@ export function KeyboardShortcutsDialog({ open, onOpenChange }: KeyboardShortcut
Actions
+
-
void
+ featureToggles: FeatureToggles
+ errorCount?: number
+}
+
+export function NavigationMenu({
+ activeTab,
+ onTabChange,
+ featureToggles,
+ errorCount = 0,
+}: NavigationMenuProps) {
+ const [open, setOpen] = useState(false)
+
+ const navigationGroups: NavigationGroup[] = [
+ {
+ id: 'overview',
+ label: 'Overview',
+ items: [
+ {
+ id: 'dashboard',
+ label: 'Dashboard',
+ icon: ,
+ value: 'dashboard',
+ },
+ ],
+ },
+ {
+ id: 'development',
+ label: 'Development',
+ items: [
+ {
+ id: 'code',
+ label: 'Code Editor',
+ icon: ,
+ value: 'code',
+ featureKey: 'codeEditor',
+ },
+ {
+ id: 'models',
+ label: 'Models',
+ icon: ,
+ value: 'models',
+ featureKey: 'models',
+ },
+ {
+ id: 'components',
+ label: 'Components',
+ icon: ,
+ value: 'components',
+ featureKey: 'components',
+ },
+ {
+ id: 'component-trees',
+ label: 'Component Trees',
+ icon: ,
+ value: 'component-trees',
+ featureKey: 'componentTrees',
+ },
+ ],
+ },
+ {
+ id: 'automation',
+ label: 'Automation',
+ items: [
+ {
+ id: 'workflows',
+ label: 'Workflows',
+ icon: ,
+ value: 'workflows',
+ featureKey: 'workflows',
+ },
+ {
+ id: 'lambdas',
+ label: 'Lambdas',
+ icon: ,
+ value: 'lambdas',
+ featureKey: 'lambdas',
+ },
+ ],
+ },
+ {
+ id: 'design',
+ label: 'Design & Styling',
+ items: [
+ {
+ id: 'styling',
+ label: 'Styling',
+ icon: ,
+ value: 'styling',
+ featureKey: 'styling',
+ },
+ {
+ id: 'sass',
+ label: 'Sass Styles',
+ icon: ,
+ value: 'sass',
+ featureKey: 'sassStyles',
+ },
+ {
+ id: 'favicon',
+ label: 'Favicon Designer',
+ icon: ,
+ value: 'favicon',
+ featureKey: 'faviconDesigner',
+ },
+ ],
+ },
+ {
+ id: 'backend',
+ label: 'Backend',
+ items: [
+ {
+ id: 'flask',
+ label: 'Flask API',
+ icon: ,
+ value: 'flask',
+ featureKey: 'flaskApi',
+ },
+ ],
+ },
+ {
+ id: 'testing',
+ label: 'Testing',
+ items: [
+ {
+ id: 'playwright',
+ label: 'Playwright',
+ icon: ,
+ value: 'playwright',
+ featureKey: 'playwright',
+ },
+ {
+ id: 'storybook',
+ label: 'Storybook',
+ icon: ,
+ value: 'storybook',
+ featureKey: 'storybook',
+ },
+ {
+ id: 'unit-tests',
+ label: 'Unit Tests',
+ icon: ,
+ value: 'unit-tests',
+ featureKey: 'unitTests',
+ },
+ ],
+ },
+ {
+ id: 'tools',
+ label: 'Tools & Configuration',
+ items: [
+ {
+ id: 'errors',
+ label: 'Error Repair',
+ icon: ,
+ value: 'errors',
+ badge: errorCount,
+ featureKey: 'errorRepair',
+ },
+ {
+ id: 'docs',
+ label: 'Documentation',
+ icon: ,
+ value: 'docs',
+ featureKey: 'documentation',
+ },
+ {
+ id: 'settings',
+ label: 'Settings',
+ icon: ,
+ value: 'settings',
+ },
+ {
+ id: 'pwa',
+ label: 'PWA',
+ icon: ,
+ value: 'pwa',
+ },
+ {
+ id: 'features',
+ label: 'Features',
+ icon: ,
+ value: 'features',
+ },
+ ],
+ },
+ ]
+
+ const handleItemClick = (value: string) => {
+ onTabChange(value)
+ setOpen(false)
+ }
+
+ const isItemVisible = (item: NavigationItem) => {
+ if (!item.featureKey) return true
+ return featureToggles[item.featureKey]
+ }
+
+ const getVisibleItemsCount = (group: NavigationGroup) => {
+ return group.items.filter(isItemVisible).length
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ Navigation
+
+
+
+ {navigationGroups.map((group) => {
+ const visibleItemsCount = getVisibleItemsCount(group)
+ if (visibleItemsCount === 0) return null
+
+ return (
+
+
+ {group.label}
+
+
+ {group.items.map((item) => {
+ if (!isItemVisible(item)) return null
+
+ const isActive = activeTab === item.value
+
+ return (
+ handleItemClick(item.value)}
+ className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-colors ${
+ isActive
+ ? 'bg-primary text-primary-foreground'
+ : 'hover:bg-muted text-foreground'
+ }`}
+ >
+
+ {item.icon}
+
+
+ {item.label}
+
+ {item.badge !== undefined && item.badge > 0 && (
+
+ {item.badge}
+
+ )}
+
+ )
+ })}
+
+
+ )
+ })}
+
+
+
+
+ )
+}
diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx
new file mode 100644
index 0000000..934a927
--- /dev/null
+++ b/src/components/PageHeader.tsx
@@ -0,0 +1,145 @@
+import {
+ ChartBar,
+ Code,
+ Database,
+ Tree,
+ FlowArrow,
+ PaintBrush,
+ Flask,
+ Play,
+ BookOpen,
+ Cube,
+ Wrench,
+ FileText,
+ Gear,
+ DeviceMobile,
+ Image,
+ Faders,
+} from '@phosphor-icons/react'
+
+interface PageHeaderProps {
+ activeTab: string
+}
+
+const tabInfo: Record = {
+ dashboard: {
+ title: 'Dashboard',
+ icon: ,
+ description: 'Project overview and statistics',
+ },
+ code: {
+ title: 'Code Editor',
+ icon: ,
+ description: 'Edit project files',
+ },
+ models: {
+ title: 'Models',
+ icon: ,
+ description: 'Define Prisma data models',
+ },
+ components: {
+ title: 'Components',
+ icon: ,
+ description: 'Create React components',
+ },
+ 'component-trees': {
+ title: 'Component Trees',
+ icon: ,
+ description: 'Manage component hierarchies',
+ },
+ workflows: {
+ title: 'Workflows',
+ icon: ,
+ description: 'Design automation workflows',
+ },
+ lambdas: {
+ title: 'Lambdas',
+ icon: ,
+ description: 'Serverless functions',
+ },
+ styling: {
+ title: 'Styling',
+ icon: ,
+ description: 'Theme and design tokens',
+ },
+ sass: {
+ title: 'Sass Styles',
+ icon: ,
+ description: 'Custom Sass stylesheets',
+ },
+ favicon: {
+ title: 'Favicon Designer',
+ icon: ,
+ description: 'Design app icons',
+ },
+ flask: {
+ title: 'Flask API',
+ icon: ,
+ description: 'Backend API configuration',
+ },
+ playwright: {
+ title: 'Playwright',
+ icon: ,
+ description: 'E2E test scenarios',
+ },
+ storybook: {
+ title: 'Storybook',
+ icon: ,
+ description: 'Component documentation',
+ },
+ 'unit-tests': {
+ title: 'Unit Tests',
+ icon: ,
+ description: 'Unit test suites',
+ },
+ errors: {
+ title: 'Error Repair',
+ icon: ,
+ description: 'Automated error detection and fixing',
+ },
+ docs: {
+ title: 'Documentation',
+ icon: ,
+ description: 'Project guides and references',
+ },
+ settings: {
+ title: 'Settings',
+ icon: ,
+ description: 'Project configuration',
+ },
+ pwa: {
+ title: 'PWA',
+ icon: ,
+ description: 'Progressive Web App settings',
+ },
+ features: {
+ title: 'Features',
+ icon: ,
+ description: 'Toggle feature modules',
+ },
+}
+
+export function PageHeader({ activeTab }: PageHeaderProps) {
+ const info = tabInfo[activeTab] || {
+ title: 'Unknown',
+ icon: ,
+ }
+
+ return (
+
+
+
+ {info.icon}
+
+
+
{info.title}
+ {info.description && (
+
+ {info.description}
+
+ )}
+
+
+
+ )
+}