diff --git a/src/components/Highlights.jsx b/src/components/Highlights.jsx index 488ac6d..73b6c6c 100644 --- a/src/components/Highlights.jsx +++ b/src/components/Highlights.jsx @@ -1,7 +1,44 @@ +import { useGSAP } from "@gsap/react" +import { rightImg, watchImg } from "../utils" +import gsap from "gsap" +import VideoCarousel from "./VideoCarousel" const Highlights = () => { + useGSAP(()=>{ + gsap.to('#title',{ + opacity:1, + y:0, + }) + gsap.to('.link',{ + opacity:1, + y:0, + duration:1, + stagger:0.25, + }) + }) + + return ( -
Highlights
+
+
+
+

+ Get the highlights. +

+
+

+ Watch the films + watch +

+

+ Watch the Event + right +

+
+
+ +
+
) } diff --git a/src/components/VideoCarousel.jsx b/src/components/VideoCarousel.jsx new file mode 100644 index 0000000..a463e20 --- /dev/null +++ b/src/components/VideoCarousel.jsx @@ -0,0 +1,234 @@ +import gsap from "gsap"; +import { useGSAP } from "@gsap/react"; +import { ScrollTrigger } from "gsap/all"; +gsap.registerPlugin(ScrollTrigger); +import { useEffect, useRef, useState } from "react"; + +import { hightlightsSlides } from "../constants"; +import { pauseImg, playImg, replayImg } from "../utils"; + +const VideoCarousel = () => { + const videoRef = useRef([]); + const videoSpanRef = useRef([]); + const videoDivRef = useRef([]); + + // video and indicator + const [video, setVideo] = useState({ + isEnd: false, + startPlay: false, + videoId: 0, + isLastVideo: false, + isPlaying: false, + }); + + const [loadedData, setLoadedData] = useState([]); + const { isEnd, isLastVideo, startPlay, videoId, isPlaying } = video; + + useGSAP(() => { + // slider animation to move the video out of the screen and bring the next video in + gsap.to("#slider", { + transform: `translateX(${-100 * videoId}%)`, + duration: 2, + ease: "power2.inOut", // show visualizer https://gsap.com/docs/v3/Eases + }); + + // video animation to play the video when it is in the view + gsap.to("#video", { + scrollTrigger: { + trigger: "#video", + toggleActions: "restart none none none", + }, + onComplete: () => { + setVideo((pre) => ({ + ...pre, + startPlay: true, + isPlaying: true, + })); + }, + }); + }, [isEnd, videoId]); + + useEffect(() => { + let currentProgress = 0; + let span = videoSpanRef.current; + + if (span[videoId]) { + // animation to move the indicator + let anim = gsap.to(span[videoId], { + onUpdate: () => { + // get the progress of the video + const progress = Math.ceil(anim.progress() * 100); + + if (progress != currentProgress) { + currentProgress = progress; + + // set the width of the progress bar + gsap.to(videoDivRef.current[videoId], { + width: + window.innerWidth < 760 + ? "10vw" // mobile + : window.innerWidth < 1200 + ? "10vw" // tablet + : "4vw", // laptop + }); + + // set the background color of the progress bar + gsap.to(span[videoId], { + width: `${currentProgress}%`, + backgroundColor: "white", + }); + } + }, + + // when the video is ended, replace the progress bar with the indicator and change the background color + onComplete: () => { + if (isPlaying) { + gsap.to(videoDivRef.current[videoId], { + width: "12px", + }); + gsap.to(span[videoId], { + backgroundColor: "#afafaf", + }); + } + }, + }); + + if (videoId == 0) { + anim.restart(); + } + + // update the progress bar + const animUpdate = () => { + anim.progress( + videoRef.current[videoId].currentTime / + hightlightsSlides[videoId].videoDuration + ); + }; + + if (isPlaying) { + // ticker to update the progress bar + gsap.ticker.add(animUpdate); + } else { + // remove the ticker when the video is paused (progress bar is stopped) + gsap.ticker.remove(animUpdate); + } + } + }, [videoId, startPlay]); + + useEffect(() => { + if (loadedData.length > 3) { + if (!isPlaying) { + videoRef.current[videoId].pause(); + } else { + startPlay && videoRef.current[videoId].play(); + } + } + }, [startPlay, videoId, isPlaying, loadedData]); + + // vd id is the id for every video until id becomes number 3 + const handleProcess = (type, i) => { + switch (type) { + case "video-end": + setVideo((pre) => ({ ...pre, isEnd: true, videoId: i + 1 })); + break; + + case "video-last": + setVideo((pre) => ({ ...pre, isLastVideo: true })); + break; + + case "video-reset": + setVideo((pre) => ({ ...pre, videoId: 0, isLastVideo: false })); + break; + + case "pause": + setVideo((pre) => ({ ...pre, isPlaying: !pre.isPlaying })); + break; + + case "play": + setVideo((pre) => ({ ...pre, isPlaying: !pre.isPlaying })); + break; + + default: + return video; + } + }; + + const handleLoadedMetaData = (i, e) => setLoadedData((pre) => [...pre, e]); + + return ( + <> +
+ {hightlightsSlides.map((list, i) => ( +
+
+
+ +
+ +
+ {list.textLists.map((text, i) => ( +

+ {text} +

+ ))} +
+
+
+ ))} +
+ +
+
+ {videoRef.current.map((_, i) => ( + (videoDivRef.current[i] = el)} + > + (videoSpanRef.current[i] = el)} + /> + + ))} +
+ + +
+ + ); +}; + +export default VideoCarousel; \ No newline at end of file