RTL Meshkee storefront with home/about/contact/products/blog, API auth/contact/blog wiring, and SEO sitemap-config. Co-authored-by: Cursor <cursoragent@cursor.com>
127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
"use client";
|
||
|
||
import { useEffect, useState } from "react";
|
||
import { featuresSection } from "@/data/site";
|
||
|
||
export function FeaturesCarousel() {
|
||
const items = featuresSection.items;
|
||
const [index, setIndex] = useState(0);
|
||
const [perView, setPerView] = useState(3);
|
||
|
||
useEffect(() => {
|
||
const update = () => {
|
||
const w = window.innerWidth;
|
||
if (w < 768) setPerView(1);
|
||
else if (w < 992) setPerView(2);
|
||
else setPerView(3);
|
||
};
|
||
update();
|
||
window.addEventListener("resize", update);
|
||
return () => window.removeEventListener("resize", update);
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (items.length <= perView) return;
|
||
const id = window.setInterval(() => {
|
||
setIndex((i) => (i + 1) % items.length);
|
||
}, 3000);
|
||
return () => window.clearInterval(id);
|
||
}, [items.length, perView]);
|
||
|
||
const visible =
|
||
perView >= items.length
|
||
? items
|
||
: Array.from({ length: perView }, (_, i) => items[(index + i) % items.length]);
|
||
|
||
const showNav = items.length > perView;
|
||
|
||
return (
|
||
<section className="relative overflow-hidden bg-[#F6F6F6] pt-20 pb-24 md:pt-[6.5rem] md:pb-28">
|
||
<div
|
||
aria-hidden
|
||
className="pointer-events-none absolute inset-x-0 top-4 hidden select-none overflow-hidden text-center text-[110px] font-semibold leading-none tracking-[-8px] text-white xl:block 2xl:text-[154px]"
|
||
>
|
||
آسانسور پارس
|
||
</div>
|
||
|
||
<div className="container-plift relative z-10">
|
||
<div className="mx-auto mb-12 max-w-2xl text-center lg:mb-14">
|
||
<span className="mb-5 block text-[17px] font-medium text-[#A0A0A0]">
|
||
{featuresSection.eyebrow}
|
||
</span>
|
||
<h2 className="text-[1.7rem] font-bold uppercase leading-snug text-dark md:text-[2rem]">
|
||
{featuresSection.title}
|
||
</h2>
|
||
</div>
|
||
|
||
<div className="grid items-start gap-6 lg:grid-cols-12 lg:gap-5">
|
||
{/* side intro — ~1/4 */}
|
||
<div className="pt-2 lg:col-span-3">
|
||
<span className="mb-5 block text-[17px] font-medium text-dark">
|
||
{featuresSection.sideLabel}
|
||
</span>
|
||
<h3 className="mb-8 text-[1.35rem] font-bold leading-9 text-dark md:text-[1.55rem] md:leading-10">
|
||
{featuresSection.sideTitle}
|
||
</h3>
|
||
|
||
{showNav && (
|
||
<div className="flex gap-2">
|
||
<button
|
||
type="button"
|
||
aria-label="بعدی"
|
||
onClick={() => setIndex((i) => (i + 1) % items.length)}
|
||
className="inline-flex h-10 w-10 items-center justify-center border border-[#ddd] text-lg text-dark transition hover:border-dark"
|
||
>
|
||
‹
|
||
</button>
|
||
<button
|
||
type="button"
|
||
aria-label="قبلی"
|
||
onClick={() =>
|
||
setIndex((i) => (i - 1 + items.length) % items.length)
|
||
}
|
||
className="inline-flex h-10 w-10 items-center justify-center border border-[#ddd] text-lg text-dark transition hover:border-dark"
|
||
>
|
||
›
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* cards — show 3 on desktop like original */}
|
||
<div className="lg:col-span-9">
|
||
<div
|
||
className={`grid gap-5 ${
|
||
perView === 1
|
||
? "grid-cols-1"
|
||
: perView === 2
|
||
? "grid-cols-2"
|
||
: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
||
}`}
|
||
>
|
||
{visible.map((item, i) => (
|
||
<article
|
||
key={`${item.number}-${perView >= items.length ? item.number : `${index}-${i}`}`}
|
||
className="border border-black/[0.08] bg-white"
|
||
>
|
||
<div className="px-7 py-10 md:px-8 md:py-12 xl:px-9">
|
||
<div className="mb-5 text-[2.5rem] font-medium leading-none tracking-[-2px] text-[#A0A0A0]">
|
||
{item.number}
|
||
</div>
|
||
<h4 className="mb-3 text-[16px] font-semibold uppercase leading-7 text-dark">
|
||
{item.title}
|
||
</h4>
|
||
<p className="text-[14px] font-light leading-[26px] text-[#5C6873] text-justify">
|
||
{item.description}
|
||
</p>
|
||
</div>
|
||
</article>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|