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 the Event
+
+
+
+
+
+
+
)
}
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