incognitolm
asdl;f
d081604
Raw
History Blame Contribute Delete
2.87 kB
import { useState } from 'react';
import { VisualElement } from '../../types/blocks';
import { ChevronRight, ChevronDown } from 'lucide-react';
interface ElementTreeProps {
elements: VisualElement[];
selectedId: string | null;
onSelect: (id: string) => void;
onContextMenu?: (e: React.MouseEvent, id: string) => void;
depth?: number;
}
function TreeItem({
element, selectedId, onSelect, onContextMenu, depth,
}: {
element: VisualElement; selectedId: string | null; onSelect: (id: string) => void;
onContextMenu?: (e: React.MouseEvent, id: string) => void; depth: number;
}) {
const isSelected = selectedId === element.id;
const hasChildren = element.children && element.children.length > 0;
const [expanded, setExpanded] = useState(true);
return (
<div>
<div
className={`flex items-center gap-1 px-2 py-1 rounded-md cursor-pointer text-xs transition-colors ${
isSelected ? 'bg-primary-500/20 text-primary-300' : 'text-surface-300 hover:bg-surface-700/50'
}`}
style={{ paddingLeft: `${8 + depth * 14}px` }}
onClick={() => onSelect(element.id)}
onContextMenu={onContextMenu ? (e) => onContextMenu(e, element.id) : undefined}
>
{hasChildren ? (
<button onClick={(e) => { e.stopPropagation(); setExpanded(!expanded); }} className="p-0.5">
{expanded ? <ChevronDown className="w-3 h-3 text-surface-500" /> : <ChevronRight className="w-3 h-3 text-surface-500" />}
</button>
) : (
<span className="w-4" />
)}
<span className="text-primary-400">&lt;</span>
<span className="font-medium">{element.tagName}</span>
<span className="text-primary-400">&gt;</span>
{element.props?.id && <span className="text-surface-500">#{element.props.id}</span>}
{element.props?.textContent && (
<span className="text-surface-500 truncate max-w-[100px]">"{element.props.textContent}"</span>
)}
</div>
{hasChildren && expanded && (
<div>
{element.children!.map((child) => (
<TreeItem key={child.id} element={child} selectedId={selectedId}
onSelect={onSelect} onContextMenu={onContextMenu} depth={depth + 1} />
))}
</div>
)}
</div>
);
}
export default function ElementTree(props: ElementTreeProps) {
const { elements, selectedId, onSelect, onContextMenu, depth = 0 } = props;
if (!elements || elements.length === 0) {
return <div className="p-4 text-center text-surface-500 text-xs">No elements on the page</div>;
}
return (
<div className="p-2 space-y-0.5">
{elements.map((element) => (
<TreeItem key={element.id} element={element} selectedId={selectedId}
onSelect={onSelect} onContextMenu={onContextMenu} depth={depth} />
))}
</div>
);
}