rfunds-online/components/edges/StreamEdge.tsx

126 lines
3.3 KiB
TypeScript

'use client'
import {
getSmoothStepPath,
EdgeLabelRenderer,
BaseEdge,
type EdgeProps,
} from '@xyflow/react'
import type { StreamEdgeData } from '@/lib/types'
const STATUS_COLORS: Record<string, { stroke: string; bg: string; text: string; label: string }> = {
planned: { stroke: '#22c55e', bg: 'rgba(34,197,94,0.12)', text: '#16a34a', label: 'Planned' },
active: { stroke: '#3b82f6', bg: 'rgba(59,130,246,0.12)', text: '#2563eb', label: 'Active' },
paused: { stroke: '#f97316', bg: 'rgba(249,115,22,0.12)', text: '#ea580c', label: 'Paused' },
}
export default function StreamEdge({
id,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
data,
markerEnd,
}: EdgeProps) {
const edgeData = data as StreamEdgeData | undefined
const status = edgeData?.status ?? 'planned'
const flowRate = edgeData?.flowRate ?? 0
const tokenSymbol = edgeData?.tokenSymbol ?? 'DAIx'
const colors = STATUS_COLORS[status] || STATUS_COLORS.planned
const [edgePath, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
})
// Animated dashed line to simulate flowing tokens
const isPaused = status === 'paused'
return (
<>
{/* Background glow path */}
<path
d={edgePath}
fill="none"
stroke={colors.stroke}
strokeWidth={8}
strokeOpacity={0.15}
/>
{/* Main path with animated dash */}
<BaseEdge
id={id}
path={edgePath}
markerEnd={markerEnd}
style={{
stroke: colors.stroke,
strokeWidth: 3,
strokeDasharray: '8 4',
animation: isPaused ? 'none' : 'streamFlow 1s linear infinite',
opacity: isPaused ? 0.5 : 0.9,
}}
/>
{/* Inject animation keyframes */}
<foreignObject width={0} height={0}>
<style>{`
@keyframes streamFlow {
to { stroke-dashoffset: -12; }
}
`}</style>
</foreignObject>
<EdgeLabelRenderer>
<div
className="nodrag nopan"
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
pointerEvents: 'all',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 2,
}}
>
{/* Flow rate label */}
<span
style={{
fontSize: 10,
fontWeight: 600,
fontFamily: 'monospace',
color: colors.text,
background: 'rgba(255,255,255,0.95)',
padding: '2px 6px',
borderRadius: 4,
border: `1px solid ${colors.stroke}`,
whiteSpace: 'nowrap',
}}
>
{flowRate.toLocaleString()} {tokenSymbol}/mo
</span>
{/* Status pill */}
<span
style={{
fontSize: 8,
fontWeight: 700,
textTransform: 'uppercase',
letterSpacing: '0.05em',
color: colors.text,
background: colors.bg,
padding: '1px 5px',
borderRadius: 6,
}}
>
{colors.label}
</span>
</div>
</EdgeLabelRenderer>
</>
)
}