96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useEffect, useState } from "react";
|
|
import { heroSlides as fallbackSlides, site } from "@/lib/site-data";
|
|
|
|
const SLIDE_INTERVAL = 5200;
|
|
|
|
export type HeroSlide = {
|
|
eyebrow: string;
|
|
title: string;
|
|
description: string;
|
|
image: string;
|
|
linkUrl?: string | null;
|
|
};
|
|
|
|
export function HeroSlider({ slides }: { slides?: HeroSlide[] }) {
|
|
const items = slides?.length ? slides : fallbackSlides;
|
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
const [isPaused, setIsPaused] = useState(false);
|
|
const activeSlide = items[activeIndex] ?? items[0];
|
|
|
|
useEffect(() => {
|
|
setActiveIndex(0);
|
|
}, [items.length]);
|
|
|
|
useEffect(() => {
|
|
if (isPaused || items.length <= 1) return;
|
|
|
|
const timer = window.setInterval(() => {
|
|
setActiveIndex((current) => (current + 1) % items.length);
|
|
}, SLIDE_INTERVAL);
|
|
|
|
return () => window.clearInterval(timer);
|
|
}, [isPaused, items.length]);
|
|
|
|
if (!activeSlide) return null;
|
|
|
|
const media = (
|
|
<div
|
|
key={activeSlide.image}
|
|
className="hero-image-layer"
|
|
style={{ backgroundImage: `url(${activeSlide.image})` }}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<section className="hero">
|
|
<div className="container">
|
|
<div
|
|
className="hero-card"
|
|
onMouseEnter={() => setIsPaused(true)}
|
|
onMouseLeave={() => setIsPaused(false)}
|
|
>
|
|
{activeSlide.linkUrl ? (
|
|
<a href={activeSlide.linkUrl} className="hero-image-link" aria-label={activeSlide.title}>
|
|
{media}
|
|
</a>
|
|
) : (
|
|
media
|
|
)}
|
|
<div key={`${activeIndex}-${activeSlide.title}`} className="hero-content">
|
|
<p className="eyebrow sequence-item sequence-eyebrow">{activeSlide.eyebrow}</p>
|
|
<h1 className="sequence-item sequence-title">{activeSlide.title}</h1>
|
|
<p className="sequence-item sequence-copy">{activeSlide.description}</p>
|
|
<div className="hero-actions sequence-item sequence-actions">
|
|
<Link className="primary-btn" href={activeSlide.linkUrl || "/store"}>
|
|
مشاهده محصولات
|
|
</Link>
|
|
<Link className="hero-phone-link" href={`tel:${site.phone.replaceAll("-", "")}`}>
|
|
<span className="hero-phone-icon" aria-hidden="true">
|
|
☎
|
|
</span>
|
|
<span className="ltr-number" dir="ltr" lang="en">
|
|
{site.phone}
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
<div className="hero-dots" aria-label="انتخاب اسلاید">
|
|
{items.map((slide, index) => (
|
|
<button
|
|
key={`${slide.image}-${index}`}
|
|
className={index === activeIndex ? "active" : ""}
|
|
type="button"
|
|
aria-label={`اسلاید ${index + 1}`}
|
|
onClick={() => setActiveIndex(index)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|