Files
e-tib.com/components/blocks/CompanyTimeline.tsx
Marc Mintel 8fcd68cf19
Some checks failed
Build & Deploy / 🔍 Prepare (push) Failing after 1m10s
CI - Lint, Typecheck & Test / quality-assurance (pull_request) Failing after 1m11s
Build & Deploy / 🧪 QA (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 32s
fix: english translation parity, remove hallucinated map projects, fix next.config syntax
2026-05-13 13:25:46 +02:00

166 lines
6.9 KiB
TypeScript

'use client';
import * as React from 'react';
import { motion, useScroll, useTransform } from 'framer-motion';
import { Building2, Compass, Layers, ArrowDownToLine, Wrench, Factory, Zap, MapPin, CheckCircle2 } from 'lucide-react';
const iconMap: Record<string, React.ElementType> = {
Building2,
Compass,
Layers,
ArrowDownToLine,
Wrench,
Factory,
Zap,
MapPin,
CheckCircle2
};
const defaultMilestones = [
{
date: '16.12.2015',
year: '2015',
title: 'Gründung E-TIB GmbH',
desc: 'Ausführung elektrischer Infrastrukturprojekte, Kabelbau und Horizontalspülbohrungen.',
iconName: 'Building2',
},
{
date: '04.02.2019',
year: '2019',
title: 'Gründung E-TIB Ingenieurgesellschaft',
desc: 'Genehmigungs- und Ausführungsplanung, komplexe Querungen sowie Netzanschlussplanung.',
iconName: 'Compass',
},
{
date: '14.11.2019',
year: '2019',
title: 'Gründung E-TIB Verwaltung GmbH',
desc: 'Zentrale Dienste, Erwerb, Vermietung, Verpachtung und Verwaltung von Immobilien und Maschinen.',
iconName: 'Layers',
},
{
date: '21.10.2025',
year: '2025',
title: 'Gründung E-TIB Bohrtechnik GmbH',
desc: 'Spezialisierung auf präzise Horizontalspülbohrungen in allen Bodenklassen.',
iconName: 'ArrowDownToLine',
},
];
interface Milestone {
date: string;
year: string;
title: string;
desc: string;
iconName: string;
}
interface CompanyTimelineProps {
badge?: string;
title?: string;
milestones?: Milestone[];
}
export function CompanyTimeline({
badge = 'Unsere Geschichte',
title = 'Meilensteine der Entwicklung',
milestones = defaultMilestones
}: CompanyTimelineProps) {
const containerRef = React.useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ["start center", "end center"]
});
const lineHeight = useTransform(scrollYProgress, [0, 1], ["0%", "100%"]);
return (
<section className="py-24 md:py-32 bg-[#FAFAFA] relative overflow-hidden">
{/* Background Decor */}
<div className="absolute top-0 right-0 w-[600px] h-[600px] bg-primary/5 rounded-full blur-[100px] pointer-events-none -translate-y-1/2 translate-x-1/3" />
<div className="absolute bottom-0 left-0 w-[800px] h-[800px] bg-neutral-200/40 rounded-full blur-[120px] pointer-events-none translate-y-1/3 -translate-x-1/3" />
<div className="container max-w-5xl relative z-10">
<div className="text-center mb-24">
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-neutral-200 text-neutral-dark text-xs font-bold uppercase tracking-wider mb-6 shadow-sm">
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
{badge}
</div>
<h3 className="font-heading text-4xl md:text-5xl lg:text-6xl font-extrabold text-neutral-dark tracking-tight">
{title}
</h3>
</div>
<div ref={containerRef} className="relative">
{/* Central Line Background */}
<div className="absolute left-[38px] md:left-1/2 top-0 bottom-0 w-1.5 bg-neutral-200 -translate-x-1/2 rounded-full" />
{/* Animated Central Line */}
<div className="absolute left-[38px] md:left-1/2 top-0 bottom-0 w-1.5 -translate-x-1/2 rounded-full overflow-hidden">
<motion.div
className="w-full bg-primary drop-shadow-[0_0_8px_rgba(130,237,32,0.8)]"
style={{ height: lineHeight }}
/>
</div>
<div className="space-y-16 md:space-y-24">
{milestones.map((milestone, i) => {
const isEven = i % 2 === 0;
const Icon = iconMap[milestone.iconName] || Building2;
return (
<motion.div
key={i}
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.7, ease: "easeOut" }}
className="relative flex flex-col md:flex-row items-center w-full group"
>
{/* Timeline Dot with Pulse */}
<div className="absolute left-[38px] md:left-1/2 top-0 md:top-1/2 w-8 h-8 rounded-full bg-white border-[5px] border-neutral-200 group-hover:border-primary transition-colors duration-500 z-20 -translate-x-1/2 md:-translate-y-1/2 shadow-sm flex items-center justify-center">
<div className="w-2 h-2 rounded-full bg-neutral-300 group-hover:bg-primary transition-colors duration-500" />
</div>
{/* Content Box Wrapper */}
<div className={`w-full md:w-1/2 pl-24 md:pl-0 ${isEven ? 'md:pr-16 md:text-right' : 'md:pl-16 md:ml-auto md:text-left'}`}>
{/* The Card */}
<div className="relative bg-white p-8 md:p-10 rounded-[2rem] shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-neutral-100 hover:shadow-[0_20px_40px_rgb(0,0,0,0.08)] hover:border-primary/20 transition-all duration-500 overflow-hidden transform hover:-translate-y-1">
{/* Giant Typography Background Year */}
<div className={`absolute select-none pointer-events-none text-[140px] leading-none font-black text-neutral-50 z-0 ${isEven ? '-left-8' : '-right-8'} -bottom-10 opacity-70 group-hover:scale-110 transition-transform duration-700`}>
{milestone.year}
</div>
<div className="relative z-10">
{/* Header Row */}
<div className={`flex items-center gap-4 mb-6 ${isEven ? 'md:flex-row-reverse' : ''}`}>
<div className="w-12 h-12 rounded-2xl bg-primary/10 text-primary flex items-center justify-center shrink-0 group-hover:bg-primary group-hover:text-neutral-dark transition-colors duration-500">
<Icon className="w-6 h-6" />
</div>
<span className="inline-block py-1.5 px-4 rounded-full bg-neutral-100 text-neutral-600 font-bold text-sm tracking-wide">
{milestone.date}
</span>
</div>
<h4 className="font-heading font-extrabold text-2xl md:text-3xl mb-4 text-neutral-dark leading-tight group-hover:text-primary transition-colors duration-300">
{milestone.title}
</h4>
<p className="text-neutral-500 text-lg leading-relaxed">
{milestone.desc}
</p>
</div>
</div>
</div>
</motion.div>
);
})}
</div>
</div>
</div>
</section>
);
}