Files
reui-blocks/blocks/feature313.tsx
T

219 lines
7.7 KiB
TypeScript
Raw Normal View History

"use client";
import { motion } from "framer-motion";
import { Play } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
interface Feature313Props {
className?: string;
imageSrc: string;
imageAlt: string;
videoUrl?: string;
videoCaption: string;
videoSecondaryCaption: string;
cards: {
id: string;
title: string;
image: string;
className?: string;
}[];
}
const Feature313 = ({
className,
imageSrc = "/block-media/shadcnblocks/block/lummi/bw6.jpeg",
imageAlt = "گزارش عملکرد",
videoUrl = "/block-media/shadcnblocks/block/man-1.mp4",
videoCaption = "داده پراکنده را به تصمیم تبدیل کنید",
videoSecondaryCaption = "تحلیل داده",
cards = [
{
id: "growth",
title: "گزارش زمان‌بندی‌شده",
image: "/block-media/shadcnblocks/block/placeholder-2.svg",
},
{
id: "design",
title: "تحلیل کوHORT",
image: "/block-media/shadcnblocks/block/placeholder-3.svg",
},
{
id: "support",
title: "مقایسه دوره‌ای",
image: "/block-media/shadcnblocks/block/placeholder-4.svg",
},
{
id: "partnerships",
title: "خروجی گزارش",
image: "/block-media/shadcnblocks/block/placeholder-5.svg",
},
],
}: Feature313Props) => {
const getYouTubeVideoId = (url: string) => {
const regExp =
/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
const match = url.match(regExp);
return match && match[2].length === 11 ? match[2] : null;
};
const youtubeId = videoUrl ? getYouTubeVideoId(videoUrl) : null;
const isYouTube = !!youtubeId;
const isMobile = useIsMobile();
return (
<section dir="rtl" lang="fa" className={cn("bg-muted py-24", className)}>
<div className="container flex flex-col gap-2">
<div className="grid grid-cols-1 gap-1 lg:grid-cols-4">
{cards.map((card, index) => (
<Card key={card.id} className="border-none p-10 text-start shadow-none">
<div className="flex items-center justify-between gap-2">
<div className="flex gap-1">
{cards.map((_, circleIndex) => (
<div
key={circleIndex}
className={`${index >= circleIndex ? "bg-primary" : "bg-muted"} size-2 rounded-full`}
/>
))}
</div>
<div className="text-sm font-medium text-muted-foreground">
{(index + 1).toLocaleString("fa-IR").padStart(2, "۰")}
</div>
</div>
<div className="flex flex-col gap-4 md:flex-row md:justify-between">
<div className="aspect-square size-12 shrink-0">
<img
src={card.image}
alt={card.title}
className="aspect-square h-full w-full rounded-lg object-cover"
/>
</div>
<div className="min-w-0 flex-1">
<h3 className="text-md leading-tight font-medium text-pretty">
{card.title}
</h3>
</div>
</div>
</Card>
))}
</div>
<Dialog>
<DialogTrigger asChild>
<motion.div
className="group relative aspect-video min-h-72 cursor-pointer overflow-hidden rounded-lg"
whileHover="hover"
initial="initial"
>
<motion.div
className="absolute inset-0"
variants={{
initial: { filter: "blur(0px)" },
hover: { filter: "blur(4px)" },
}}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<motion.img
src={imageSrc}
alt={imageAlt}
className="h-full w-full rounded-lg object-cover"
variants={{
initial: { scale: 1 },
hover: { scale: 1.1 },
}}
transition={{ duration: 0.3, ease: "easeOut" }}
/>
</motion.div>
<div className="bg-opacity-20 absolute inset-0 flex items-center justify-center">
<motion.div
className="flex flex-col items-center justify-center gap-2 md:flex-row"
variants={{
initial: { gap: "0.5rem" },
hover: { gap: "0rem" },
}}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<motion.div
variants={{
initial: { x: 0, scale: 1 },
hover: {
x: isMobile ? 0 : "-75%",
scale: 1.2,
},
}}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<Button
size="lg"
className="size-14 rounded-full bg-secondary hover:bg-secondary lg:size-20"
>
<Play className="ms-0.5 size-5 text-primary md:size-7" />
<span className="sr-only">{videoCaption}</span>
</Button>
</motion.div>
<motion.div
className="text-center md:text-start"
variants={{
initial: { opacity: 1 },
hover: { opacity: 0, transform: "-translate-y-3" },
}}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<div className="px-4 py-2">
<p className="text-lg font-bold text-secondary">
{videoCaption}
</p>
<p className="text-lg font-medium text-muted-foreground">
{videoSecondaryCaption}
</p>
</div>
</motion.div>
</motion.div>
</div>
</motion.div>
</DialogTrigger>
<DialogContent className="w-full border-none bg-black p-0 md:max-w-6xl md:p-1">
<DialogTitle className="sr-only">{videoCaption}</DialogTitle>
<DialogDescription className="sr-only">
{videoSecondaryCaption} {videoCaption}
</DialogDescription>
<div className="aspect-video w-full">
{isYouTube ? (
<iframe
className="h-full w-full"
src={`https://www.youtube.com/embed/${youtubeId}?autoplay=1`}
title="شاخص‌های کلیدی را یکجا ببینید"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
) : (
<video
className="h-full w-full rounded-lg"
controls
autoPlay
src={videoUrl}
>
ویجت‌های موردنیاز هر تیم را بچینید و فقط معیارهای مرتبط را ببینید.
</video>
)}
</div>
</DialogContent>
</Dialog>
</div>
</section>
);
};
export { Feature313 };