This commit is contained in:
2026-01-30 22:33:29 +01:00
parent 615e8b4b4b
commit 6beaf3c0aa
2 changed files with 360 additions and 26 deletions

View File

@@ -0,0 +1,333 @@
'use client';
import * as React from 'react';
import { motion } from 'framer-motion';
import { IllustrationProps } from './types';
export const SystemArchitecture: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Central Core */}
<motion.rect
x="70" y="70" width="60" height="60" rx="12"
className="fill-slate-900"
initial={{ scale: 0, rotate: -45 }}
whileInView={{ scale: 1, rotate: 0 }}
viewport={{ once: true }}
transition={{ type: "spring", stiffness: 100, delay }}
/>
{/* Orbiting Elements */}
{[0, 90, 180, 270].map((angle, i) => {
const rad = (angle * Math.PI) / 180;
const x = 100 + Math.cos(rad) * 60 - 15;
const y = 100 + Math.sin(rad) * 60 - 15;
return (
<motion.rect
key={i}
x={x} y={y} width="30" height="30" rx="8"
className="fill-white stroke-slate-200"
strokeWidth="1"
initial={{ opacity: 0, scale: 0 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
animate={{
y: [y, y - 5, y],
}}
transition={{
delay: delay + 0.2 + i * 0.1,
duration: 3,
repeat: Infinity,
repeatDelay: i * 0.5,
ease: "easeInOut"
}}
/>
);
})}
{/* Connection Lines */}
<motion.path
d="M 100 40 V 70 M 100 130 V 160 M 40 100 H 70 M 130 100 H 160"
stroke="currentColor" strokeWidth="1"
className="text-slate-200"
strokeDasharray="4 4"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1, delay: delay + 0.6 }}
/>
</svg>
);
export const SpeedPerformance: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* The "Built" Foundation */}
<motion.path
d="M 40 160 H 160"
stroke="currentColor" strokeWidth="4" strokeLinecap="round"
className="text-slate-900"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay }}
/>
{/* Bricks forming a structure */}
{[
{ x: 50, y: 130, w: 30 },
{ x: 85, y: 130, w: 30 },
{ x: 120, y: 130, w: 30 },
{ x: 65, y: 105, w: 30 },
{ x: 105, y: 105, w: 30 },
].map((brick, i) => (
<motion.rect
key={i}
x={brick.x} y={brick.y} width={brick.w} height="20" rx="2"
className="fill-slate-100 stroke-slate-200"
strokeWidth="1"
initial={{ opacity: 0, y: brick.y + 10 }}
whileInView={{ opacity: 1, y: brick.y }}
viewport={{ once: true }}
transition={{ delay: delay + 0.2 + i * 0.1 }}
/>
))}
{/* Lightning Bolt emerging from the "Built" structure */}
<motion.path
d="M 110 30 L 80 80 H 100 L 70 130"
stroke="currentColor" strokeWidth="6" strokeLinecap="round" strokeLinejoin="round"
className="text-slate-900"
initial={{ pathLength: 0, filter: "drop-shadow(0 0 0px rgba(0,0,0,0))" }}
whileInView={{ pathLength: 1, filter: "drop-shadow(0 0 8px rgba(0,0,0,0.1))" }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: delay + 1, ease: "easeOut" }}
/>
{/* Speed Lines */}
{[0, 1, 2].map((i) => (
<motion.path
key={i}
d={`M ${130 + i * 10} ${50 + i * 20} H ${150 + i * 10}`}
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
className="text-slate-200"
initial={{ x: -10, opacity: 0 }}
animate={{ x: 10, opacity: [0, 1, 0] }}
transition={{ duration: 0.8, repeat: Infinity, delay: delay + 1.2 + i * 0.2 }}
/>
))}
</svg>
);
export const SolidFoundation: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Stacked Blocks */}
<motion.rect
x="40" y="140" width="120" height="30" rx="4"
className="fill-slate-900"
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay }}
/>
<motion.rect
x="60" y="100" width="80" height="30" rx="4"
className="fill-slate-400"
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 0.2 }}
/>
<motion.rect
x="80" y="60" width="40" height="30" rx="4"
className="fill-slate-200"
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 0.4 }}
/>
{/* Shield Icon Overlay */}
<motion.path
d="M 100 30 L 120 40 V 60 C 120 80 100 90 100 90 C 100 90 80 80 80 60 V 40 L 100 30 Z"
className="fill-white stroke-slate-900"
strokeWidth="2"
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ type: "spring", delay: delay + 0.8 }}
/>
</svg>
);
export const LayerSeparation: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Top Layer (Content) */}
<motion.g
initial={{ y: -20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay }}
>
<rect x="40" y="40" width="120" height="40" rx="8" className="fill-white stroke-slate-200" strokeWidth="1" />
<rect x="55" y="55" width="30" height="10" rx="2" className="fill-slate-100" />
<rect x="95" y="55" width="50" height="10" rx="2" className="fill-slate-100" />
</motion.g>
{/* Gap with Arrows */}
<motion.path
d="M 100 90 V 110"
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
className="text-slate-200"
strokeDasharray="4 4"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 0.4 }}
/>
{/* Bottom Layer (Code/Logic) */}
<motion.g
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 0.2 }}
>
<rect x="40" y="120" width="120" height="40" rx="8" className="fill-slate-900" />
<path d="M 60 140 L 70 135 L 60 130 M 140 140 L 130 135 L 140 130" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</motion.g>
</svg>
);
export const DirectService: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Two Nodes */}
<motion.circle
cx="50" cy="100" r="15"
className="fill-slate-200"
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ delay }}
/>
<motion.circle
cx="150" cy="100" r="15"
className="fill-slate-900"
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 0.2 }}
/>
{/* Direct Connection */}
<motion.path
d="M 65 100 H 135"
stroke="currentColor" strokeWidth="3" strokeLinecap="round"
className="text-slate-900"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: delay + 0.4 }}
/>
{/* Pulse moving between */}
<motion.circle r="4" className="fill-white">
<animateMotion
dur="2s"
repeatCount="indefinite"
path="M 65 100 H 135"
/>
</motion.circle>
</svg>
);
export const AgencyChaos: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Messy Path */}
<motion.path
d="M 30 100 C 50 40, 70 160, 90 100 C 110 40, 130 160, 170 100"
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
className="text-slate-200"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 2, delay }}
/>
{/* Intersecting Circles (Meetings) */}
{[0, 1, 2].map((i) => (
<motion.circle
key={i}
cx={60 + i * 40} cy={100 + (i % 2 === 0 ? -30 : 30)} r="20"
className="stroke-slate-100 fill-white"
strokeWidth="1"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
animate={{ scale: [1, 1.1, 1] }}
transition={{
delay: delay + 0.5 + i * 0.3,
duration: 4,
repeat: Infinity,
repeatDelay: i * 0.5
}}
/>
))}
{/* Slate "X" or Stop signs - NO COLOR */}
<motion.path
d="M 160 90 L 180 110 M 180 90 L 160 110"
stroke="currentColor" strokeWidth="3" strokeLinecap="round"
className="text-slate-300"
initial={{ opacity: 0, scale: 0 }}
whileInView={{ opacity: 0.5, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 1.5 }}
/>
</svg>
);
export const TaskDone: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Checkmark Circle */}
<motion.circle
cx="100" cy="100" r="60"
className="stroke-slate-900"
strokeWidth="2"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1, delay }}
/>
{/* Checkmark */}
<motion.path
d="M 70 100 L 90 120 L 135 75"
stroke="currentColor" strokeWidth="8" strokeLinecap="round" strokeLinejoin="round"
className="text-slate-900"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: delay + 0.8 }}
/>
{/* Confetti/Sparkles */}
{[0, 45, 90, 135, 180, 225, 270, 315].map((angle, i) => {
const rad = (angle * Math.PI) / 180;
const x1 = 100 + Math.cos(rad) * 70;
const y1 = 100 + Math.sin(rad) * 70;
const x2 = 100 + Math.cos(rad) * 85;
const y2 = 100 + Math.sin(rad) * 85;
return (
<motion.line
key={i}
x1={x1} y1={y1} x2={x2} y2={y2}
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
className="text-slate-200"
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: delay + 1.2 + i * 0.05 }}
/>
);
})}
</svg>
);