198 lines
5.6 KiB
TypeScript
198 lines
5.6 KiB
TypeScript
"use client";
|
|
|
|
import { AudioLines } from "lucide-react";
|
|
import type React from "react";
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
import {
|
|
Carousel,
|
|
CarouselContent,
|
|
CarouselItem,
|
|
CarouselNext,
|
|
CarouselPrevious,
|
|
} from "@/components/ui/carousel";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface VideoSectionProps {
|
|
videoSrc: string;
|
|
thumbnailSrc: string;
|
|
studioName: string;
|
|
projectTitle: string;
|
|
}
|
|
|
|
const VideoSection: React.FC<VideoSectionProps> = ({
|
|
videoSrc,
|
|
thumbnailSrc,
|
|
studioName,
|
|
projectTitle,
|
|
}) => {
|
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (videoRef.current) {
|
|
videoRef.current.pause();
|
|
videoRef.current.currentTime = 0;
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (videoRef.current) {
|
|
if (isHovered) {
|
|
videoRef.current.play();
|
|
} else {
|
|
videoRef.current.pause();
|
|
videoRef.current.currentTime = 0;
|
|
}
|
|
}
|
|
}, [isHovered]);
|
|
|
|
const handleMouseEnter = () => {
|
|
setIsHovered(true);
|
|
};
|
|
|
|
const handleMouseLeave = () => {
|
|
setIsHovered(false);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="group relative h-[60vh] w-full cursor-pointer overflow-hidden md:h-[70vh]"
|
|
onMouseEnter={handleMouseEnter}
|
|
onMouseLeave={handleMouseLeave}
|
|
>
|
|
{/* Thumbnail Image */}
|
|
<img
|
|
src={thumbnailSrc}
|
|
alt={projectTitle}
|
|
className={`absolute inset-0 h-full w-full object-cover transition-opacity duration-700 ease-in-out ${isHovered ? "opacity-0" : "opacity-100"
|
|
}`}
|
|
/>
|
|
|
|
{/* Video */}
|
|
<video
|
|
ref={videoRef}
|
|
className={`absolute inset-0 h-full w-full object-cover transition-opacity duration-700 ease-in-out ${isHovered ? "opacity-100" : "opacity-0"
|
|
}`}
|
|
muted
|
|
loop
|
|
playsInline
|
|
preload="metadata"
|
|
>
|
|
<source src={videoSrc} type="video/mp4" />
|
|
مرورگر شما از پخش ویدیو پشتیبانی نمیکند.
|
|
</video>
|
|
|
|
<div className="absolute inset-0 bg-black/30 transition-all duration-500 group-hover:bg-black/20" />
|
|
|
|
<div className="absolute inset-0 bottom-12 flex items-end">
|
|
<div className="px-6 text-start text-white sm:px-8 md:px-12 lg:px-16 xl:px-20">
|
|
<p className="mb-2 text-xs font-medium tracking-wider opacity-80 sm:mb-3 sm:text-sm md:mb-4 md:text-base">
|
|
{studioName}
|
|
</p>
|
|
<h2 className="max-w-md text-2xl font-light tracking-tight sm:text-3xl md:text-4xl lg:max-w-lg">
|
|
{projectTitle}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const videoSections = [
|
|
{
|
|
thumbnailSrc:
|
|
"/block-media/shadcnblocks/block/photos/jeremy-bishop-iEjCQtcsVPY-unsplash.jpg",
|
|
videoSrc:
|
|
"/block-media/shadcnblocks/block/3571264-hd_1280_720_30fps.mp4",
|
|
studioName: "مریدیان لبز",
|
|
projectTitle: "تعاملهای اثیری",
|
|
},
|
|
|
|
{
|
|
thumbnailSrc:
|
|
"/block-media/shadcnblocks/block/photos/carles-rabada-f7UprkNqi08-unsplash.jpg",
|
|
videoSrc:
|
|
"/block-media/shadcnblocks/block/1448735-hd_1366_720_24fps.mp4",
|
|
studioName: "زنیث دیجیتال",
|
|
projectTitle: "نکسوس استودیو",
|
|
},
|
|
{
|
|
thumbnailSrc:
|
|
"/block-media/shadcnblocks/block/photos/sam-wermut-FiUuNWxnb3k-unsplash.jpg",
|
|
videoSrc:
|
|
"/block-media/shadcnblocks/block/19348567-hd_1280_720_25fps.mp4",
|
|
studioName: "پریزم لبز",
|
|
projectTitle: "مرزهای نو",
|
|
},
|
|
{
|
|
thumbnailSrc:
|
|
"/block-media/shadcnblocks/block/photos/ines-alvarez-fdez-VjRc6HDXJ5s-unsplash.jpg",
|
|
videoSrc:
|
|
"/block-media/shadcnblocks/block/9882072-hd_1280_720_30fps.mp4",
|
|
studioName: "سمفونی تعامل",
|
|
projectTitle: "تعاملهای روان",
|
|
},
|
|
];
|
|
|
|
interface Projects15eProps {
|
|
className?: string;
|
|
}
|
|
|
|
const Projects15e = ({ className }: Projects15eProps) => {
|
|
return (
|
|
<section dir="rtl" lang="fa" className={cn("w-full bg-background", className)}>
|
|
{/* Header Section */}
|
|
<div className="container py-16">
|
|
<div className="text-start text-foreground">
|
|
<h1 className="mb-4 text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl lg:mb-8 lg:text-8xl">
|
|
کاوش در پروژههای ما
|
|
</h1>
|
|
|
|
<div className="flex items-center">
|
|
<p className="me-4 text-sm font-medium tracking-wider opacity-80">
|
|
کارهای ما
|
|
</p>
|
|
<div className="opacity-60">
|
|
<AudioLines className="h-6 w-6" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Full Width Carousel */}
|
|
<div className="w-full">
|
|
<Carousel
|
|
dir="rtl"
|
|
opts={{
|
|
align: "start",
|
|
loop: true,
|
|
direction: "rtl",
|
|
}}
|
|
className="w-full"
|
|
>
|
|
<CarouselContent className="-ms-2 md:-ms-4">
|
|
{videoSections.map((section, index) => (
|
|
<CarouselItem
|
|
key={index}
|
|
className="ps-2 md:basis-4/5 md:ps-4 lg:basis-3/4 xl:basis-2/3"
|
|
>
|
|
<VideoSection
|
|
videoSrc={section.videoSrc}
|
|
thumbnailSrc={section.thumbnailSrc}
|
|
studioName={section.studioName}
|
|
projectTitle={section.projectTitle}
|
|
/>
|
|
</CarouselItem>
|
|
))}
|
|
</CarouselContent>
|
|
<CarouselPrevious className="start-4 md:start-8" />
|
|
<CarouselNext className="end-4 md:end-8" />
|
|
</Carousel>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Projects15e };
|