Files
reui-blocks/blocks/gallery16.tsx
T

272 lines
9.1 KiB
TypeScript

"use client";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselItem,
} from "@/components/ui/carousel";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
const items = [
{
title: (
<>
<span className="bg-gradient-to-b from-foreground/20 to-muted-foreground bg-clip-text text-transparent">
کشف
</span>
<br />
ویژگی‌های اصلی ما
</>
),
description: (
<>
به عمق قابلیت‌های قدرتمندی بروید که برای ساده‌سازی گردش کار شما طراحی
شده‌اند. از طراحی شهودی، یکپارچه‌سازی روان و گزینه‌های سفارشی‌سازی
قدرتمند بهره ببرید.
<br />
<br />
ببینید پلتفرم ما چگونه با نیازهای در حال تغییر شما سازگار می‌شود و
ارزش و کارایی بلندمدت را تضمین می‌کند.
</>
),
note: "مستندات جامع و کانال‌های پشتیبانی اختصاصی برای همراهی با شما در دسترس است.",
image:
"/block-media/shadcnblocks/block/placeholder-1.svg",
category: "ویژگی‌ها",
},
{
title: (
<>
<span className="bg-gradient-to-b from-foreground/20 to-muted-foreground bg-clip-text text-transparent">
راهکار برای
</span>
<br />
هر سناریو
</>
),
description: (
<>
<p>
ببینید پلتفرم ما چگونه چالش‌های متنوع در حوزه‌های مختلف را پاسخ
می‌دهد:
</p>
<ul className="my-4 ms-6 list-disc">
<li>افزایش کارایی همکاری تیمی.</li>
<li>بهینه‌سازی تخصیص منابع حیاتی.</li>
<li>ساده‌سازی تحلیل داده‌های پیچیده.</li>
</ul>
<p>ابزارهای سازگار برای بستر منحصربه‌فرد شما ارائه می‌دهیم.</p>
</>
),
note: "از تخصص ما در یکپارچه‌سازی و توسعه سفارشی برای نیازهای خاص بهره ببرید.",
image:
"/block-media/shadcnblocks/block/placeholder-2.svg",
category: "راهکارها",
},
{
title: (
<>
<span className="bg-gradient-to-b from-foreground/20 to-muted-foreground bg-clip-text text-transparent">
ساخت
</span>
<br />
آینده با هم
</>
),
description: (
<>
<p>
نگاهی به تعهد مداوم ما به نوآوری و بهبود بیندازید:
</p>
<ul className="my-4 ms-6 list-disc">
<li>طراحی رابط کاربری نسل بعد.</li>
<li>عرضه قابلیت‌های تحلیل پیشرفته.</li>
<li>گسترش شبکه یکپارچه‌سازی با سرویس‌های شخص ثالث.</li>
</ul>
<p>
ما بر اساس بازخورد کاربران و روندهای صنعت دائماً در حال تکامل
هستیم.
</p>
</>
),
note: "تیم تحقیق و توسعه اختصاصی ما بر ارائه راهکارهای پیشرفته متمرکز است.",
image:
"/block-media/shadcnblocks/block/placeholder-3.svg",
category: "نقشه راه",
},
];
interface Gallery16Props {
className?: string;
}
const Gallery16 = ({ className }: Gallery16Props) => {
const [api, setApi] = useState<CarouselApi>();
const [current, setCurrent] = useState(items[0].category);
const [canScrollPrev, setCanScrollPrev] = useState(false);
const [canScrollNext, setCanScrollNext] = useState(false);
const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
const [indicatorStyle, setIndicatorStyle] = useState({
width: 0,
insetInlineStart: 0,
});
useEffect(() => {
const currentIndex = items.findIndex((item) => item.category === current);
const activeTab = tabRefs.current[currentIndex];
if (activeTab) {
const { offsetWidth, offsetLeft } = activeTab;
setIndicatorStyle({
width: offsetWidth,
insetInlineStart: offsetLeft,
});
}
}, [current]);
useEffect(() => {
if (!api) {
return;
}
const currentIndex = items.findIndex((item) => item.category === current);
api.scrollTo(currentIndex);
const onSelect = () => {
const idx = api.selectedScrollSnap();
setCurrent(items[idx].category);
setCanScrollPrev(api.canScrollPrev());
setCanScrollNext(api.canScrollNext());
};
setCanScrollPrev(api.canScrollPrev());
setCanScrollNext(api.canScrollNext());
api.on("select", onSelect);
return () => {
api.off("select", onSelect);
};
}, [api, current]);
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",
}}
className="[&>div[data-slot=carousel-content]]:overflow-visible"
>
<div className="flex items-center justify-between">
<Tabs
value={current}
onValueChange={setCurrent}
className="mb-8 flex justify-center"
dir="rtl"
>
<TabsList className="relative h-auto gap-6 bg-background">
{items.map((item, idx) => (
<TabsTrigger
key={idx}
ref={(el) => {
tabRefs.current[idx] = el;
}}
value={item.category}
className="border-none !bg-background text-base transition-all duration-700 ease-out [&[data-state=active]]:shadow-none"
>
{item.category}
</TabsTrigger>
))}
<div
className="absolute bottom-0 h-0.5 bg-primary transition-all duration-700 ease-out"
style={{
width: `${indicatorStyle.width}px`,
insetInlineStart: `${indicatorStyle.insetInlineStart}px`,
}}
/>
</TabsList>
</Tabs>
<div className="hidden items-center gap-4 sm:flex">
<Button
type="button"
size="icon"
variant="outline"
className="static size-10 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-10 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-4xl">
{items.map((item, idx) => (
<CarouselItem
key={idx}
className="w-fit max-w-4xl ps-4 pe-0"
>
<div className="grid h-full max-w-4xl gap-10 rounded-xl border border-border p-6 shadow-sm select-none sm:p-10 md:max-h-[450px] md:grid-cols-2 lg:gap-20">
<div className="flex flex-col justify-between gap-4 text-start">
<div>
<h2 className="text-xl font-medium sm:text-xl">
{item.title}
</h2>
<div className="mt-4 text-sm text-muted-foreground sm:mt-6">
{item.description}
</div>
</div>
<p className="mt-4 text-xs text-muted-foreground sm:mt-6">
{item.note}
</p>
</div>
<div className="rounded-xl border border-border p-2">
<img
src={item.image}
alt={item.category}
className="h-full w-full rounded-xl object-cover"
/>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
</div>
</section>
);
};
export { Gallery16 };