218 lines
7.9 KiB
TypeScript
218 lines
7.9 KiB
TypeScript
"use client";
|
|
import type { LucideIcon } from "lucide-react";
|
|
import {
|
|
Globe,
|
|
Lock,
|
|
ShieldCheck,
|
|
SlidersHorizontal,
|
|
Sparkles,
|
|
Workflow,
|
|
} from "lucide-react";
|
|
import { startTransition, useEffect, useState } from "react";
|
|
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import type { CarouselApi } from "@/components/ui/carousel";
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
CarouselNext,
|
|
CarouselPrevious,
|
|
} from "@/components/ui/carousel";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface FeatureItem {
|
|
id: string;
|
|
title: string;
|
|
label: string;
|
|
icon: LucideIcon;
|
|
description: string;
|
|
background: string;
|
|
imageAlt: string;
|
|
}
|
|
|
|
const FEATURES: FeatureItem[] = [
|
|
{
|
|
id: "natural-patterns",
|
|
title: "تریگر رویداد",
|
|
label: "فرایند هوشمند",
|
|
icon: Workflow,
|
|
description:
|
|
"با هر رویداد مثل ثبت فرم یا تغییر وضعیت، اقدام بعدی را خودکار اجرا کنید.",
|
|
background:
|
|
"/block-media/shadcnblocks/block/photos/jeremy-bishop-iEjCQtcsVPY-unsplash.jpg",
|
|
imageAlt: "سازنده گردشکار",
|
|
},
|
|
{
|
|
id: "natural-security",
|
|
title: "شرط هوشمند",
|
|
label: "اتوماسیون",
|
|
icon: Lock,
|
|
description:
|
|
"مسیر متفاوت برای شرایط مختلف تعریف کنید و تصمیمگیری را سریعتر کنید.",
|
|
background:
|
|
"/block-media/shadcnblocks/block/photos/ivan-bandura-hqnUYXsN5oY-unsplash.jpg",
|
|
imageAlt: "نمای اتوماسیون فرایند",
|
|
},
|
|
{
|
|
id: "ecology-safeguards",
|
|
title: "اعلان خودکار",
|
|
label: "گردشکار",
|
|
icon: ShieldCheck,
|
|
description:
|
|
"تیم را در لحظه از تغییر وضعیت باخبر کنید تا هیچ موردی رها نشود.",
|
|
background:
|
|
"/block-media/shadcnblocks/block/photos/sam-wermut-FiUuNWxnb3k-unsplash.jpg",
|
|
imageAlt: "لاگ اجرای خودکار",
|
|
},
|
|
{
|
|
id: "natural-communication",
|
|
title: "تأیید چندمرحلهای",
|
|
label: "صرفهجویی زمان",
|
|
icon: SlidersHorizontal,
|
|
description:
|
|
"مسیر کار را با کشیدن و رها کردن بسازید و بدون وابستگی به تیم فنی راه بیندازید.",
|
|
background:
|
|
"/block-media/shadcnblocks/block/photos/ivan-bandura-Kj2tYAl4HZg-unsplash.jpg",
|
|
imageAlt: "سازنده گردشکار",
|
|
},
|
|
{
|
|
id: "multilingual-ecology",
|
|
title: "لاگ اجرا",
|
|
label: "فرایند هوشمند",
|
|
icon: Globe,
|
|
description:
|
|
"با هر رویداد مثل ثبت فرم یا تغییر وضعیت، اقدام بعدی را خودکار اجرا کنید.",
|
|
background:
|
|
"/block-media/shadcnblocks/block/photos/vasilis-karkalas-LadCWrSL7X8-unsplash.jpg",
|
|
imageAlt: "نمای اتوماسیون فرایند",
|
|
},
|
|
];
|
|
|
|
interface Feature224Props {
|
|
className?: string;
|
|
}
|
|
|
|
const Feature224 = ({ className }: Feature224Props) => {
|
|
const [api, setApi] = useState<CarouselApi>();
|
|
const [current, setCurrent] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (!api) {
|
|
return;
|
|
}
|
|
|
|
startTransition(() => {
|
|
setCurrent(api.selectedScrollSnap() + 1);
|
|
});
|
|
|
|
api.on("select", () => {
|
|
startTransition(() => {
|
|
setCurrent(api.selectedScrollSnap() + 1);
|
|
});
|
|
});
|
|
}, [api]);
|
|
|
|
const goToSlide = (index: number) => {
|
|
if (api) {
|
|
api.scrollTo(index);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section
|
|
dir="rtl"
|
|
lang="fa"
|
|
className={cn("w-full min-w-0 overflow-x-hidden py-12 sm:py-20 lg:py-32", className)}
|
|
>
|
|
<div className="container min-w-0 px-4 sm:px-6">
|
|
<div className="flex w-full min-w-0 flex-col items-center justify-center gap-4">
|
|
<h2 className="mx-auto max-w-full text-center text-xl leading-none font-medium text-balance md:max-w-112.5 md:text-2xll lg:max-w-140 lg:text-2xll">
|
|
فرایندها را استاندارد و سریع کنید
|
|
</h2>
|
|
</div>
|
|
<Carousel
|
|
opts={{
|
|
align: "start",
|
|
direction: "rtl",
|
|
}}
|
|
className="w-full min-w-0 max-w-full"
|
|
setApi={setApi}
|
|
>
|
|
<CarouselContent className="pt-12 sm:pt-20">
|
|
{FEATURES.map((card) => (
|
|
<CarouselItem
|
|
key={card.id}
|
|
className="min-w-0 basis-[85%] sm:basis-1/2 lg:basis-1/3"
|
|
>
|
|
<div className="min-w-0 p-1">
|
|
<Card className="min-w-0 border-0 py-0 shadow-none dark:bg-background">
|
|
<CardContent className="flex min-w-0 flex-col p-0">
|
|
<div
|
|
style={{ backgroundImage: `url("${card.background}")` }}
|
|
className="relative flex aspect-[0.935802469] w-full min-w-0 flex-col items-center justify-between overflow-hidden rounded-2xl bg-cover bg-center bg-no-repeat p-4 sm:p-7"
|
|
role="img"
|
|
aria-label={card.imageAlt}
|
|
>
|
|
<div className="flex size-full flex-1" />
|
|
<div className="h-12 w-full min-w-0">
|
|
<div className="mx-auto mb-6 flex w-full max-w-full min-w-0 items-center gap-3 rounded-full bg-primary px-3 py-2.5 shadow-xl sm:mb-8 sm:max-w-60 sm:gap-4 dark:bg-background">
|
|
<div className="shrink-0">
|
|
<div className="flex -space-x-2 rtl:space-x-reverse">
|
|
<div className="flex size-7 rounded-full border border-black bg-background dark:bg-primary">
|
|
<Sparkles className="m-auto size-4 dark:text-background" />
|
|
</div>
|
|
<div className="flex size-7 rounded-full border border-black bg-background dark:bg-primary">
|
|
<card.icon className="m-auto size-4 dark:text-background" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="min-w-0 text-sm font-medium text-white">
|
|
{card.label}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex w-full min-w-0 flex-col gap-1 pt-6 text-start">
|
|
<h3 className="text-lg font-medium text-balance text-foreground sm:text-xl">
|
|
{card.title}
|
|
</h3>
|
|
<p className="text-sm text-pretty text-muted-foreground">
|
|
{card.description}
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent> <div className="mt-8 hidden items-center justify-center gap-4 md:flex">
|
|
<CarouselPrevious className="static size-12 translate-y-0 rtl:rotate-180" />
|
|
<CarouselNext className="static size-12 translate-y-0 rtl:rotate-180" />
|
|
</div>
|
|
<div className="mt-6 flex w-full min-w-0 items-center gap-2 md:hidden">
|
|
{Array.from({ length: FEATURES.length }).map((_, i) => (
|
|
<button
|
|
type="button"
|
|
onClick={() => goToSlide(i % FEATURES.length)}
|
|
key={`carousel-btn-${i}`}
|
|
aria-label={`رفتن به اسلاید ${i + 1}`}
|
|
className="h-4 w-full"
|
|
>
|
|
<div
|
|
className={cn(
|
|
"my-auto h-1 w-full rounded-full",
|
|
current === i + 1 ? "bg-primary" : "bg-muted",
|
|
)}
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</Carousel>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Feature224 };
|