feat: Implement JSON components with wrappers for LoadingFallback, NavigationItem, PageHeaderContent

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-18 22:07:45 +00:00
parent a386551f23
commit a65a994ec4
12 changed files with 401 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
import { Card, Badge, ActionIcon, IconButton, Stack, Flex, Text, Heading } from '@/components/atoms'
import { ComponentTree } from '@/types/project'
interface TreeCardProps {
tree: ComponentTree
isSelected: boolean
onSelect: () => void
onEdit: () => void
onDuplicate: () => void
onDelete: () => void
disableDelete?: boolean
}
export function TreeCard({
tree,
isSelected,
onSelect,
onEdit,
onDuplicate,
onDelete,
disableDelete = false,
}: TreeCardProps) {
return (
<Card
className={`cursor-pointer transition-all p-4 ${
isSelected ? 'ring-2 ring-primary bg-accent' : 'hover:bg-accent/50'
}`}
onClick={onSelect}
>
<Stack spacing="sm">
<Flex justify="between" align="start" gap="sm">
<Stack spacing="xs" className="flex-1 min-w-0">
<Heading level={4} className="text-sm truncate">{tree.name}</Heading>
{tree.description && (
<Text variant="caption" className="line-clamp-2">
{tree.description}
</Text>
)}
<div>
<Badge variant="outline" className="text-xs">
{tree.rootNodes.length} components
</Badge>
</div>
</Stack>
</Flex>
<div onClick={(e) => e.stopPropagation()}>
<Flex gap="xs" className="mt-1">
<IconButton
icon={<ActionIcon action="edit" size={14} />}
variant="ghost"
size="sm"
onClick={onEdit}
title="Edit tree"
/>
<IconButton
icon={<ActionIcon action="copy" size={14} />}
variant="ghost"
size="sm"
onClick={onDuplicate}
title="Duplicate tree"
/>
<IconButton
icon={<ActionIcon action="delete" size={14} />}
variant="ghost"
size="sm"
onClick={onDelete}
disabled={disableDelete}
title="Delete tree"
/>
</Flex>
</div>
</Stack>
</Card>
)
}

View File

@@ -0,0 +1,53 @@
import { Button, TreeIcon, ActionIcon, Flex, Heading, Stack, IconButton } from '@/components/atoms'
interface TreeListHeaderProps {
onCreateNew: () => void
onImportJson: () => void
onExportJson: () => void
hasSelectedTree?: boolean
}
export function TreeListHeader({
onCreateNew,
onImportJson,
onExportJson,
hasSelectedTree = false,
}: TreeListHeaderProps) {
return (
<Stack spacing="sm">
<Flex justify="between" align="center">
<Flex align="center" gap="sm">
<TreeIcon size={20} />
<Heading level={2} className="text-lg font-semibold">Component Trees</Heading>
</Flex>
<IconButton
icon={<ActionIcon action="add" size={16} />}
size="sm"
onClick={onCreateNew}
/>
</Flex>
<Flex gap="sm">
<Button
size="sm"
variant="outline"
onClick={onImportJson}
className="flex-1 text-xs"
leftIcon={<ActionIcon action="upload" size={14} />}
>
Import JSON
</Button>
<Button
size="sm"
variant="outline"
onClick={onExportJson}
disabled={!hasSelectedTree}
className="flex-1 text-xs"
leftIcon={<ActionIcon action="download" size={14} />}
>
Export JSON
</Button>
</Flex>
</Stack>
)
}

View File

@@ -18,3 +18,9 @@ export { SearchInput } from './SearchInput'
export { BindingEditor } from './BindingEditor'
export { DataSourceEditorDialog } from './DataSourceEditorDialog'
export { ComponentBindingDialog } from './ComponentBindingDialog'
export { TreeCard } from './TreeCard'
export { TreeListHeader } from './TreeListHeader'
export { LoadingFallbackWrapper as LoadingFallback } from '@/lib/json-ui/wrappers'
export { NavigationItemWrapper as NavigationItem } from '@/lib/json-ui/wrappers'
export { PageHeaderContentWrapper as PageHeaderContent } from '@/lib/json-ui/wrappers'
export { preloadMonacoEditor } from './LazyMonacoEditor'