Files
reui-blocks/blocks/feature219.tsx
T

201 lines
6.2 KiB
TypeScript

import type { LucideIcon } from "lucide-react";
import { AudioLines, AudioWaveform } from "lucide-react";
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { cn } from "@/lib/utils";
type ImageItem = {
src: string;
alt: string;
};
type ImageVariant = "1" | "2" | "3";
interface Item {
id: string;
title: string;
summary: string;
number?: string;
images: ImageItem[];
Icon?: LucideIcon;
variant: ImageVariant;
}
interface CardImageProps {
variant: ImageVariant;
images: ImageItem[];
Icon?: LucideIcon;
}
const LIST: Item[] = [
{
id: "file-upload",
title: "پیشنهاد عنوان",
summary:
"تحلیل فنی، محتوا و رقبا در یک ابزار جمع می‌شود. تیم محتوا می‌داند روی کدام صفحه و کلمه باید تمرکز کند.",
images: [
{
src: "/block-media/shadcnblocks/block/photos/ivan-bandura-Kj2tYAl4HZg-unsplash.jpg",
alt: "داشبورد SEO",
},
],
Icon: AudioWaveform,
variant: "1",
},
{
id: "secure-fast",
title: "تحلیل کلمه کلیدی",
summary:
"ساختار عنوان و توضیحات را برای کلیک بیشتر بهینه کنید.",
images: [
{
src: "/block-media/shadcnblocks/block/photos/ivan-bandura-3QqzCTIfUJI-unsplash.jpg",
alt: "تحلیل کلمات کلیدی",
},
],
variant: "2",
},
{
id: "manage-files",
title: "ممیزی فنی",
summary:
"کلمات با پتانسیل بالا را پیدا کنید و استراتژی محتوا را بر همان اساس بچینید.",
images: [
{
src: "/block-media/shadcnblocks/block/photos/vasilis-karkalas-qOaeVSKyhhE-unsplash.jpg",
alt: "گزارش رتبه جستجو",
},
],
Icon: AudioLines,
variant: "3",
},
];
const CardImage = ({ variant, images, Icon }: CardImageProps) => {
switch (variant) {
case "1":
return (
<div className="absolute end-[30%] bottom-[3.75rem]">
<div className="aspect-[1.645714286] w-[25rem]">
<div className="flex size-full items-center -space-x-[10%] rtl:flex-row-reverse rtl:space-x-reverse">
<div className="w-full shrink-0">
<AspectRatio
className="overflow-hidden rounded-2xl"
ratio={1.558095238}
>
<img
src={images[0].src}
alt={images[0].alt}
className="block size-full object-cover object-center"
/>
</AspectRatio>
</div>
<div className="w-[16%] shrink-0">
<AspectRatio
className="w-full overflow-hidden rounded-lg shadow"
ratio={1}
>
<div className="flex size-full bg-background">
{Icon && (
<Icon className="m-auto size-[65%] stroke-muted-foreground/80 stroke-1" />
)}
</div>
</AspectRatio>
</div>
</div>
</div>
</div>
);
case "2":
return (
<div className="absolute end-1/6 -bottom-[5%]">
<div className="aspect-video w-[31.25rem] overflow-hidden rounded-2xl shadow-2xl sm:w-[42.5rem]">
<img
src={images[0].src}
alt={images[0].alt}
className="block size-full object-cover object-center"
/>
</div>
</div>
);
default:
return (
<div className="absolute end-1/6 -bottom-[5%]">
<div className="relative aspect-[1.195592287] w-[21.25rem] sm:w-[25rem]">
<div className="absolute bottom-0 aspect-[1.287833828] w-full overflow-hidden rounded-2xl">
<img
src={images[0].src}
alt={images[0].alt}
className="block size-full object-cover object-center"
/>
</div>
<div className="absolute end-0 top-0 flex aspect-square w-[20%] translate-x-1/2 overflow-hidden rounded-lg bg-background shadow rtl:-translate-x-1/2">
{Icon && (
<Icon className="m-auto size-[65%] stroke-muted-foreground/80 stroke-1" />
)}
</div>
</div>
</div>
);
}
};
const Card = ({ title, summary, images, Icon, number, variant }: Item) => {
const numberBorderColor = "var(--muted-foreground)";
return (
<div
className="relative flex h-full min-h-[39.375rem] w-full max-w-[34rem] flex-col justify-between gap-4 overflow-hidden rounded-[0.75rem] bg-muted"
style={{
backgroundImage:
"url('/block-media/shadcnblocks/block/patterns/p6.png')",
}}
>
<div className="flex w-full flex-col gap-4 p-10 pe-[3.75rem] pb-0 text-start md:p-[3.75rem]">
<h3 className="text-xl leading-none">{title}</h3>
<p className="text-xl leading-normal text-pretty">{summary}</p>
</div>
<div className="relative size-full min-h-[21.875rem]">
<CardImage images={images} Icon={Icon} variant={variant} />
</div>
<div
className="absolute end-5 top-5 size-fit text-2xll leading-none font-light text-muted opacity-25"
style={{
textShadow: `
2px 0 ${numberBorderColor}, -2px 0 ${numberBorderColor},
0 2px ${numberBorderColor}, 0 -2px ${numberBorderColor},
1px 1px ${numberBorderColor}, -1px -1px ${numberBorderColor},
1px -1px ${numberBorderColor}, -1px 1px ${numberBorderColor}
`,
}}
>
{number}
</div>
</div>
);
};
interface Feature219Props {
className?: string;
}
const Feature219 = ({ className }: Feature219Props) => {
return (
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
<div className="container">
<div className="grid items-center justify-center gap-6 xl:grid-cols-3">
{LIST.map((item, index) => (
<Card
key={item.id}
number={(index + 1).toLocaleString("fa-IR")}
{...item}
/>
))}
</div>
</div>
</section>
);
};
export { Feature219 };