chore: estructura inicial del MVP
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>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user