Files
reui-blocks/blocks/gallery14.tsx
T

190 lines
6.8 KiB
TypeScript

"use client";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { startTransition, useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import type { CarouselApi } from "@/components/ui/carousel";
import {
Carousel,
CarouselContent,
CarouselItem,
} from "@/components/ui/carousel";
import { cn } from "@/lib/utils";
const carouselItems = [
{
image:
"/block-media/external/unsplash/photo-1589100787575-fad1dcaa9d17.jpg",
title: "واکنش‌گرا",
description:
"قالب‌های ما با رویکرد mobile-first ساخته شده‌اند تا وب‌سایت شما در همه دستگاه‌ها و اندازه‌های صفحه زیبا به نظر برسد.",
},
{
image:
"/block-media/external/unsplash/photo-1698516923130-8845104b6224.jpg",
title: "کد تمیز",
description:
"هر قالب با کد تمیز و ساختارمند و مطابق بهترین شیوه‌ها طراحی شده تا سفارشی‌سازی و نگهداری ساده باشد.",
},
{
image:
"/block-media/external/unsplash/photo-1647517649508-855580038bfd.jpg",
title: "کپی و پیست",
description:
"قالب‌ها برای کپی و پیست آسان طراحی شده‌اند تا بتوانید سریعاً کامپوننت‌ها و قابلیت‌ها را در پروژه‌های خود پیاده کنید.",
},
{
image:
"/block-media/external/unsplash/photo-1586869871566-d8e41dd50318.jpg",
title: "به‌روزرسانی آسان",
description:
"به‌روزرسانی و نگهداری منظم تضمین می‌کند قالب شما همیشه با استانداردها و امنیت وب به‌روز بماند.",
},
];
interface Gallery14Props {
className?: string;
}
const Gallery14 = ({ className }: Gallery14Props) => {
const [api, setApi] = useState<CarouselApi>();
const [current, setCurrent] = useState(1);
const [canScrollPrev, setCanScrollPrev] = useState(false);
const [canScrollNext, setCanScrollNext] = useState(false);
useEffect(() => {
if (!api) {
return;
}
const updateSelection = () => {
startTransition(() => {
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">
<Carousel
dir="rtl"
setApi={setApi}
opts={{
align: "start",
direction: "rtl",
}}
>
<div className="grid gap-8 md:gap-4 lg:grid-cols-2 [&>div[data-slot=carousel-content]]:overflow-visible [&>div[data-slot=carousel-content]]:[clip-path:inset(-100vw_0_-100vw_-100vw)]">
<div className="text-start">
<h2 className="text-xl font-semibold md:text-2xll">
کمتر کد بزن. <br />
<span className="text-primary/40">سریع‌تر بساز.</span>
</h2>
<p className="mt-8 text-xl text-primary">
با قالب‌های ما شروع کنید و مطابق نیاز خود سفارشی کنید.
</p>
<div className="mt-8 hidden items-center gap-4 md:flex">
<Button
type="button"
size="icon"
variant="outline"
className="static size-12 translate-none touch-manipulation"
disabled={!canScrollPrev}
onClick={() => api?.scrollPrev()}
>
<ArrowRight className="size-4" />
<span className="sr-only">اسلاید قبلی</span>
</Button>
<Button
type="button"
size="icon"
variant="outline"
className="static size-12 translate-none touch-manipulation"
disabled={!canScrollNext}
onClick={() => api?.scrollNext()}
>
<ArrowLeft className="size-4" />
<span className="sr-only">اسلاید بعدی</span>
</Button>
</div>
</div>
<CarouselContent className="me-0 ms-0 max-w-[400px] select-none">
{carouselItems.map((item, idx) => (
<CarouselItem className="w-fit ps-4 pe-0" key={idx}>
<div className="relative aspect-4/5 max-h-[500px] rounded-2xl">
<div className="absolute inset-0 rounded-2xl bg-linear-to-b from-primary to-transparent to-40% dark:from-background" />
<img
src={item.image}
alt={item.title}
className="size-full rounded-2xl bg-cover"
/>
<div className="absolute inset-0 p-8 text-start">
<p className="text-sm font-semibold text-background/50 dark:text-foreground/50">
<span className="me-1 text-background dark:text-foreground">
{item.title}.
</span>
{item.description}
</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
</div>
</Carousel>
<div className="mt-8 flex items-center lg:ms-[50%]">
{Array.from({ length: carouselItems.length }).map((_, index) => (
<button
type="button"
key={index}
className={cn(
"flex h-8 cursor-pointer items-center justify-center overflow-hidden rounded-full bg-muted-foreground/15 text-xs font-semibold whitespace-nowrap transition-all duration-300",
index + 1 === current ? "w-32" : "m-4 size-4",
)}
onClick={() => api?.scrollTo(index)}
aria-label={`رفتن به ${carouselItems[index].title}`}
>
<span
className={cn(
"inline-block transition-all duration-300",
index + 1 === current
? "translate-x-0 opacity-100"
: "translate-x-6 opacity-0 rtl:-translate-x-6",
)}
>
{carouselItems[index].title}
</span>
</button>
))}
</div>
</div>
</section>
);
};
export { Gallery14 };