From 9b13431bd318243846bfe327b9899b73a2637878 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sat, 17 Jan 2026 20:09:04 +0000 Subject: [PATCH] Generated by Spark: Expand All, Collapse All buttons are too big, Maybe just use icon buttons? --- src/components/atoms/ComponentTreeNode.tsx | 21 +++- src/components/molecules/ComponentTree.tsx | 126 ++++++++++++++++----- 2 files changed, 117 insertions(+), 30 deletions(-) diff --git a/src/components/atoms/ComponentTreeNode.tsx b/src/components/atoms/ComponentTreeNode.tsx index 186bede..8b42047 100644 --- a/src/components/atoms/ComponentTreeNode.tsx +++ b/src/components/atoms/ComponentTreeNode.tsx @@ -17,6 +17,9 @@ interface ComponentTreeNodeProps { onDragLeave: (e: React.DragEvent) => void onDrop: (e: React.DragEvent) => void depth?: number + hasChildren?: boolean + isExpanded?: boolean + onToggleExpand?: () => void } export function ComponentTreeNode({ @@ -33,10 +36,12 @@ export function ComponentTreeNode({ onDragLeave, onDrop, depth = 0, + hasChildren = false, + isExpanded = false, + onToggleExpand, }: ComponentTreeNodeProps) { const def = getComponentDef(component.type) const IconComponent = def ? (Icons as any)[def.icon] || Icons.Cube : Icons.Cube - const hasChildren = Array.isArray(component.children) && component.children.length > 0 return (
@@ -67,7 +72,19 @@ export function ComponentTreeNode({ )} > {hasChildren ? ( - + ) : (
)} diff --git a/src/components/molecules/ComponentTree.tsx b/src/components/molecules/ComponentTree.tsx index 72cd9e6..6290fd4 100644 --- a/src/components/molecules/ComponentTree.tsx +++ b/src/components/molecules/ComponentTree.tsx @@ -1,9 +1,10 @@ +import { useState, useCallback } from 'react' import { UIComponent } from '@/types/json-ui' import { ComponentTreeNode } from '@/components/atoms/ComponentTreeNode' import { PanelHeader } from '@/components/atoms' import { ScrollArea } from '@/components/ui/scroll-area' import { Button } from '@/components/ui/button' -import { Tree, Plus } from '@phosphor-icons/react' +import { Tree, CaretDown, CaretRight } from '@phosphor-icons/react' interface ComponentTreeProps { components: UIComponent[] @@ -34,39 +35,108 @@ export function ComponentTree({ onDragLeave, onDrop, }: ComponentTreeProps) { + const [expandedIds, setExpandedIds] = useState>(new Set()) + + const getAllComponentIds = useCallback((comps: UIComponent[]): string[] => { + const ids: string[] = [] + const traverse = (components: UIComponent[]) => { + components.forEach((comp) => { + if (Array.isArray(comp.children) && comp.children.length > 0) { + ids.push(comp.id) + traverse(comp.children) + } + }) + } + traverse(comps) + return ids + }, []) + + const handleExpandAll = useCallback(() => { + const allIds = getAllComponentIds(components) + setExpandedIds(new Set(allIds)) + }, [components, getAllComponentIds]) + + const handleCollapseAll = useCallback(() => { + setExpandedIds(new Set()) + }, []) + + const toggleExpand = useCallback((id: string) => { + setExpandedIds((prev) => { + const next = new Set(prev) + if (next.has(id)) { + next.delete(id) + } else { + next.add(id) + } + return next + }) + }, []) + const renderTree = (comps: UIComponent[], depth = 0) => { - return comps.map((comp) => ( -
- onSelect(comp.id)} - onHover={() => onHover(comp.id)} - onHoverEnd={onHoverEnd} - onDragStart={(e) => onDragStart(comp.id, e)} - onDragOver={(e) => onDragOver(comp.id, e)} - onDragLeave={onDragLeave} - onDrop={(e) => onDrop(comp.id, e)} - depth={depth} - /> - {Array.isArray(comp.children) && comp.children.length > 0 && ( -
{renderTree(comp.children, depth + 1)}
- )} -
- )) + return comps.map((comp) => { + const hasChildren = Array.isArray(comp.children) && comp.children.length > 0 + const isExpanded = expandedIds.has(comp.id) + + return ( +
+ onSelect(comp.id)} + onHover={() => onHover(comp.id)} + onHoverEnd={onHoverEnd} + onDragStart={(e) => onDragStart(comp.id, e)} + onDragOver={(e) => onDragOver(comp.id, e)} + onDragLeave={onDragLeave} + onDrop={(e) => onDrop(comp.id, e)} + depth={depth} + hasChildren={hasChildren} + isExpanded={isExpanded} + onToggleExpand={() => toggleExpand(comp.id)} + /> + {hasChildren && isExpanded && comp.children && ( +
{renderTree(comp.children, depth + 1)}
+ )} +
+ ) + }) } return (
- } - /> +
+ } + /> + {components.length > 0 && ( +
+ + +
+ )} +