Initial commit: Hoomat storefront with Meshkee API and static-image slots.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user