Spaces:
Sleeping
Sleeping
| import { memo, useState } from 'react'; | |
| import { Handle, Position } from '@xyflow/react'; | |
| import { Bell, Box, Cloud, Code, Cpu, Database, GitBranch, Globe, Layers, Lock, Play } from 'lucide-react'; | |
| const ICONS = { Bell, Box, Cloud, Code, Cpu, Database, GitBranch, Globe, Layers, Lock, Play }; | |
| function WorkflowNode({ data, selected }) { | |
| const [editing, setEditing] = useState(false); | |
| const [label, setLabel] = useState(data.label); | |
| const isDecision = data.nodeType === 'decision'; | |
| const Icon = ICONS[data.iconName] || Cpu; | |
| return ( | |
| <div | |
| className={isDecision ? 'relative h-24 w-24 rotate-45 border transition-transform' : 'min-w-[150px] rounded-lg border px-3 py-3 transition-transform'} | |
| style={{ | |
| background: `linear-gradient(145deg, ${data.color}18, rgba(15,23,42,0.96))`, | |
| borderColor: selected ? data.color : `${data.color}55`, | |
| transform: `${isDecision ? 'rotate(45deg)' : ''} ${selected ? 'scale(1.04)' : ''}`, | |
| }} | |
| > | |
| <Handle type="target" position={isDecision ? Position.Top : Position.Left} style={{ background: data.color, border: 'none' }} /> | |
| {isDecision ? ( | |
| <div className="absolute inset-0 flex -rotate-45 items-center justify-center p-2 text-center"> | |
| <span className="text-[11px] font-semibold leading-tight text-white">{label}</span> | |
| </div> | |
| ) : ( | |
| <> | |
| <div className="mb-1.5 flex items-center gap-2"> | |
| <span className="flex h-7 w-7 items-center justify-center rounded-md" style={{ background: `${data.color}1f` }}> | |
| <Icon className="h-3.5 w-3.5" style={{ color: data.color }} /> | |
| </span> | |
| <span className="text-[10px] font-bold uppercase tracking-wide" style={{ color: data.color }}> | |
| {data.nodeType} | |
| </span> | |
| </div> | |
| {editing ? ( | |
| <input | |
| value={label} | |
| onChange={(event) => setLabel(event.target.value)} | |
| onBlur={() => { | |
| setEditing(false); | |
| data.label = label; | |
| }} | |
| autoFocus | |
| className="w-full border-b border-white/20 bg-transparent text-xs text-white outline-none" | |
| /> | |
| ) : ( | |
| <p onDoubleClick={() => setEditing(true)} className="path-text cursor-text text-xs font-semibold leading-snug text-white"> | |
| {label} | |
| </p> | |
| )} | |
| {data.description && <p className="path-text mt-1 text-[10px] leading-snug text-slate-500">{data.description}</p>} | |
| </> | |
| )} | |
| <Handle type="source" position={isDecision ? Position.Bottom : Position.Right} style={{ background: data.color, border: 'none' }} /> | |
| </div> | |
| ); | |
| } | |
| export default memo(WorkflowNode); | |