Initial Next.js clone of Pars Elevator (plift.ir).

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>
This commit is contained in:
Alireza Hassani
2026-09-05 14:55:42 +03:30
co-authored by Cursor
commit 5909899b1e
83 changed files with 10035 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
"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>
);
}