253 lines
8.2 KiB
React
253 lines
8.2 KiB
React
import React, { useState, useRef } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
|
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
|
|
import { Play, X, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
|
|
// Import Swiper styles
|
|
import 'swiper/css';
|
|
import 'swiper/css/navigation';
|
|
import 'swiper/css/pagination';
|
|
|
|
const VideoSwiperGallery = ({ videos }) => {
|
|
const [selectedVideo, setSelectedVideo] = useState(null);
|
|
const swiperRef = useRef(null);
|
|
|
|
const displayVideos = videos || [];
|
|
|
|
if (displayVideos.length === 0) return null;
|
|
|
|
const getEmbedUrl = (url) => {
|
|
if (!url) return '';
|
|
let embedUrl = url;
|
|
if (url.includes('youtu.be/')) {
|
|
embedUrl = url.replace('youtu.be/', 'www.youtube.com/embed/');
|
|
} else if (url.includes('youtube.com/watch?v=')) {
|
|
embedUrl = url.replace('youtube.com/watch?v=', 'youtube.com/embed/');
|
|
}
|
|
return embedUrl.split('?')[0] + '?autoplay=1';
|
|
};
|
|
|
|
const VideoCard = ({ video }) => {
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5 }}
|
|
className="group cursor-pointer h-full"
|
|
onMouseEnter={() => setIsHovered(true)}
|
|
onMouseLeave={() => setIsHovered(false)}
|
|
onClick={() => setSelectedVideo(video)}
|
|
>
|
|
<div className="relative rounded-xl overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 h-full">
|
|
{/* Thumbnail */}
|
|
<div className="relative aspect-video">
|
|
<img
|
|
src={video.thumbnail}
|
|
alt="Video Thumbnail"
|
|
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110"
|
|
/>
|
|
|
|
{/* Overlay */}
|
|
<div className="absolute inset-0 bg-black/30 group-hover:bg-black/50 transition-colors" />
|
|
|
|
{/* Play Button */}
|
|
<motion.div
|
|
initial={{ scale: 1 }}
|
|
whileHover={{ scale: 1.2 }}
|
|
className="absolute inset-0 flex items-center justify-center"
|
|
>
|
|
<div className="w-14 h-14 bg-white/90 rounded-full flex items-center justify-center shadow-xl group-hover:bg-[#A70710] transition-all">
|
|
<Play className="w-7 h-7 text-[#034E08] group-hover:text-white ml-1" fill="currentColor" />
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
};
|
|
|
|
// Video Modal
|
|
const VideoModal = () => {
|
|
if (!selectedVideo) return null;
|
|
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4 z-[9999]"
|
|
onClick={() => setSelectedVideo(null)}
|
|
>
|
|
<motion.div
|
|
initial={{ scale: 0.9, opacity: 0 }}
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
exit={{ scale: 0.9, opacity: 0 }}
|
|
className="relative w-full max-w-5xl"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
{/* Close Button */}
|
|
<button
|
|
onClick={() => setSelectedVideo(null)}
|
|
className="absolute -top-12 right-0 text-white hover:text-gray-300 transition-colors"
|
|
>
|
|
<X className="w-8 h-8" />
|
|
</button>
|
|
|
|
{/* Video Player */}
|
|
<div className="bg-black rounded-2xl overflow-hidden shadow-2xl">
|
|
<iframe
|
|
src={getEmbedUrl(selectedVideo.youtube_url)}
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowFullScreen
|
|
className="w-full aspect-video"
|
|
></iframe>
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className=" my-12">
|
|
<div className="max-w-[1400px] mx-auto ">
|
|
{/* Header */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="text-center mb-12"
|
|
>
|
|
<h1 className="text-[20px] text-[#00000] sm:text-[22px] lg:text-[24px] font-semibold mb-3">
|
|
Video Gallery
|
|
</h1>
|
|
<p className="text-gray-900 text-[12px]">
|
|
Discover profiles through their stories
|
|
</p>
|
|
</motion.div>
|
|
|
|
{/* Swiper Container */}
|
|
<div className="relative ">
|
|
<Swiper
|
|
ref={swiperRef}
|
|
modules={[Navigation, Pagination, Autoplay]}
|
|
spaceBetween={20}
|
|
slidesPerView={1}
|
|
autoplay={{
|
|
delay: 4000,
|
|
disableOnInteraction: false,
|
|
pauseOnMouseEnter: true
|
|
}}
|
|
// pagination={{
|
|
// clickable: true,
|
|
// dynamicBullets: true,
|
|
// className: 'custom-pagination'
|
|
// }}
|
|
loop={true}
|
|
speed={800}
|
|
breakpoints={{
|
|
640: {
|
|
slidesPerView: 2,
|
|
spaceBetween: 20
|
|
},
|
|
768: {
|
|
slidesPerView: 3,
|
|
spaceBetween: 20
|
|
},
|
|
1024: {
|
|
slidesPerView: 4,
|
|
spaceBetween: 25
|
|
}
|
|
}}
|
|
className="pb-16"
|
|
>
|
|
{displayVideos.map((video) => (
|
|
<SwiperSlide key={video.id}>
|
|
<VideoCard video={video} />
|
|
</SwiperSlide>
|
|
))}
|
|
</Swiper>
|
|
|
|
{/* Custom Navigation Buttons */}
|
|
{/* Custom Navigation Buttons */}
|
|
<motion.button
|
|
whileHover={{ scale: 1.1, x: -5 }}
|
|
whileTap={{ scale: 0.9 }}
|
|
onClick={() => swiperRef.current?.swiper.slidePrev()}
|
|
className="hidden sm:flex absolute left-0 top-1/2 -translate-y-1/2 z-10
|
|
bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-all
|
|
w-12 h-12 rounded-full shadow-xl hover:shadow-2xl items-center justify-center "
|
|
>
|
|
<ChevronLeft className="w-6 h-6 text-gray-700" />
|
|
</motion.button>
|
|
|
|
<motion.button
|
|
whileHover={{ scale: 1.1, x: 5 }}
|
|
whileTap={{ scale: 0.9 }}
|
|
onClick={() => swiperRef.current?.swiper.slideNext()}
|
|
className="hidden sm:flex absolute right-0 top-1/2 -translate-y-1/2 z-10
|
|
bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center hover:bg-white/30 transition-all
|
|
w-12 h-12 rounded-full shadow-xl hover:shadow-2xl items-center justify-center transition-all"
|
|
>
|
|
<ChevronRight className="w-6 h-6 text-gray-700" />
|
|
</motion.button>
|
|
</div>
|
|
|
|
{/* View All Button */}
|
|
{/* <motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ delay: 0.5 }}
|
|
className="text-center mt-12"
|
|
>
|
|
<motion.button
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
className="px-8 py-3 bg-[#034E08] hover:bg-green-700 text-white rounded-full font-semibold text-lg shadow-lg hover:shadow-xl transition-all"
|
|
>
|
|
View All Videos
|
|
</motion.button>
|
|
</motion.div> */}
|
|
</div>
|
|
|
|
{/* Video Modal */}
|
|
{selectedVideo && <VideoModal />}
|
|
|
|
{/* Custom Swiper Styles */}
|
|
<style>{`
|
|
.swiper-pagination-bullet {
|
|
width: 10px;
|
|
height: 10px;
|
|
background: #A70710;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.swiper-pagination-bullet-active {
|
|
opacity: 1;
|
|
width: 30px;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.swiper-slide {
|
|
height: auto;
|
|
display: flex;
|
|
}
|
|
|
|
/* Custom Pagination Position */
|
|
.custom-pagination {
|
|
position: absolute;
|
|
top: 200px; /* Adjusted top position */
|
|
left: 0;
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
z-index: 10;
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default VideoSwiperGallery; |