Fertig
This commit is contained in:
130
components/hero-cinema.tsx
Normal file
130
components/hero-cinema.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user