114 lines
3.4 KiB
TypeScript
114 lines
3.4 KiB
TypeScript
/* eslint-disable react-hooks/rules-of-hooks */
|
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
import { motion } from "framer-motion";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import ArrowLeftIcon from "./icons/ArrowLeftIcon";
|
|
import ArrowRightIcon from "./icons/ArrowRightIcon";
|
|
import { useSwipeable } from "react-swipeable";
|
|
import { Video } from "../types/Video";
|
|
|
|
interface IVideoSliderMobile {
|
|
isViewportEntered: boolean;
|
|
videos: Video[];
|
|
}
|
|
|
|
function VideoSliderMobile({ isViewportEntered, videos }: IVideoSliderMobile) {
|
|
const [activeIndex, setActiveIndex] = useState<number>(0);
|
|
const videoRefs = videos.map(() => useRef<HTMLVideoElement>(null));
|
|
const handlers = useSwipeable({
|
|
trackMouse: true,
|
|
onSwipedLeft: handleClickNext,
|
|
onSwipedRight: handleClickPrev,
|
|
});
|
|
|
|
function handleClickPrev() {
|
|
if (activeIndex === 0) {
|
|
setActiveIndex(videos.length - 1);
|
|
return;
|
|
}
|
|
|
|
setActiveIndex((prev) => prev - 1);
|
|
}
|
|
|
|
function handleClickNext() {
|
|
if (activeIndex === videos.length - 1) {
|
|
setActiveIndex(0);
|
|
return;
|
|
}
|
|
|
|
setActiveIndex((prev) => prev + 1);
|
|
}
|
|
|
|
useEffect(() => {
|
|
videos.forEach((_, index) => {
|
|
if (activeIndex === index) {
|
|
videoRefs[index].current?.play();
|
|
} else {
|
|
videoRefs[index].current?.pause();
|
|
}
|
|
});
|
|
}, [activeIndex, videoRefs]);
|
|
|
|
return (
|
|
<div
|
|
{...handlers}
|
|
className="xl:hidden flex flex-col sm:gap-6 gap-4 border-b border-[#3D425C] pb-5"
|
|
>
|
|
<div
|
|
className={`relative flex sm:gap-[88px] items-start transition-all duration-500`}
|
|
style={{ left: `-${activeIndex * 100}%` }}
|
|
>
|
|
{videos.map((item, index) => (
|
|
<motion.video
|
|
poster={item.poster}
|
|
key={item.id}
|
|
ref={videoRefs[index]}
|
|
src={isViewportEntered ? item.value : ""}
|
|
muted
|
|
loop
|
|
playsInline
|
|
preload="metadata"
|
|
className={`relative aspect-video transition-all duration-500 sm:w-[calc(100%-88px)] ${
|
|
index !== activeIndex
|
|
? "sm:scale-[70%] scale-[80%] sm:-translate-y-[15%] -translate-y-[10%] sm:-translate-x-[calc(15%+88px-12px)] -translate-x-[calc(10%-8px)]"
|
|
: ""
|
|
}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div className="flex justify-between sm:gap-[30px] gap-3 sm:h-auto h-[168px]">
|
|
<div className="flex flex-col gap-3">
|
|
<p className="text-xl font-gilroy font-medium">
|
|
{videos[activeIndex].title}
|
|
</p>
|
|
<p className="text-sm">{videos[activeIndex].desc}</p>
|
|
</div>
|
|
<div className="relative flex flex-col items-center gap-4">
|
|
<div className="sm:absolute -top-[64px]">
|
|
<p className="sm:text-2xl text-xl font-gilroy font-medium">
|
|
{activeIndex + 1}/{videos.length}
|
|
</p>
|
|
</div>
|
|
<div className="flex flex-col gap-2 self-end">
|
|
<button
|
|
onClick={handleClickNext}
|
|
className="sm:p-4 p-2 border border-[#3D425C] rounded-full outline-none"
|
|
>
|
|
<ArrowRightIcon />
|
|
</button>
|
|
<button
|
|
onClick={handleClickPrev}
|
|
className="sm:p-4 p-2 border border-[#3D425C] rounded-full outline-none"
|
|
>
|
|
<ArrowLeftIcon />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default VideoSliderMobile;
|