125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { BLACK_ITEMS } from "@/data/home";
|
|
import BilingualTitle from "@/components/ui/BilingualTitle";
|
|
|
|
export type BlackItemData = {
|
|
id: string;
|
|
image: string;
|
|
alt: string;
|
|
nameFa: string;
|
|
nameEn: string;
|
|
href: string;
|
|
};
|
|
|
|
type BlackCollectionProps = {
|
|
items?: BlackItemData[];
|
|
};
|
|
|
|
export default function BlackCollection({ items }: BlackCollectionProps) {
|
|
const list: BlackItemData[] =
|
|
items?.length
|
|
? items
|
|
: BLACK_ITEMS.map((item) => ({
|
|
id: item.id,
|
|
image: item.image,
|
|
alt: item.alt,
|
|
nameFa: item.nameFa,
|
|
nameEn: item.nameEn,
|
|
href: `/products?color=black&item=${item.id}`,
|
|
}));
|
|
|
|
const ref = useRef<HTMLElement>(null);
|
|
const [visible, setVisible] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const el = ref.current;
|
|
if (!el) return;
|
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
setVisible(true);
|
|
return;
|
|
}
|
|
const io = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
setVisible(true);
|
|
io.disconnect();
|
|
}
|
|
},
|
|
{ threshold: 0.15, rootMargin: "0px 0px -6% 0px" },
|
|
);
|
|
io.observe(el);
|
|
return () => io.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<section
|
|
ref={ref}
|
|
className="relative mx-auto w-full max-w-[1710px] px-4 py-10 sm:px-6 lg:px-[120px] lg:py-14"
|
|
>
|
|
<div
|
|
className="seq-fade-item relative mb-8 lg:mb-10"
|
|
style={{
|
|
transitionDelay: visible ? "0ms" : "0ms",
|
|
opacity: visible ? 1 : 0,
|
|
transform: visible ? "translate3d(0,0,0)" : "translate3d(0,20px,0)",
|
|
}}
|
|
>
|
|
<BilingualTitle
|
|
titleFa="من عاشق رنگ مشکی هستم"
|
|
titleEn="I Like It Black"
|
|
size="xl"
|
|
align="center"
|
|
/>
|
|
</div>
|
|
|
|
<ul className="grid grid-cols-2 gap-[14px] lg:grid-cols-4 lg:gap-[22px]">
|
|
{list.map((item, i) => (
|
|
<li
|
|
key={item.id}
|
|
className="seq-fade-item"
|
|
style={{
|
|
transitionDelay: visible ? `${(i + 1) * 110}ms` : "0ms",
|
|
opacity: visible ? 1 : 0,
|
|
transform: visible
|
|
? "translate3d(0,0,0)"
|
|
: "translate3d(0,28px,0)",
|
|
}}
|
|
>
|
|
<Link
|
|
href={item.href}
|
|
className="group relative block aspect-[410/717] overflow-hidden bg-[#f3f3f3]"
|
|
>
|
|
<Image
|
|
src={item.image}
|
|
alt={item.alt}
|
|
fill
|
|
sizes="(max-width: 1024px) 50vw, 25vw"
|
|
className="object-cover transition-transform duration-700 group-hover:scale-[1.03]"
|
|
/>
|
|
<div className="absolute inset-x-3 bottom-3 z-10 overflow-hidden bg-white px-3 py-2.5 text-center sm:inset-x-4 sm:bottom-4 sm:px-4 sm:py-3">
|
|
<span
|
|
aria-hidden
|
|
className="pointer-events-none absolute inset-0 origin-bottom scale-y-0 bg-ink transition-transform duration-[400ms] ease-out group-hover:scale-y-100"
|
|
/>
|
|
<p className="relative z-10 font-doran text-base font-medium text-ink transition-colors duration-[400ms] ease-out group-hover:text-white sm:text-lg lg:text-xl">
|
|
{item.nameFa}
|
|
</p>
|
|
<p
|
|
dir="ltr"
|
|
className="relative z-10 mt-0.5 font-montserrat text-[10px] font-light uppercase tracking-[0.28em] text-[#898989] transition-colors duration-[400ms] ease-out group-hover:text-white sm:text-[11px]"
|
|
>
|
|
{item.nameEn}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
);
|
|
}
|