131 lines
3.5 KiB
TypeScript
131 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
import Image from "next/image";
|
|
import { siteConfig } from "@/data/site-content";
|
|
|
|
const slides = [
|
|
{
|
|
src: "/herosection/A_massive_perfectly_organized_masonry_supply_yard__delpmaspu.webp",
|
|
alt: "Masonry Supply Yard",
|
|
},
|
|
{
|
|
src: "/herosection/Closeup_cinematic_macro_shot_of_a_stack_of_premium_delpmaspu.webp",
|
|
alt: "Premium Masonry Materials",
|
|
},
|
|
{
|
|
src: "/herosection/Ultrarealistic_cinematic_wide_shot_for_a_professio_delpmaspu.webp",
|
|
alt: "Professional Masonry Project",
|
|
},
|
|
{
|
|
src: "/herosection/Wide_angle_architectural_shot_of_a_contemporary_st_delpmaspu.webp",
|
|
alt: "Contemporary Stone Architecture",
|
|
},
|
|
];
|
|
|
|
export function HeroCinema() {
|
|
const [current, setCurrent] = useState(0);
|
|
const [previous, setPrevious] = useState<number | null>(null);
|
|
const currentRef = useRef(0);
|
|
const clearPreviousTimerRef = useRef<number | null>(null);
|
|
|
|
function transitionTo(nextIndex: number) {
|
|
if (nextIndex === currentRef.current) {
|
|
return;
|
|
}
|
|
|
|
setPrevious(currentRef.current);
|
|
setCurrent(nextIndex);
|
|
currentRef.current = nextIndex;
|
|
|
|
if (clearPreviousTimerRef.current) {
|
|
window.clearTimeout(clearPreviousTimerRef.current);
|
|
}
|
|
|
|
clearPreviousTimerRef.current = window.setTimeout(() => {
|
|
setPrevious(null);
|
|
clearPreviousTimerRef.current = null;
|
|
}, 1400);
|
|
}
|
|
|
|
useEffect(() => {
|
|
const timer = window.setInterval(() => {
|
|
transitionTo((currentRef.current + 1) % slides.length);
|
|
}, 4500);
|
|
|
|
return () => {
|
|
window.clearInterval(timer);
|
|
if (clearPreviousTimerRef.current) {
|
|
window.clearTimeout(clearPreviousTimerRef.current);
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
const renderedSlides =
|
|
previous === null
|
|
? [current]
|
|
: [previous, current].filter(
|
|
(index, position, values) => values.indexOf(index) === position,
|
|
);
|
|
|
|
return (
|
|
<div className="hc-root">
|
|
{renderedSlides.map((index) => {
|
|
const slide = slides[index];
|
|
const isCurrent = index === current;
|
|
|
|
return (
|
|
<div
|
|
key={`${index}-${isCurrent ? "current" : "previous"}`}
|
|
className="hc-slide-full"
|
|
style={{
|
|
opacity: isCurrent ? 1 : 0,
|
|
transition: "opacity 1.4s ease",
|
|
zIndex: isCurrent ? 2 : 1,
|
|
}}
|
|
>
|
|
<Image
|
|
src={slide.src}
|
|
alt={slide.alt}
|
|
fill
|
|
sizes="(max-width: 1100px) 100vw, 50vw"
|
|
quality={72}
|
|
className="cover-image"
|
|
priority={isCurrent && index === 0}
|
|
/>
|
|
</div>
|
|
);
|
|
})}
|
|
|
|
<div className="hc-overlay" />
|
|
|
|
<div className="hc-dots">
|
|
{slides.map((_, i) => (
|
|
<button
|
|
key={i}
|
|
className={`hc-dot${i === current ? " hc-dot-active" : ""}`}
|
|
onClick={() => transitionTo(i)}
|
|
aria-label={`Show image ${i + 1}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div className="hc-video-card">
|
|
<video
|
|
className="hc-video-small"
|
|
autoPlay
|
|
muted
|
|
loop
|
|
playsInline
|
|
poster={siteConfig.heroMedia.featureCardImage}
|
|
aria-label={siteConfig.heroMedia.featureCardAlt}
|
|
>
|
|
<source src={siteConfig.heroMedia.featureCardVideo} type="video/mp4" />
|
|
</video>
|
|
|
|
<div className="hc-video-card-badge">LIVE FROM THE YARD</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|