This commit is contained in:
2026-01-29 22:20:50 +01:00
parent 802d707487
commit 936a997f03
4 changed files with 346 additions and 51 deletions

View File

@@ -4,7 +4,7 @@ export const Footer: React.FC = () => {
const currentYear = new Date().getFullYear();
return (
<footer className="py-16 mt-24 border-t border-slate-100">
<footer className="py-16 mt-24 border-t border-slate-100 bg-white relative z-10">
<div className="narrow-container">
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-end">
<div className="space-y-8">
@@ -22,7 +22,7 @@ export const Footer: React.FC = () => {
<div className="flex flex-col md:items-end gap-4 text-sm font-mono text-slate-300 uppercase tracking-widest">
<span>© {currentYear}</span>
<div className="flex gap-8">
<a href="mailto:marc@mintel.me" className="hover:text-slate-900 transition-colors no-underline">Email</a>
<a href="/contact" className="hover:text-slate-900 transition-colors no-underline">Kontakt</a>
<a href="https://github.com/marcmintel" className="hover:text-slate-900 transition-colors no-underline">GitHub</a>
</div>
</div>

View File

@@ -8,6 +8,7 @@ interface LineProps {
delay?: number;
}
// ... existing components ...
export const HeroLines: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 800 600" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -31,6 +32,23 @@ export const HeroLines: React.FC<LineProps> = ({ className = "", delay = 0 }) =>
animate={{ pathLength: 1, opacity: 1 }}
transition={{ duration: 2.5, delay: delay + 0.2, ease: "easeInOut" }}
/>
{/* Animated Pulses */}
<motion.circle r="3" fill="currentColor" className="text-slate-300">
<animateMotion
dur="6s"
repeatCount="indefinite"
path="M-100 300 C 100 300, 200 100, 400 100 C 600 100, 700 500, 900 500"
/>
</motion.circle>
<motion.circle r="3" fill="currentColor" className="text-slate-200">
<animateMotion
dur="8s"
repeatCount="indefinite"
path="M-100 350 C 100 350, 200 150, 400 150 C 600 150, 700 550, 900 550"
/>
</motion.circle>
{/* Nodes */}
<motion.circle cx="400" cy="100" r="4" className="fill-slate-200"
initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ delay: delay + 1, duration: 0.5 }} />
@@ -63,6 +81,13 @@ export const GridLines: React.FC<LineProps> = ({ className = "", delay = 0 }) =>
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
{/* Active Cells */}
<motion.rect x="120" y="40" width="40" height="40" className="fill-slate-50"
initial={{ opacity: 0 }} animate={{ opacity: [0, 0.5, 0] }} transition={{ duration: 3, repeat: Infinity, repeatDelay: 2 }} />
<motion.rect x="160" y="80" width="40" height="40" className="fill-slate-50"
initial={{ opacity: 0 }} animate={{ opacity: [0, 0.5, 0] }} transition={{ duration: 4, repeat: Infinity, repeatDelay: 1 }} />
<motion.circle cx="200" cy="120" r="3" className="fill-slate-400"
initial={{ scale: 0 }} whileInView={{ scale: 1 }} viewport={{ once: true }} transition={{ delay: delay + 1.5 }} />
</svg>
@@ -93,6 +118,15 @@ export const FlowLines: React.FC<LineProps> = ({ className = "", delay = 0 }) =>
transition={{ duration: 1.5, delay: delay + 0.2 }}
/>
{/* Pulse */}
<motion.circle r="2" fill="currentColor" className="text-slate-400">
<animateMotion
dur="4s"
repeatCount="indefinite"
path="M 0 100 H 100 C 150 100, 150 50, 200 50 H 300"
/>
</motion.circle>
<motion.rect x="300" y="30" width="80" height="40" rx="8" className="stroke-slate-300 fill-white" strokeWidth="1"
initial={{ opacity: 0, x: 280 }} whileInView={{ opacity: 1, x: 300 }} viewport={{ once: true }} transition={{ delay: delay + 1 }} />
@@ -111,6 +145,221 @@ export const CirclePattern: React.FC<LineProps> = ({ className = "", delay = 0 }
initial={{ scale: 0.8, opacity: 0 }} whileInView={{ scale: 1, opacity: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: delay + 0.2 }} />
<motion.circle cx="200" cy="200" r="50" stroke="currentColor" strokeWidth="1" className="text-slate-200"
initial={{ scale: 0.8, opacity: 0 }} whileInView={{ scale: 1, opacity: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: delay + 0.4 }} />
{/* Rotating Ring */}
<motion.circle cx="200" cy="200" r="120" stroke="currentColor" strokeWidth="1" strokeDasharray="10 10" className="text-slate-200"
animate={{ rotate: 360 }} transition={{ duration: 20, repeat: Infinity, ease: "linear" }} />
</svg>
)
}
export const ServicesFlow: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 1000 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Path connecting the 3 steps */}
<motion.path
d="M 100 100 L 900 100"
stroke="currentColor"
strokeWidth="3"
strokeDasharray="8 8"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 2, delay: delay }}
/>
{/* Animated pulse moving along the line */}
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="3s"
repeatCount="indefinite"
path="M 100 100 L 900 100"
/>
</motion.circle>
{/* Second pulse with delay */}
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="3s"
begin="1.5s"
repeatCount="indefinite"
path="M 100 100 L 900 100"
/>
</motion.circle>
</svg>
);
};
export const ComparisonLines: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 100 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<motion.path
d="M 50 0 V 400"
stroke="currentColor"
strokeWidth="3"
strokeDasharray="4 4"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="4s"
repeatCount="indefinite"
path="M 50 0 V 400"
/>
</motion.circle>
</svg>
)
}
// --- New Connector Components ---
export const ConnectorStart: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 100 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<motion.path
d="M 50 0 V 400"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
<circle cx="50" cy="10" r="8" className="fill-slate-900" />
{/* Multiple Pulses */}
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="4s"
repeatCount="indefinite"
path="M 50 0 V 400"
/>
</motion.circle>
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="4s"
begin="2s"
repeatCount="indefinite"
path="M 50 0 V 400"
/>
</motion.circle>
</svg>
);
};
export const ConnectorBranch: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 200 400" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Main vertical line */}
<motion.path
d="M 50 0 V 400"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
{/* Branch */}
<motion.path
d="M 50 100 C 50 150, 100 150, 150 150 H 200"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay + 0.5 }}
/>
{/* Pulses */}
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="4s"
repeatCount="indefinite"
path="M 50 0 V 400"
/>
</motion.circle>
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="3s"
repeatCount="indefinite"
path="M 50 100 C 50 150, 100 150, 150 150 H 200"
/>
</motion.circle>
</svg>
);
};
export const ConnectorSplit: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 200 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<motion.path
d="M 50 0 V 50 C 50 100, 100 100, 150 100 H 200"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
<motion.path
d="M 50 50 V 400"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="4s"
repeatCount="indefinite"
path="M 50 0 V 400"
/>
</motion.circle>
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="3s"
repeatCount="indefinite"
path="M 50 0 V 50 C 50 100, 100 100, 150 100 H 200"
/>
</motion.circle>
</svg>
);
};
export const ConnectorEnd: React.FC<LineProps> = ({ className = "", delay = 0 }) => {
return (
<svg className={`absolute pointer-events-none ${className}`} viewBox="0 0 100 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<motion.path
d="M 50 0 V 200"
stroke="currentColor"
strokeWidth="3"
className="text-slate-300"
initial={{ pathLength: 0 }}
whileInView={{ pathLength: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, delay: delay }}
/>
<circle cx="50" cy="200" r="8" className="fill-slate-900" />
<motion.circle r="5" fill="currentColor" className="text-slate-900">
<animateMotion
dur="2s"
repeatCount="indefinite"
path="M 50 0 V 200"
/>
</motion.circle>
</svg>
);
};

View File

@@ -9,6 +9,7 @@ interface SectionProps {
delay?: number;
variant?: 'white' | 'gray';
borderTop?: boolean;
connector?: React.ReactNode;
}
export const Section: React.FC<SectionProps> = ({
@@ -19,6 +20,7 @@ export const Section: React.FC<SectionProps> = ({
delay = 0,
variant = 'white',
borderTop = false,
connector,
}) => {
const bgClass = variant === 'gray' ? 'bg-slate-50' : 'bg-white';
const borderClass = borderTop ? 'border-t border-slate-100' : '';
@@ -29,10 +31,17 @@ export const Section: React.FC<SectionProps> = ({
<div className="grid grid-cols-1 md:grid-cols-12 gap-12 md:gap-16">
{/* Sidebar: Number & Title */}
<div className="md:col-span-3 relative">
{/* Connector Line */}
{connector && (
<div className="absolute left-[2.5rem] top-0 bottom-0 w-24 hidden md:block -z-10 pointer-events-none">
{connector}
</div>
)}
<div className="md:sticky md:top-32 space-y-6">
{number && (
<Reveal delay={delay}>
<span className="block text-6xl md:text-8xl font-bold text-slate-100 leading-none select-none">
<span className="block text-6xl md:text-8xl font-bold text-slate-100 leading-none select-none relative bg-white/0 backdrop-blur-[2px]">
{number}
</span>
</Reveal>