129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
import gsap from "gsap";
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
|
|
if (typeof window !== "undefined") {
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
}
|
|
|
|
const STATS = [
|
|
{ prefix: "", from: 7000, to: 7500, suffix: "", label: "Delivered packages" },
|
|
{ prefix: "2.", from: 1, to: 6, suffix: " bil", label: "Tonnes of goods" },
|
|
{ prefix: "", from: 10, to: 100, suffix: "+", label: "Countries covered" },
|
|
{ prefix: "", from: 100, to: 550, suffix: "+", label: "Warehouses" },
|
|
];
|
|
|
|
export default function AirFreightCoverage() {
|
|
const sectionRef = useRef<HTMLDivElement>(null);
|
|
const countersRef = useRef<(HTMLSpanElement | null)[]>([]);
|
|
|
|
useEffect(() => {
|
|
const section = sectionRef.current;
|
|
if (!section) return;
|
|
|
|
const trigger = ScrollTrigger.create({
|
|
trigger: section,
|
|
start: "top 75%",
|
|
once: true,
|
|
onEnter: () => {
|
|
STATS.forEach((stat, i) => {
|
|
const el = countersRef.current[i];
|
|
if (!el) return;
|
|
const obj = { val: stat.from };
|
|
gsap.to(obj, {
|
|
val: stat.to,
|
|
duration: 2,
|
|
ease: "power2.out",
|
|
delay: i * 0.12,
|
|
onUpdate: () => {
|
|
if (el) {
|
|
el.textContent = Math.round(obj.val).toLocaleString("en-IN");
|
|
}
|
|
},
|
|
});
|
|
});
|
|
},
|
|
});
|
|
|
|
return () => { trigger.kill(); };
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<style dangerouslySetInnerHTML={{ __html: `
|
|
.afc4-section {
|
|
background: #1F1F1F;
|
|
padding: 80px 20px;
|
|
}
|
|
.afc4-inner {
|
|
}
|
|
.afc4-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 2px;
|
|
}
|
|
.afc4-item {
|
|
padding: 50px 40px;
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid rgba(255,255,255,0.07);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
transition: background 0.35s ease, border-color 0.35s ease;
|
|
}
|
|
.afc4-item:hover {
|
|
background: rgba(192,18,39,0.05);
|
|
border-color: rgba(192,18,39,0.25);
|
|
}
|
|
.afc4-number {
|
|
font-family: var(--font-manrope), "Manrope", sans-serif;
|
|
font-size: clamp(48px, 5vw, 80px);
|
|
font-weight: 800;
|
|
color: #FFFFFF;
|
|
line-height: 1;
|
|
letter-spacing: -0.04em;
|
|
}
|
|
.afc4-number-suffix {
|
|
color: #c01227;
|
|
}
|
|
.afc4-label {
|
|
font-family: var(--font-manrope), "Manrope", sans-serif;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: rgba(255,255,255,0.45);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
margin-top: 4px;
|
|
}
|
|
@media (max-width: 1020px) {
|
|
.afc4-grid { grid-template-columns: repeat(2, 1fr); }
|
|
.afc4-section { padding: 60px 20px; }
|
|
}
|
|
@media (max-width: 600px) {
|
|
.afc4-item { padding: 30px 24px; }
|
|
.afc4-section { padding: 40px 20px; }
|
|
}
|
|
`}} />
|
|
|
|
<section className="afc4-section" ref={sectionRef}>
|
|
<div className="afc4-inner dm-section-container">
|
|
<div className="afc4-grid">
|
|
{STATS.map((stat, i) => (
|
|
<div key={stat.label} className="afc4-item">
|
|
<div className="afc4-number">
|
|
{stat.prefix && <span>{stat.prefix}</span>}
|
|
<span ref={(el) => { countersRef.current[i] = el; }}>{stat.from.toLocaleString("en-IN")}</span>
|
|
{stat.suffix && <span className="afc4-number-suffix">{stat.suffix}</span>}
|
|
</div>
|
|
<div className="afc4-label">{stat.label}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|