228 lines
8.2 KiB
TypeScript
228 lines
8.2 KiB
TypeScript
"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("relative w-full min-w-0 overflow-hidden bg-muted py-16 md:py-24", className)}
|
||
>
|
||
<div className="container flex min-w-0 flex-col gap-2 px-4 sm:px-6">
|
||
<div className="grid w-full min-w-0 grid-cols-1 gap-1 lg:grid-cols-4">
|
||
{cards.map((card, index) => (
|
||
<Card
|
||
key={card.id}
|
||
className="min-w-0 overflow-hidden border-none p-5 text-start shadow-none sm:p-8 lg:p-10"
|
||
>
|
||
<div className="flex min-w-0 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 min-w-0 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-balance break-words">
|
||
{card.title}
|
||
</h3>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
|
||
<Dialog>
|
||
<DialogTrigger asChild>
|
||
<motion.div
|
||
className="group relative aspect-video w-full min-w-0 min-h-48 cursor-pointer overflow-hidden rounded-lg sm:min-h-72"
|
||
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 max-w-full rounded-lg object-cover"
|
||
variants={{
|
||
initial: { scale: 1 },
|
||
hover: isMobile ? { scale: 1 } : { 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: isMobile ? 1 : 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="min-w-0 text-center md:text-start"
|
||
variants={{
|
||
initial: { opacity: 1 },
|
||
hover: isMobile
|
||
? { opacity: 1 }
|
||
: { opacity: 0, transform: "-translate-y-3" },
|
||
}}
|
||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||
>
|
||
<div className="px-2 py-2 sm:px-4">
|
||
<p className="text-base font-bold text-balance break-words text-secondary sm:text-lg">
|
||
{videoCaption}
|
||
</p>
|
||
<p className="text-base font-medium text-balance break-words text-muted-foreground sm:text-lg">
|
||
{videoSecondaryCaption}
|
||
</p>
|
||
</div>
|
||
</motion.div>
|
||
</motion.div>
|
||
</div>
|
||
</motion.div>
|
||
</DialogTrigger>
|
||
<DialogContent className="w-[calc(100%-2rem)] max-w-[calc(100%-2rem)] border-none bg-black p-0 sm:w-full 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 };
|