188 lines
5.5 KiB
TypeScript
188 lines
5.5 KiB
TypeScript
"use client";
|
|
|
|
import { ArrowLeft, ArrowRight } from "lucide-react";
|
|
import { startTransition, useEffect, useState } from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
type CarouselApi,
|
|
} from "@/components/ui/carousel";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const IMAGES = [
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-1.svg",
|
|
alt: "تصویر گالری ۱",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-2.svg",
|
|
alt: "تصویر گالری ۲",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-3.svg",
|
|
alt: "تصویر گالری ۳",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-4.svg",
|
|
alt: "تصویر گالری ۴",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-5.svg",
|
|
alt: "تصویر گالری ۵",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-1.svg",
|
|
alt: "تصویر گالری ۶",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-2.svg",
|
|
alt: "تصویر گالری ۷",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-3.svg",
|
|
alt: "تصویر گالری ۸",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-4.svg",
|
|
alt: "تصویر گالری ۹",
|
|
},
|
|
{
|
|
src: "/block-media/shadcnblocks/block/placeholder-dark-5.svg",
|
|
alt: "تصویر گالری ۱۰",
|
|
},
|
|
];
|
|
|
|
interface Gallery17Props {
|
|
className?: string;
|
|
}
|
|
|
|
const Gallery17 = ({ className }: Gallery17Props) => {
|
|
const [api, setApi] = useState<CarouselApi>();
|
|
const [current, setCurrent] = useState(0);
|
|
const [count, setCount] = useState(0);
|
|
const [canScrollPrev, setCanScrollPrev] = useState(false);
|
|
const [canScrollNext, setCanScrollNext] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!api) {
|
|
return;
|
|
}
|
|
|
|
const updateSelection = () => {
|
|
startTransition(() => {
|
|
setCount(api.scrollSnapList().length);
|
|
setCurrent(api.selectedScrollSnap() + 1);
|
|
setCanScrollPrev(api.canScrollPrev());
|
|
setCanScrollNext(api.canScrollNext());
|
|
});
|
|
};
|
|
|
|
updateSelection();
|
|
api.on("select", updateSelection);
|
|
|
|
return () => {
|
|
api.off("select", updateSelection);
|
|
};
|
|
}, [api]);
|
|
|
|
useEffect(() => {
|
|
if (!api) {
|
|
return;
|
|
}
|
|
api.reInit();
|
|
}, [api]);
|
|
|
|
return (
|
|
<section
|
|
dir="rtl"
|
|
lang="fa"
|
|
className={cn("overflow-hidden py-32", className)}
|
|
>
|
|
<div className="container md:px-45">
|
|
<Carousel
|
|
dir="rtl"
|
|
className="mx-auto w-full max-w-[50rem] [&>div:nth-child(1)]:md:overflow-visible"
|
|
setApi={setApi}
|
|
opts={{
|
|
startIndex: 1,
|
|
direction: "rtl",
|
|
}}
|
|
>
|
|
<CarouselContent className="-ms-4 me-0">
|
|
{IMAGES.map((img, index) => (
|
|
<CarouselItem
|
|
key={`carousel-img-${index}`}
|
|
className="basis-full ps-4 pe-0"
|
|
>
|
|
<div
|
|
className={cn(
|
|
"aspect-[1.333333333] max-w-[50rem] overflow-hidden rounded-[0.75rem] transition-all duration-300",
|
|
current === index + 1
|
|
? "scale-100 opacity-100"
|
|
: "scale-70 opacity-40",
|
|
)}
|
|
>
|
|
<img
|
|
className="block size-full object-cover object-center"
|
|
src={img.src}
|
|
alt={img.alt}
|
|
/>
|
|
</div>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<div className="mt-4 hidden md:block">
|
|
<Button
|
|
type="button"
|
|
size="icon"
|
|
variant="default"
|
|
className="absolute top-1/2 size-10 -translate-y-1/2 max-[767px]:static max-[767px]:translate-y-0 md:start-[-6.25rem] md:size-14 lg:start-[-9.9375rem] lg:size-14 [&>svg]:size-6!"
|
|
disabled={!canScrollPrev}
|
|
onClick={() => api?.scrollPrev()}
|
|
>
|
|
<ArrowRight className="size-6" />
|
|
<span className="sr-only">اسلاید قبلی</span>
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
size="icon"
|
|
variant="default"
|
|
className="absolute top-1/2 size-10 -translate-y-1/2 max-[767px]:static max-[767px]:translate-y-0 md:end-[-6.25rem] md:size-14 lg:end-[-9.9375rem] lg:size-14 [&>svg]:size-6!"
|
|
disabled={!canScrollNext}
|
|
onClick={() => api?.scrollNext()}
|
|
>
|
|
<ArrowLeft className="size-6" />
|
|
<span className="sr-only">اسلاید بعدی</span>
|
|
</Button>
|
|
</div>
|
|
</Carousel>
|
|
<div className="mx-auto mt-10 flex w-full max-w-[33.9375rem] items-center justify-center">
|
|
{Array.from({ length: count }).map((_, index) => (
|
|
<button
|
|
type="button"
|
|
aria-label={`رفتن به اسلاید ${(index + 1).toLocaleString("fa-IR")}`}
|
|
key={`carousel-dot-btn-${index}`}
|
|
className="p-2"
|
|
onClick={() => {
|
|
api?.scrollTo(index);
|
|
}}
|
|
>
|
|
<div
|
|
className={cn(
|
|
"size-3 rounded-full",
|
|
current === index + 1 ? "bg-black" : "bg-black/10",
|
|
)}
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Gallery17 };
|