anycoder-ea74d65e / components /NodeCanvas.jsx
Kidizzz's picture
Upload components/NodeCanvas.jsx with huggingface_hub
98d5416 verified
Raw
History Blame Contribute Delete
3.92 kB
import React from 'react'
import Node from './Node'
export default function NodeCanvas({
nodes,
connections,
selectedNode,
onSelectNode,
onEditNode,
onDeleteNode,
onAddConnection,
onNodeDragStart
}) {
const getNodeColor = (type) => {
switch (type) {
case 'ceo': return 'from-yellow-500 to-amber-600'
case 'claude': return 'from-violet-500 to-purple-600'
case 'gemini': return 'from-blue-500 to-cyan-600'
case 'openai': return 'from-emerald-500 to-teal-600'
case 'llama': return 'from-orange-500 to-red-600'
default: return 'from-slate-500 to-slate-600'
}
}
const renderConnections = () => {
return connections.map(conn => {
const fromNode = nodes.find(n => n.id === conn.from)
const toNode = nodes.find(n => n.id === conn.to)
if (!fromNode || !toNode) return null
const fromX = fromNode.position.x + 140
const fromY = fromNode.position.y + 60
const toX = toNode.position.x + 140
const toY = toNode.position.y + 60
const midX = (fromX + toX) / 2
const controlOffset = Math.abs(toX - fromX) / 3
return (
<g key={conn.id}>
<path
d={`M ${fromX} ${fromY} C ${fromX + controlOffset} ${fromY}, ${toX - controlOffset} ${toY}, ${toX} ${toY}`}
className={`node-connection ${conn.active ? 'active' : ''}`}
markerEnd="url(#arrowhead)"
/>
<circle
cx={toX}
cy={toY}
r={6}
fill={conn.active ? '#22c55e' : '#64748b'}
className="cursor-pointer hover:fill-red-500 transition-colors"
onClick={() => {
if (confirm('Delete this connection?')) {
onDeleteNode(conn.id)
}
/>
</g>
)
})
}
return (
<div id="node-canvas" className="w-full h-full canvas-grid overflow-auto relative">
<svg className="absolute inset-0 w-full h-full pointer-events-none" style={{ minWidth: '100%', minHeight: '100%' }}>
<defs>
<marker
id="arrowhead"
markerWidth="10"
markerHeight="7"
refX="9"
refY="3.5"
orient="auto"
>
<polygon points="0 0, 10 3.5, 0 7" fill="#64748b" />
</marker>
</defs>
<g className="pointer-events-auto">
{renderConnections()}
</g>
</svg>
{nodes.map(node => (
<Node
key={node.id}
node={node}
isSelected={selectedNode?.id === node.id}
color={getNodeColor(node.type)}
onSelect={() => onSelectNode(node)}
onEdit={() => onEditNode(node)}
onDelete={() => onDeleteNode(node.id)}
onAddConnection={() => onAddConnection(node.id)}
onDragStart={(e) => onNodeDragStart(e, node)}
/>
))}
{nodes.length === 0 && (
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-center">
<div className="w-20 h-20 mx-auto mb-4 bg-slate-700/50 rounded-2xl flex items-center justify-center">
<svg className="w-10 h-10 text-slate-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
</svg>
</div>
<h3 className="text-lg font-medium text-slate-400">No agents yet</h3>
<p className="text-sm text-slate-500 mt-1">Click "Add Node" to create your first agent</p>
</div>
</div>
)}
</div>
)
}