init
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import {
|
||||
ComponentProps,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { VideoMutingBtn } from "./VideoMutingBtn";
|
||||
import { VideoProgressBar } from "./VideoProgressBar";
|
||||
|
||||
export const VideoPlayer = forwardRef<
|
||||
HTMLVideoElement,
|
||||
{
|
||||
src: string;
|
||||
showMutingBtn: boolean;
|
||||
children?: React.ReactNode;
|
||||
} & ComponentProps<"video">
|
||||
>(
|
||||
(
|
||||
{ src, showMutingBtn, children, loop = true, autoPlay = true, className },
|
||||
ref
|
||||
) => {
|
||||
const progressbarRef = useRef<HTMLDivElement>(null);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => videoRef.current!);
|
||||
|
||||
const [muted, setMuted] = useState(autoPlay);
|
||||
const [playing, setPlaying] = useState(autoPlay);
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
||||
function handleProgressbarClick(e: React.MouseEvent) {
|
||||
const video = videoRef.current;
|
||||
const bar = progressbarRef.current;
|
||||
if (!video || !bar) return;
|
||||
video.currentTime =
|
||||
(video.duration * (e.clientX - bar.getBoundingClientRect().x)) /
|
||||
bar.clientWidth;
|
||||
setProgress(
|
||||
((video.currentTime ?? 0) / (video.duration ?? 1)) * 100
|
||||
);
|
||||
}
|
||||
|
||||
function handlePlaybackClick() {
|
||||
if (!videoRef.current) return;
|
||||
setPlaying(videoRef.current.paused);
|
||||
videoRef.current[videoRef.current.paused ? "play" : "pause"]();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
const timeUpdateHandler = () =>
|
||||
setProgress(((video.currentTime ?? 0) / (video.duration ?? 1)) * 100);
|
||||
|
||||
video.addEventListener("timeupdate", timeUpdateHandler);
|
||||
return () => video.removeEventListener("timeupdate", timeUpdateHandler);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
<video
|
||||
ref={videoRef}
|
||||
src={src}
|
||||
autoPlay={autoPlay}
|
||||
muted={muted}
|
||||
loop={loop}
|
||||
playsInline
|
||||
className={`lg:rounded-[1.111vw] rounded-2xl w-full h-full object-cover${
|
||||
className ? " " + className : ""
|
||||
}`}
|
||||
/>
|
||||
{showMutingBtn && (
|
||||
<VideoMutingBtn
|
||||
handleClick={() => setMuted(!videoRef.current!.muted)}
|
||||
muted={muted}
|
||||
/>
|
||||
)}
|
||||
<div className="absolute inset-0 rounded-2xl [background:linear-gradient(to_top,rgba(20,22,31,0.6),rgba(20,22,31,0))]" />
|
||||
<AnimatePresence>
|
||||
{muted && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<VideoProgressBar
|
||||
muted={muted}
|
||||
progress={progress}
|
||||
progressbarRef={progressbarRef}
|
||||
playing={playing}
|
||||
handlePlaybackClick={handlePlaybackClick}
|
||||
handleProgressbarClick={handleProgressbarClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
VideoPlayer.displayName = "VideoPlayer";
|
||||
Reference in New Issue
Block a user