Files
hatchet/frontend/docs/components/WorkflowDiagram.tsx
T
Gabe Ruttner 5babd09679 docs: chunky overhaul (#3129)
* improve overall docs structure and things
2026-03-04 14:33:15 -08:00

290 lines
7.5 KiB
TypeScript

import React from "react";
import { brand, state, fill, inactive, gradient } from "./diagram-colors";
const WorkflowDiagram: React.FC = () => {
const nodeW = 130;
const nodeH = 46;
const rx = 10;
return (
<div className="my-8 flex justify-center">
<div className="w-full max-w-3xl rounded-xl border border-neutral-700/40 bg-neutral-900/30 p-6 backdrop-blur-sm">
<svg
viewBox="0 0 720 260"
className="w-full h-auto"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient id="wf-blue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop
offset="0%"
stopColor={gradient.blue[0]}
stopOpacity="0.6"
/>
<stop
offset="100%"
stopColor={gradient.blue[1]}
stopOpacity="0.3"
/>
</linearGradient>
<linearGradient id="wf-magenta" x1="0%" y1="0%" x2="100%" y2="100%">
<stop
offset="0%"
stopColor={gradient.magenta[0]}
stopOpacity="0.6"
/>
<stop
offset="100%"
stopColor={gradient.magenta[1]}
stopOpacity="0.3"
/>
</linearGradient>
<linearGradient id="wf-green" x1="0%" y1="0%" x2="100%" y2="100%">
<stop
offset="0%"
stopColor={gradient.green[0]}
stopOpacity="0.6"
/>
<stop
offset="100%"
stopColor={gradient.green[1]}
stopOpacity="0.3"
/>
</linearGradient>
</defs>
<style>{`
@keyframes wf-dash {
to { stroke-dashoffset: -20; }
}
.wf-flow {
stroke-dasharray: 8 6;
animation: wf-dash 0.8s linear infinite;
}
`}</style>
{/* Workflow label */}
<text
x="360"
y="24"
textAnchor="middle"
fill={brand.cyanDark}
fontSize="11"
fontWeight="500"
letterSpacing="0.05em"
>
WORKFLOW
</text>
{/* Dashed container */}
<rect
x="10"
y="34"
width="700"
height="216"
rx="14"
fill="none"
stroke={inactive.edge}
strokeWidth="1"
strokeDasharray="6 4"
/>
{/* --- Row 1: Task A → Task B --- */}
{/* Task A */}
<rect
x={40}
y={60}
width={nodeW}
height={nodeH}
rx={rx}
fill={fill.activeNode}
stroke="url(#wf-blue)"
strokeWidth="1.5"
/>
<text
x={40 + nodeW / 2}
y={60 + nodeH / 2 + 1}
textAnchor="middle"
fill={brand.cyan}
fontSize="12"
fontWeight="500"
>
Task A
</text>
{/* Edge A → B */}
<path
d={`M ${40 + nodeW + 2} ${60 + nodeH / 2} L ${248} ${60 + nodeH / 2}`}
fill="none"
stroke={brand.blue}
strokeWidth="2"
className="wf-flow"
/>
{/* Task B */}
<rect
x={250}
y={60}
width={nodeW}
height={nodeH}
rx={rx}
fill={fill.activeNode}
stroke="url(#wf-blue)"
strokeWidth="1.5"
/>
<text
x={250 + nodeW / 2}
y={60 + nodeH / 2 + 1}
textAnchor="middle"
fill={brand.cyan}
fontSize="12"
fontWeight="500"
>
Task B
</text>
{/* --- Fan out: B → C and B → D --- */}
{/* Edge B → C */}
<path
d={`M ${250 + nodeW + 2} ${60 + nodeH / 2} C ${430} ${60 + nodeH / 2}, ${430} ${60 + nodeH / 2}, ${460} ${60 + nodeH / 2}`}
fill="none"
stroke={brand.magenta}
strokeWidth="2"
className="wf-flow"
style={{ animationDelay: "0.2s" }}
/>
{/* Edge B → D */}
<path
d={`M ${250 + nodeW + 2} ${60 + nodeH / 2} C ${420} ${60 + nodeH / 2}, ${420} ${170 + nodeH / 2}, ${460} ${170 + nodeH / 2}`}
fill="none"
stroke={brand.magenta}
strokeWidth="2"
className="wf-flow"
style={{ animationDelay: "0.3s" }}
/>
{/* Task C */}
<rect
x={460}
y={60}
width={nodeW}
height={nodeH}
rx={rx}
fill={fill.magenta}
stroke="url(#wf-magenta)"
strokeWidth="1.5"
/>
<text
x={460 + nodeW / 2}
y={60 + nodeH / 2 + 1}
textAnchor="middle"
fill={brand.magentaLight}
fontSize="12"
fontWeight="500"
>
Task C
</text>
{/* Task D */}
<rect
x={460}
y={170}
width={nodeW}
height={nodeH}
rx={rx}
fill={fill.magenta}
stroke="url(#wf-magenta)"
strokeWidth="1.5"
/>
<text
x={460 + nodeW / 2}
y={170 + nodeH / 2 + 1}
textAnchor="middle"
fill={brand.magentaLight}
fontSize="12"
fontWeight="500"
>
Task D
</text>
{/* --- Both converge to Result --- */}
{/* Edges C → Result, D → Result drawn before Result box so they don't overlap text */}
{/* Annotations */}
<text
x={40 + nodeW / 2}
y={60 + nodeH + 16}
textAnchor="middle"
fill={brand.blue}
fontSize="9"
>
start
</text>
<text
x={315}
y={60 + nodeH + 16}
textAnchor="middle"
fill={brand.blue}
fontSize="9"
>
depends on A
</text>
<text
x={525}
y={60 + nodeH + 16}
textAnchor="middle"
fill={brand.magenta}
fontSize="9"
>
parallel
</text>
<text
x={525}
y={170 + nodeH + 16}
textAnchor="middle"
fill={brand.magenta}
fontSize="9"
>
parallel
</text>
{/* Vertical dashed line between sequential and parallel sections */}
<line
x1="430"
y1="50"
x2="430"
y2="240"
stroke={inactive.edge}
strokeWidth="1"
strokeDasharray="4 4"
opacity="0.5"
/>
<text
x="432"
y="248"
fill={inactive.text}
fontSize="8"
textAnchor="start"
>
fan-out
</text>
{/* Labels for sections */}
<text
x="200"
y="248"
fill={inactive.text}
fontSize="8"
textAnchor="middle"
>
sequential
</text>
</svg>
</div>
</div>
);
};
export default WorkflowDiagram;