diff --git a/src/components/app/AppLayout.tsx b/src/components/app/AppLayout.tsx index 1fb0ef0..ba9aab1 100644 --- a/src/components/app/AppLayout.tsx +++ b/src/components/app/AppLayout.tsx @@ -3,7 +3,7 @@ import { toast } from 'sonner' import AppDialogs from '@/components/app/AppDialogs' import AppMainPanel from '@/components/app/AppMainPanel' -import { NavigationMenu } from '@/components/organisms/NavigationMenu' +import { NavigationMenu } from '@/lib/json-ui/json-components' import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar' import appStrings from '@/data/app-shortcuts.json' import useAppNavigation from '@/hooks/use-app-navigation' diff --git a/src/components/app/AppMainPanel.tsx b/src/components/app/AppMainPanel.tsx index 18708d7..bed429d 100644 --- a/src/components/app/AppMainPanel.tsx +++ b/src/components/app/AppMainPanel.tsx @@ -1,6 +1,6 @@ import { Suspense } from 'react' -import { AppHeader } from '@/components/organisms' +import { AppHeader } from '@/lib/json-ui/json-components' import { PWARegistry } from '@/lib/component-registry' import { RouterProvider } from '@/router' import type { FeatureToggles, Project } from '@/types/project' diff --git a/src/components/organisms/AppHeader.tsx b/src/components/organisms/AppHeader.tsx deleted file mode 100644 index 5e36bb1..0000000 --- a/src/components/organisms/AppHeader.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { AppBranding, Breadcrumb, SaveIndicator } from '@/components/molecules' -import { SidebarTrigger } from '@/components/ui/sidebar' -import { ToolbarActions } from '@/components/organisms/ToolbarActions' -import { ProjectManager } from '@/components/ProjectManager' -import { FeatureToggles, Project } from '@/types/project' -import { Flex, Stack, Separator, Container } from '@/components/atoms' - -interface AppHeaderProps { - activeTab: string - onTabChange: (tab: 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 -} - -export function AppHeader({ - activeTab, - onTabChange, - featureToggles, - errorCount, - lastSaved, - currentProject, - onProjectLoad, - onSearch, - onShowShortcuts, - onGenerateAI, - onExport, - onPreview, - onShowErrors, -}: AppHeaderProps) { - return ( -
- -
- - - - - - - - - 0} - /> - - -
- -
- -
-
-
- ) -} diff --git a/src/components/organisms/EmptyCanvasState.tsx b/src/components/organisms/EmptyCanvasState.tsx deleted file mode 100644 index c80e4b0..0000000 --- a/src/components/organisms/EmptyCanvasState.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Plus, Folder } from '@phosphor-icons/react' -import { EmptyState, ActionButton, Stack } from '@/components/atoms' - -interface EmptyCanvasStateProps { - onAddFirstComponent?: () => void - onImportSchema?: () => void -} - -export function EmptyCanvasState({ onAddFirstComponent, onImportSchema }: EmptyCanvasStateProps) { - return ( -
- } - title="Empty Canvas" - description="Start building your UI by dragging components from the left panel, or import an existing schema." - > - - {onImportSchema && ( - } - label="Import Schema" - onClick={onImportSchema} - variant="outline" - /> - )} - {onAddFirstComponent && ( - } - label="Add Component" - onClick={onAddFirstComponent} - variant="default" - /> - )} - - -
- ) -} diff --git a/src/components/organisms/NavigationMenu.tsx b/src/components/organisms/NavigationMenu.tsx deleted file mode 100644 index b077790..0000000 --- a/src/components/organisms/NavigationMenu.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import { useState } from 'react' -import { Button } from '@/components/ui/button' -import { Sidebar, SidebarContent, SidebarHeader } from '@/components/ui/sidebar' -import { ScrollArea } from '@/components/ui/scroll-area' -import { Collapsible, CollapsibleContent } from '@/components/ui/collapsible' -import { CaretDoubleDown, CaretDoubleUp, CaretDown } from '@phosphor-icons/react' -import { CollapsibleTrigger } from '@/components/ui/collapsible' -import { Badge, Flex, Text, IconWrapper } from '@/components/atoms' -import { navigationGroups, NavigationItemData } from '@/lib/navigation-config' -import { FeatureToggles } from '@/types/project' -import { useRoutePreload } from '@/hooks/use-route-preload' -import navigationMenuCopy from '@/data/navigation-menu.json' - -interface NavigationMenuProps { - activeTab: string - onTabChange: (tab: string) => void - featureToggles: FeatureToggles - errorCount?: number -} - -interface NavigationMenuControlsProps { - onExpandAll: () => void - onCollapseAll: () => void -} - -interface NavigationMenuGroupListProps { - activeTab: string - expandedGroups: Set - featureToggles: FeatureToggles - errorCount: number - onToggleGroup: (groupId: string) => void - onItemClick: (value: string) => void - onItemHover: (value: string) => void - onItemLeave: (value: string) => void -} - -function NavigationMenuControls({ - onExpandAll, - onCollapseAll, -}: NavigationMenuControlsProps) { - return ( -
- - -
- ) -} - -function NavigationMenuHeader({ - onExpandAll, - onCollapseAll, -}: NavigationMenuControlsProps) { - return ( - -

{navigationMenuCopy.labels.title}

- -
- ) -} - -function NavigationMenuGroupList({ - activeTab, - expandedGroups, - featureToggles, - errorCount, - onToggleGroup, - onItemClick, - onItemHover, - onItemLeave, -}: NavigationMenuGroupListProps) { - const isItemVisible = (item: NavigationItemData) => { - if (!item.featureKey) return true - return featureToggles[item.featureKey] - } - - const getVisibleItemsCount = (groupId: string) => { - const group = navigationGroups.find((g) => g.id === groupId) - if (!group) return 0 - return group.items.filter(isItemVisible).length - } - - const getItemBadge = (item: NavigationItemData) => { - if (item.id === 'errors') return errorCount - return item.badge - } - - return ( -
- {navigationGroups.map((group) => { - const visibleItemsCount = getVisibleItemsCount(group.id) - if (visibleItemsCount === 0) return null - - const isExpanded = expandedGroups.has(group.id) - - return ( - onToggleGroup(group.id)} - > - {/* NavigationGroupHeader - inlined */} - - -

- {group.label} -

- {visibleItemsCount} -
- -
- {group.items.map((item) => { - if (!isItemVisible(item)) return null - - const isActive = activeTab === item.value - const badge = getItemBadge(item) - - return ( -
onItemHover(item.value)} - onMouseLeave={() => onItemLeave(item.value)} - > - {/* NavigationItem - inlined */} - -
- ) - })} -
-
-
- ) - })} -
- ) -} - -export function NavigationMenu({ - activeTab, - onTabChange, - featureToggles, - errorCount = 0, -}: NavigationMenuProps) { - const [expandedGroups, setExpandedGroups] = useState>( - new Set(['overview', 'development', 'automation', 'design', 'backend', 'testing', 'tools']) - ) - - const { preloadRoute, cancelPreload } = useRoutePreload({ delay: 100 }) - - const handleItemClick = (value: string) => { - onTabChange(value) - } - - const handleItemHover = (value: string) => { - console.log(`[NAV] 🖱️ Hover detected on: ${value}`) - preloadRoute(value) - } - - const handleItemLeave = (value: string) => { - console.log(`[NAV] 👋 Hover left: ${value}`) - cancelPreload(value) - } - - const toggleGroup = (groupId: string) => { - setExpandedGroups((prev) => { - const newSet = new Set(prev) - if (newSet.has(groupId)) { - newSet.delete(groupId) - } else { - newSet.add(groupId) - } - return newSet - }) - } - - const handleExpandAll = () => { - const allGroupIds = navigationGroups - .filter((group) => - group.items.some((item) => { - if (!item.featureKey) return true - return featureToggles[item.featureKey] - }) - ) - .map((group) => group.id) - setExpandedGroups(new Set(allGroupIds)) - } - - const handleCollapseAll = () => { - setExpandedGroups(new Set()) - } - - return ( - - - - - - - - - ) -} diff --git a/src/components/organisms/PageHeader.tsx b/src/components/organisms/PageHeader.tsx deleted file mode 100644 index 19bd020..0000000 --- a/src/components/organisms/PageHeader.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Stack, Container } from '@/components/atoms' -import { TabIcon } from '@/lib/json-ui/json-components' -import { tabInfo } from '@/lib/navigation-config' - -interface PageHeaderProps { - activeTab: string -} - -export function PageHeader({ activeTab }: PageHeaderProps) { - const info = tabInfo[activeTab] - - if (!info) return null - - return ( - - {/* PageHeaderContent - inlined */} -
- -
-

{info.title}

- {info.description && ( -

- {info.description} -

- )} -
-
-
- ) -} diff --git a/src/components/organisms/SchemaCodeViewer.tsx b/src/components/organisms/SchemaCodeViewer.tsx deleted file mode 100644 index db138a5..0000000 --- a/src/components/organisms/SchemaCodeViewer.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { ScrollArea } from '@/components/ui/scroll-area' -import { Code, Eye } from '@phosphor-icons/react' -import { UIComponent } from '@/types/json-ui' -import { PanelHeader, Text, Code as CodeAtom, Stack, IconText } from '@/components/atoms' - -interface SchemaCodeViewerProps { - components: UIComponent[] - schema: any -} - -export function SchemaCodeViewer({ components, schema }: SchemaCodeViewerProps) { - const jsonString = JSON.stringify(schema, null, 2) - - return ( -
- } /> - - - - JSON - Preview - - - - -
-              {jsonString}
-            
-
-
- - -
- - Live preview coming soon - -
-
-
-
- ) -} diff --git a/src/components/organisms/ToolbarActions.tsx b/src/components/organisms/ToolbarActions.tsx deleted file mode 100644 index 513a29c..0000000 --- a/src/components/organisms/ToolbarActions.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { ToolbarButton } from '@/components/molecules' -import { ErrorBadge, Flex, Tooltip, Badge } from '@/components/atoms' -import { - MagnifyingGlass, - Keyboard, - Sparkle, - Download, - Wrench, - Eye, -} from '@phosphor-icons/react' - -interface ToolbarActionsProps { - onSearch: () => void - onShowShortcuts: () => void - onGenerateAI: () => void - onExport: () => void - onPreview?: () => void - onShowErrors?: () => void - errorCount?: number - showErrorButton?: boolean -} - -export function ToolbarActions({ - onSearch, - onShowShortcuts, - onGenerateAI, - onExport, - onPreview, - onShowErrors, - errorCount = 0, - showErrorButton = false, -}: ToolbarActionsProps) { - return ( - - } - label="Search (Ctrl+K)" - onClick={onSearch} - data-search-trigger - /> - - {showErrorButton && errorCount > 0 && onShowErrors && ( -
- } - label={`${errorCount} ${errorCount === 1 ? 'Error' : 'Errors'}`} - onClick={onShowErrors} - variant="outline" - className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground" - /> - -
- )} - - {onPreview && ( - } - label="Preview (Ctrl+P)" - onClick={onPreview} - variant="outline" - /> - )} - - } - label="Keyboard Shortcuts (Ctrl+/)" - onClick={onShowShortcuts} - variant="ghost" - className="hidden sm:flex" - /> - - } - label="AI Generate (Ctrl+Shift+G)" - onClick={onGenerateAI} - /> - - } - label="Export Project (Ctrl+E)" - onClick={onExport} - variant="default" - /> -
- ) -} diff --git a/src/components/organisms/TreeListPanel.tsx b/src/components/organisms/TreeListPanel.tsx deleted file mode 100644 index f5ca05d..0000000 --- a/src/components/organisms/TreeListPanel.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { ScrollArea } from '@/components/ui/scroll-area' -import { EmptyState, Stack, Container, Card, Badge, ActionIcon, IconButton, Flex, Text, Heading, Button, TreeIcon } from '@/components/atoms' -import { ComponentTree } from '@/types/project' -import { FolderOpen } from '@phosphor-icons/react' - -interface TreeListPanelProps { - trees: ComponentTree[] - selectedTreeId: string | null - onTreeSelect: (treeId: string) => void - onTreeEdit: (tree: ComponentTree) => void - onTreeDuplicate: (tree: ComponentTree) => void - onTreeDelete: (treeId: string) => void - onCreateNew: () => void - onImportJson: () => void - onExportJson: () => void -} - -export function TreeListPanel({ - trees, - selectedTreeId, - onTreeSelect, - onTreeEdit, - onTreeDuplicate, - onTreeDelete, - onCreateNew, - onImportJson, - onExportJson, -}: TreeListPanelProps) { - return ( -
- {/* TreeListHeader - inlined */} - - - - - Component Trees - - } - size="sm" - onClick={onCreateNew} - /> - - - - - - - - - {trees.length === 0 ? ( - - } - title="No component trees yet" - description="Create your first tree to get started" - action={{ - label: 'Create First Tree', - onClick: onCreateNew - }} - /> - - ) : ( - - - {trees.map((tree) => { - const isSelected = selectedTreeId === tree.id - const disableDelete = trees.length === 1 - - return ( - // TreeCard - inlined - onTreeSelect(tree.id)} - > - - - - {tree.name} - {tree.description && ( - - {tree.description} - - )} -
- - {tree.rootNodes.length} components - -
-
-
-
e.stopPropagation()}> - - } - variant="ghost" - size="sm" - onClick={() => onTreeEdit(tree)} - title="Edit tree" - /> - } - variant="ghost" - size="sm" - onClick={() => onTreeDuplicate(tree)} - title="Duplicate tree" - /> - } - variant="ghost" - size="sm" - onClick={() => onTreeDelete(tree.id)} - disabled={disableDelete} - title={disableDelete ? "Can't delete last tree" : "Delete tree"} - /> - -
-
-
- ) - })} -
-
- )} -
- ) -} - diff --git a/src/components/organisms/index.ts b/src/components/organisms/index.ts index 7d6a368..c0115e5 100644 --- a/src/components/organisms/index.ts +++ b/src/components/organisms/index.ts @@ -1,6 +1,7 @@ -export { NavigationMenu } from './NavigationMenu' -export { AppHeader } from './AppHeader' -export { TreeListPanel } from './TreeListPanel' export { SchemaEditorLayout } from './SchemaEditorLayout' -export { SchemaCodeViewer } from './SchemaCodeViewer' +export { SchemaEditorCanvas } from './SchemaEditorCanvas' +export { SchemaEditorPropertiesPanel } from './SchemaEditorPropertiesPanel' +export { SchemaEditorSidebar } from './SchemaEditorSidebar' +export { SchemaEditorStatusBar } from './SchemaEditorStatusBar' +export { SchemaEditorToolbar } from './SchemaEditorToolbar' export { JSONUIShowcase } from '../JSONUIShowcase'