diff --git a/client/public/videos/board-intro-archive.mp4 b/client/public/videos/board-intro-archive.mp4 new file mode 100644 index 0000000..476306f Binary files /dev/null and b/client/public/videos/board-intro-archive.mp4 differ diff --git a/client/public/videos/community-01.mp4 b/client/public/videos/community-01.mp4 new file mode 100644 index 0000000..29cc136 Binary files /dev/null and b/client/public/videos/community-01.mp4 differ diff --git a/client/public/videos/community-02.mp4 b/client/public/videos/community-02.mp4 new file mode 100644 index 0000000..1c3e26a Binary files /dev/null and b/client/public/videos/community-02.mp4 differ diff --git a/client/public/videos/community-03.mp4 b/client/public/videos/community-03.mp4 new file mode 100644 index 0000000..78e5b40 Binary files /dev/null and b/client/public/videos/community-03.mp4 differ diff --git a/client/public/videos/community-04.mp4 b/client/public/videos/community-04.mp4 new file mode 100644 index 0000000..ad1e18f Binary files /dev/null and b/client/public/videos/community-04.mp4 differ diff --git a/client/public/videos/community-05.mp4 b/client/public/videos/community-05.mp4 new file mode 100644 index 0000000..025443a Binary files /dev/null and b/client/public/videos/community-05.mp4 differ diff --git a/client/src/App.tsx b/client/src/App.tsx index e61c175..bac1178 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -10,6 +10,7 @@ import Bylaws from './components/Bylaws'; import Sponsors from './components/Sponsors'; import MeetBoard from './components/Meet-Board'; import Gallery from './components/Gallery'; +import VideoGallery from './components/VideoGallery'; /* import ComingSoon from './components/ComingSoon'; */ import JoinMCDi from './components/JoinMCDi'; @@ -28,6 +29,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> } /> diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx index 3d59ef9..87670ba 100644 --- a/client/src/components/Header.tsx +++ b/client/src/components/Header.tsx @@ -74,7 +74,8 @@ const Header: React.FC = () => {
  • setIsMenuOpen(false)}>Home
  • setIsMenuOpen(false)}>About MCDi
  • setIsMenuOpen(false)}>Calendar
  • -
  • setIsMenuOpen(false)}>Gallery
  • +
  • setIsMenuOpen(false)}>Photo Gallery
  • +
  • setIsMenuOpen(false)}>Video Gallery
  • setIsMenuOpen(false)}>Join MCDi
  • @@ -157,7 +158,8 @@ const AboutDropdown: React.FC = () => { Meet MCDi Board Bylaws Minutes - Gallery + Photo Gallery + Video Gallery Sponsors diff --git a/client/src/components/VideoGallery.tsx b/client/src/components/VideoGallery.tsx new file mode 100644 index 0000000..defa5cc --- /dev/null +++ b/client/src/components/VideoGallery.tsx @@ -0,0 +1,270 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { FaPlay, FaPause, FaStop } from 'react-icons/fa'; + +interface VideoItem { + id: number; + videoUrl: string; + title: string; + thumbnail?: string; +} + +const videoData: VideoItem[] = [ + { + id: 1, + videoUrl: '/videos/community-01.mp4', + title: 'Community Event Video 1', + }, + { + id: 2, + videoUrl: '/videos/community-02.mp4', + title: 'Community Event Video 2', + }, + { + id: 3, + videoUrl: '/videos/community-03.mp4', + title: 'Community Event Video 3', + }, + { + id: 4, + videoUrl: '/videos/community-04.mp4', + title: 'Community Event Video 4', + }, + { + id: 5, + videoUrl: '/videos/community-05.mp4', + title: 'Community Event Video 5', + }, + { + id: 6, + videoUrl: '/videos/board-intro-archive.mp4', + title: 'Board Introduction Archive', + }, +]; + +const VideoGallery: React.FC = () => { + const [selectedVideo, setSelectedVideo] = useState(null); + const videoRef = useRef(null); + const [isPlaying, setIsPlaying] = useState(false); + const [showControls, setShowControls] = useState(true); + const [progress, setProgress] = useState(0); + const controlsTimeoutRef = useRef(null); + + const openVideo = (item: VideoItem) => { + setSelectedVideo(item); + setIsPlaying(false); + setProgress(0); + }; + + const closeVideo = () => { + if (videoRef.current) { + videoRef.current.pause(); + videoRef.current.currentTime = 0; + } + setSelectedVideo(null); + setIsPlaying(false); + }; + + const togglePlay = () => { + if (videoRef.current) { + if (isPlaying) { + videoRef.current.pause(); + } else { + videoRef.current.play(); + } + setIsPlaying(!isPlaying); + } + }; + + const handleStop = () => { + if (videoRef.current) { + videoRef.current.pause(); + videoRef.current.currentTime = 0; + setIsPlaying(false); + } + }; + + const handleTimeUpdate = () => { + if (videoRef.current) { + const progress = (videoRef.current.currentTime / videoRef.current.duration) * 100; + setProgress(progress); + } + }; + + const handleSeek = (e: React.ChangeEvent) => { + if (videoRef.current) { + const seekTime = (parseFloat(e.target.value) / 100) * videoRef.current.duration; + videoRef.current.currentTime = seekTime; + } + }; + + const handleMouseMove = () => { + setShowControls(true); + if (controlsTimeoutRef.current) { + clearTimeout(controlsTimeoutRef.current); + } + controlsTimeoutRef.current = setTimeout(() => { + if (isPlaying) { + setShowControls(false); + } + }, 3000); + }; + + useEffect(() => { + return () => { + if (controlsTimeoutRef.current) { + clearTimeout(controlsTimeoutRef.current); + } + }; + }, []); + + return ( +
    + +

    Video Gallery

    + + {/* Video Grid */} +
    + {videoData.map((item) => ( + openVideo(item)} + > +
    +
    +
    +
    +

    + {item.title} +

    +
    +
    +
    + ))} +
    +
    + + {/* Video Modal */} + + {selectedVideo && ( + + e.stopPropagation()} + onMouseMove={handleMouseMove} + onMouseLeave={() => isPlaying && setShowControls(false)} + > + {/* Close Button */} + + + {/* Video Container */} +
    + + + {/* Video Controls */} + + {showControls && ( + +
    +

    + {selectedVideo.title} +

    +
    +
    + + + +
    +
    + )} +
    +
    +
    +
    + )} +
    +
    + ); +}; + +export default VideoGallery;