feat: add Pods capabilities and how-it-works sections

- Created PodsCapabilities component showcasing four key features (communicate, organization, manage, storage) with icon-based layout
- Added PodsHow section with CloudPods animation demonstrating pod-to-pod communication concept
- Implemented animated CloudPods visualization with inter-cluster data flow and pulsing effects
This commit is contained in:
2025-11-12 12:49:16 +01:00
parent 8276ede9fd
commit aab7e66f29
5 changed files with 345 additions and 1 deletions

View File

@@ -0,0 +1,195 @@
"use client";
import { motion, useReducedMotion } from "framer-motion";
import clsx from "clsx";
type Props = {
className?: string;
accent?: string;
bg?: string;
};
const W = 760;
const H = 420;
export default function CloudPods({
className,
accent = "#00b8db",
bg = "#0b0b0b",
}: Props) {
const prefers = useReducedMotion();
// Pods: 2 clusters (top-right & bottom-left)
const clusterA = [
{ x: 180, y: 300 },
{ x: 240, y: 330 },
{ x: 300, y: 290 },
];
const clusterB = [
{ x: 480, y: 100 },
{ x: 540, y: 130 },
{ x: 600, y: 90 },
];
// Combine all pods for rendering
const pods = [...clusterA, ...clusterB];
// Inter-cluster communication paths (cross connections)
const links = [
[0, 3],
[1, 4],
[2, 5],
[0, 4],
[1, 5],
];
const drawLink = (i: number, j: number) => {
const a = pods[i];
const b = pods[j];
return `M ${a.x} ${a.y} L ${b.x} ${b.y}`;
};
return (
<div className={clsx("relative overflow-hidden", className)}>
<svg viewBox={`0 0 ${W} ${H}`} className="w-full h-full" style={{ background: bg }}>
<defs>
{/* Subtle cyan glow */}
<filter id="glow">
<feGaussianBlur stdDeviation="3" result="b" />
<feMerge>
<feMergeNode in="b" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
{/* Cyan gradient for pods */}
<radialGradient id="podGradient" cx="50%" cy="50%" r="60%">
<stop offset="0%" stopColor={accent} stopOpacity="0.9" />
<stop offset="100%" stopColor={accent} stopOpacity="0.05" />
</radialGradient>
</defs>
{/* ✅ Static base links between clusters */}
{links.map(([i, j], idx) => (
<motion.path
key={idx}
d={drawLink(i, j)}
stroke="#1f2937"
strokeWidth={1.8}
strokeLinecap="round"
fill="none"
opacity="0.5"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 1.2, delay: idx * 0.05 }}
/>
))}
{/* ✅ Cyan data signals moving across clusters */}
{!prefers &&
links.map(([i, j], idx) => (
<motion.circle
key={`pulse-${idx}`}
r={4}
fill={accent}
style={{ offsetPath: `path('${drawLink(i, j)}')` }}
initial={{ offsetDistance: "0%", opacity: 0 }}
animate={{
offsetDistance: ["0%", "100%"],
opacity: [0.2, 1, 0.2],
}}
transition={{
duration: 2.6,
delay: idx * 0.25,
repeat: Infinity,
ease: "linear",
}}
filter="url(#glow)"
/>
))}
{/* ✅ Cloud Pods */}
{pods.map((p, i) => (
<g key={i}>
<motion.ellipse
cx={p.x}
cy={p.y}
rx={34}
ry={22}
fill="url(#podGradient)"
stroke="#1f2937"
strokeWidth={1.6}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.6, delay: 0.05 * i }}
filter="url(#glow)"
/>
{/* Soft inner cyan pulse */}
{!prefers && (
<motion.ellipse
cx={p.x}
cy={p.y}
rx={18}
ry={12}
fill={accent}
opacity={0.08}
animate={{ opacity: [0.05, 0.3, 0.05], scale: [1, 1.1, 1] }}
transition={{
duration: 2.4,
delay: i * 0.15,
repeat: Infinity,
ease: [0.22, 1, 0.36, 1],
}}
/>
)}
</g>
))}
{/* ✅ Cluster halos */}
{!prefers && (
<>
<motion.circle
cx="250"
cy="310"
r="100"
fill="none"
stroke={accent}
strokeWidth={1.2}
opacity={0.1}
animate={{
scale: [1, 1.1, 1.2],
opacity: [0.05, 0.2, 0],
}}
transition={{
duration: 3.8,
repeat: Infinity,
ease: [0.22, 1, 0.36, 1],
}}
/>
<motion.circle
cx="560"
cy="110"
r="100"
fill="none"
stroke={accent}
strokeWidth={1.2}
opacity={0.1}
animate={{
scale: [1, 1.1, 1.2],
opacity: [0.05, 0.2, 0],
}}
transition={{
duration: 3.8,
delay: 1.2,
repeat: Infinity,
ease: [0.22, 1, 0.36, 1],
}}
/>
</>
)}
</svg>
</div>
);
}