ldc-qualimaine/resources/ts/front/Components/CertificationSection.tsx
2026-07-24 17:19:24 +02:00

159 lines
5.9 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import agricultureBio from "&/images/certifications/agriculture-biologique.png";
import agricultureBioWebp from "&/images/certifications/agriculture-biologique.webp";
import bienEtre from "&/images/certifications/bien-etre-animal.png";
import bienEtreWebp from "&/images/certifications/bien-etre-animal.webp";
import conformite from "&/images/certifications/conformite-certifiee.jpg";
import conformiteWebp from "&/images/certifications/conformite-certifiee.webp";
import labelRouge from "&/images/certifications/label-rouge.png";
import labelRougeWebp from "&/images/certifications/label-rouge.webp";
import origineGeo from "&/images/certifications/origine-geographique.png";
import origineGeoWebp from "&/images/certifications/origine-geographique.webp";
import impact from "&/images/certifications/planet-scrore.png";
import impactWebp from "&/images/certifications/planet-scrore.webp";
import { GetTranslation } from "@/lib/utils";
const CERTIFICATIONS = [
{
webp: labelRougeWebp,
fallback: labelRouge,
label: "front.certifications.quality.text",
alt: "front.certifications.quality.alt",
title: "front.certifications.quality.title",
},
{
webp: origineGeoWebp,
fallback: origineGeo,
label: "front.certifications.origin.text",
alt: "front.certifications.origin.alt",
title: "front.certifications.origin.title",
},
{
webp: agricultureBioWebp,
fallback: agricultureBio,
label: "front.certifications.organic.text",
alt: "front.certifications.organic.alt",
title: "front.certifications.organic.title",
},
{
webp: conformiteWebp,
fallback: conformite,
label: "front.certifications.product_cerf.text",
alt: "front.certifications.product_cerf.alt",
title: "front.certifications.product_cerf.title",
},
{
webp: bienEtreWebp,
fallback: bienEtre,
label: "front.certifications.animalWelfare.text",
alt: "front.certifications.animalWelfare.alt",
title: "front.certifications.animalWelfare.title",
},
{
webp: impactWebp,
fallback: impact,
label: "front.certifications.environmentalImpact.text",
alt: "front.certifications.environmentalImpact.text",
title: "front.certifications.environmentalImpact.title",
},
];
export default function CertificationsSection() {
const scrollerRef = useRef<HTMLDivElement>(null);
const [thumb, setThumb] = useState({ width: 200, left: 0 });
useEffect(() => {
const scroller = scrollerRef.current;
if (!scroller) return;
const updateThumb = () => {
const { scrollLeft, scrollWidth, clientWidth } = scroller;
const thumbWidth = (clientWidth / scrollWidth) * 100;
const maxScroll = scrollWidth - clientWidth;
const scrollRatio = maxScroll > 0 ? scrollLeft / maxScroll : 0;
const thumbLeft = scrollRatio * (100 - thumbWidth);
setThumb({ width: thumbWidth, left: thumbLeft });
};
updateThumb();
scroller.addEventListener("scroll", updateThumb, { passive: true });
window.addEventListener("resize", updateThumb);
return () => {
scroller.removeEventListener("scroll", updateThumb);
window.removeEventListener("resize", updateThumb);
};
}, []);
return (
<section className="relative w-full overflow-hidden px-8 py-14 md:px-12 lg:px-[60px]">
<div className="mx-auto max-w-[1320px] text-start lg:text-center">
<h2 className="font-sans text-[26px] lg:text-[32px] font-extrabold text-neutral-800 whitespace-nowrap">
{GetTranslation("front.certifications.title")}
</h2>
<p className="mx-auto mt-3 max-w-[820px] font-sans text-[18px] leading-relaxed text-neutral-700 ">
{GetTranslation("front.certifications.subtitle")}
</p>
{/* Mobile */}
<div
ref={scrollerRef}
className="no-scrollbar mt-10 -mx-8 flex snap-x snap-mandatory gap-8 overflow-x-auto px-8 pb-4 md:hidden"
>
{CERTIFICATIONS.map((cert) => (
<div
key={cert.label}
className="flex w-[160px] flex-none snap-center flex-col items-center gap-3"
>
<picture>
<source srcSet={cert.webp} type="image/webp" />
<img
src={cert.fallback}
title={GetTranslation(cert.title)}
alt={GetTranslation(cert.alt)}
className="h-[90px] w-auto object-contain"
/>
</picture>
<p className="font-sans text-[14px] font-normal uppercase text-neutral-700 text-center">
{GetTranslation(cert.label)}
</p>
</div>
))}
</div>
{/* Custom progress Bar */}
<div className="relative mt-2 h-2.5 w-full max-w-[300px] bg-[#eeede7] md:hidden">
<div
className="absolute top-0 h-full rounded-full bg-[#D9D9D9] transition-[left,width] duration-150 ease-out"
style={{
width: `${thumb.width.toString()}%`,
left: `${thumb.left.toString()}%`,
}}
/>
</div>
{/* Desktop */}
<div className="mt-10 hidden items-start justify-between gap-6 md:flex">
{CERTIFICATIONS.map((cert) => (
<div
key={cert.label}
className="flex flex-1 flex-col items-center gap-3"
>
<picture>
<source srcSet={cert.webp} type="image/webp" />
<img
src={cert.fallback}
alt={GetTranslation(cert.alt)}
title={GetTranslation(cert.title)}
className="h-[90px] w-auto object-contain"
/>
</picture>
<p className="font-sans text-[14px] font-normal uppercase text-neutral-700">
{GetTranslation(cert.label)}
</p>
</div>
))}
</div>
</div>
</section>
);
}