99 lines
3.8 KiB
TypeScript
99 lines
3.8 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
|
|
const DroneVideoCarousel: React.FC = () => {
|
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
|
|
// Placeholder YouTube video IDs - replace with actual drone video IDs
|
|
const videos = [
|
|
{ id: 'dQw4w9WgXcQ', title: 'Drone Footage 1' },
|
|
{ id: 'dQw4w9WgXcQ', title: 'Drone Footage 2' },
|
|
{ id: 'dQw4w9WgXcQ', title: 'Drone Footage 3' },
|
|
{ id: 'dQw4w9WgXcQ', title: 'Drone Footage 4' }
|
|
];
|
|
|
|
const nextSlide = () => {
|
|
setCurrentIndex((prevIndex) => (prevIndex + 1) % videos.length);
|
|
};
|
|
|
|
const prevSlide = () => {
|
|
setCurrentIndex((prevIndex) => (prevIndex - 1 + videos.length) % videos.length);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const timer = setInterval(nextSlide, 5000);
|
|
return () => clearInterval(timer);
|
|
}, []);
|
|
|
|
return (
|
|
<section className="py-20 bg-background">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="text-center mb-12">
|
|
<h2 className="text-3xl font-bold text-text sm:text-4xl">
|
|
Drone Videography
|
|
</h2>
|
|
<p className="mt-4 text-lg text-lines max-w-2xl mx-auto">
|
|
Capturing stunning aerial perspectives through professional drone footage
|
|
</p>
|
|
</div>
|
|
|
|
<div className="relative max-w-4xl mx-auto">
|
|
<div className="aspect-video bg-background-light rounded-xl overflow-hidden shadow-2xl border border-lines">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={currentIndex}
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
className="w-full h-full"
|
|
>
|
|
<iframe
|
|
src={`https://www.youtube.com/embed/${videos[currentIndex].id}?autoplay=0&mute=1&loop=1&playlist=${videos[currentIndex].id}`}
|
|
title={videos[currentIndex].title}
|
|
className="w-full h-full"
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowFullScreen
|
|
/>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</div>
|
|
|
|
<button
|
|
onClick={prevSlide}
|
|
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-boxes hover:bg-other text-text p-3 rounded-full transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-lines focus:ring-offset-2 focus:ring-offset-background"
|
|
aria-label="Previous video"
|
|
>
|
|
<ChevronLeft className="h-6 w-6" />
|
|
</button>
|
|
|
|
<button
|
|
onClick={nextSlide}
|
|
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-boxes hover:bg-other text-text p-3 rounded-full transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-lines focus:ring-offset-2 focus:ring-offset-background"
|
|
aria-label="Next video"
|
|
>
|
|
<ChevronRight className="h-6 w-6" />
|
|
</button>
|
|
|
|
<div className="flex justify-center mt-6 space-x-2">
|
|
{videos.map((_, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => setCurrentIndex(index)}
|
|
className={`w-3 h-3 rounded-full transition-all duration-200 ${
|
|
index === currentIndex
|
|
? 'bg-other'
|
|
: 'bg-lines hover:bg-boxes'
|
|
}`}
|
|
aria-label={`Go to video ${index + 1}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default DroneVideoCarousel; |