Spaces:
Build error
Build error
| import React from 'react' | |
| export default function Node({ | |
| node, | |
| isSelected, | |
| color, | |
| onSelect, | |
| onEdit, | |
| onDelete, | |
| onAddConnection, | |
| onDragStart | |
| }) { | |
| const getModelIcon = (model) => { | |
| if (model?.includes('claude')) return 'π§ ' | |
| if (model?.includes('gemini')) return 'π' | |
| if (model?.includes('gpt')) return 'π€' | |
| if (model?.includes('llama')) return 'π¦' | |
| return 'β‘' | |
| } | |
| return ( | |
| <div | |
| className={`absolute cursor-move select-none ${isSelected ? 'z-20' : 'z-10'}`} | |
| style={{ | |
| left: node.position.x, | |
| top: node.position.y | |
| onMouseDown={onDragStart} | |
| > | |
| <div | |
| className={`w-72 bg-slate-800 rounded-2xl border-2 transition-all ${ | |
| isSelected | |
| ? 'border-violet-500 shadow-lg shadow-violet-500/20' | |
| : 'border-slate-700 hover:border-slate-600' | |
| }`} | |
| onClick={(e) => { | |
| e.stopPropagation() | |
| onSelect() | |
| > | |
| {/* Header */} | |
| <div className={`bg-gradient-to-r ${color} p-3 rounded-t-xl flex items-center gap-3`}> | |
| <div className="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center text-xl backdrop-blur-sm"> | |
| {node.type === 'ceo' ? 'π' : getModelIcon(node.model)} | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <h3 className="font-bold text-white truncate">{node.name}</h3> | |
| <p className="text-xs text-white/70 truncate">{node.model}</p> | |
| </div> | |
| {node.type === 'ceo' && ( | |
| <span className="px-2 py-0.5 bg-white/20 rounded-full text-xs text-white font-medium"> | |
| CEO | |
| </span> | |
| )} | |
| </div> | |
| {/* Body */} | |
| <div className="p-3"> | |
| <p className="text-xs text-slate-400 line-clamp-2 mb-3"> | |
| {node.brief || 'No brief set'} | |
| </p> | |
| <div className="flex items-center gap-2 mb-3"> | |
| <div className={`w-2 h-2 rounded-full ${node.apiKey ? 'bg-emerald-400' : 'bg-red-400'}`}></div> | |
| <span className="text-xs text-slate-500"> | |
| {node.apiKey ? 'API Key Set' : 'No API Key'} | |
| </span> | |
| </div> | |
| {/* Actions */} | |
| <div className="flex gap-2"> | |
| <button | |
| onClick={(e) => { | |
| e.stopPropagation() | |
| onEdit() | |
| className="flex-1 px-3 py-1.5 bg-slate-700 hover:bg-slate-600 rounded-lg text-xs text-slate-300 transition-colors" | |
| > | |
| βοΈ Settings | |
| </button> | |
| <button | |
| onClick={(e) => { | |
| e.stopPropagation() | |
| onAddConnection() | |
| className="flex-1 px-3 py-1.5 bg-slate-700 hover:bg-slate-600 rounded-lg text-xs text-slate-300 transition-colors" | |
| > | |
| π Connect | |
| </button> | |
| {node.type !== 'ceo' && ( | |
| <button | |
| onClick={(e) => { | |
| e.stopPropagation() | |
| if (confirm('Delete this node?')) { | |
| onDelete() | |
| } | |
| className="px-3 py-1.5 bg-red-900/30 hover:bg-red-900/50 rounded-lg text-xs text-red-400 transition-colors" | |
| > | |
| ποΈ | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| {/* Connection Points */} | |
| <div className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-2 w-4 h-4 bg-slate-600 rounded-full border-2 border-slate-500 hover:bg-violet-500 hover:border-violet-400 transition-colors cursor-crosshair"></div> | |
| <div className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-2 w-4 h-4 bg-slate-600 rounded-full border-2 border-slate-500 hover:bg-violet-500 hover:border-violet-400 transition-colors cursor-crosshair"></div> | |
| </div> | |
| </div> | |
| ) | |
| } |