1d22adc42e
Backend (Express + MariaDB) y frontend (React + Vite, identidad Fluent/Windows) con el nucleo funcional: seguridad, organizacion, proyectos, actividades, subtareas, dependencias, dashboard, calendario, gantt, comentarios, adjuntos, notificaciones in-app y catalogos. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
1.3 KiB
React
40 lines
1.3 KiB
React
import { useState } from 'react';
|
|
import { ChevronRight, ChevronDown, Folder } from 'lucide-react';
|
|
|
|
function TreeNode({ node, level, onSelect, selectedId }) {
|
|
const [open, setOpen] = useState(true);
|
|
const hasChildren = node.children && node.children.length > 0;
|
|
return (
|
|
<div>
|
|
<div
|
|
className="tree-item-row"
|
|
style={{ paddingLeft: level * 18 + 6, background: selectedId === node.id ? 'rgb(var(--accent) / .14)' : undefined }}
|
|
onClick={() => onSelect?.(node)}
|
|
>
|
|
{hasChildren ? (
|
|
<button className="tree-toggle" onClick={(e) => { e.stopPropagation(); setOpen((v) => !v); }}>
|
|
{open ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
|
|
</button>
|
|
) : (
|
|
<span className="tree-toggle" />
|
|
)}
|
|
<Folder size={15} style={{ opacity: .7 }} />
|
|
<span>{node.name}</span>
|
|
</div>
|
|
{hasChildren && open && node.children.map((child) => (
|
|
<TreeNode key={child.id} node={child} level={level + 1} onSelect={onSelect} selectedId={selectedId} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function Treeview({ nodes, onSelect, selectedId }) {
|
|
return (
|
|
<div>
|
|
{nodes.map((node) => (
|
|
<TreeNode key={node.id} node={node} level={0} onSelect={onSelect} selectedId={selectedId} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|