diff options
Diffstat (limited to 'src/components/YTPlayer')
| -rw-r--r-- | src/components/YTPlayer/index.styled.ts | 39 | ||||
| -rw-r--r-- | src/components/YTPlayer/index.tsx | 100 |
2 files changed, 139 insertions, 0 deletions
diff --git a/src/components/YTPlayer/index.styled.ts b/src/components/YTPlayer/index.styled.ts new file mode 100644 index 0000000..3c98f1e --- /dev/null +++ b/src/components/YTPlayer/index.styled.ts @@ -0,0 +1,39 @@ +import styled from "styled-components"; + +export const ProgressBackground = styled.div` + position: relative; + width: 100%; + height: 12px; + background-color: var(--cl-gray-2); + border: 1px solid ${({ theme }) => theme.border}; + margin: 24px 0 4px 0; +`; + +export const Progress = styled.div<{ value: number }>` + width: ${({ value }) => value * 6.25}%; + height: 100%; + background-color: ${({ theme }) => theme.green}; + transition: width 0.5s; +`; + +export const Separator = styled.div` + position: absolute; + top: 0; + width: 1px; + height: 100%; + background-color: ${({ theme }) => theme.border}; +`; + +export const TimeStamps = styled.div` + display: flex; + justify-content: space-between; + width: 100%; + margin-bottom: 12px; +`; + +export const TimeStamp = styled.p` + margin: 0; + font-family: "Roboto Mono", monospace; + font-size: 0.7rem; + color: var(--cl-gray-5); +`; diff --git a/src/components/YTPlayer/index.tsx b/src/components/YTPlayer/index.tsx new file mode 100644 index 0000000..1aac9ac --- /dev/null +++ b/src/components/YTPlayer/index.tsx @@ -0,0 +1,100 @@ +import React from "react"; +import YouTube from "react-youtube"; +import { IoPlay, IoPause } from "react-icons/io5"; +import { playTimes } from "../../constants"; +import * as Styled from "./index.styled"; + +interface Props { + id: string; + currentTry: number; +} + +export function Player({ id, currentTry }: Props) { + const opts = { + width: "0", + height: "0", + }; + + // react-youtube doesn't export types for this + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const playerRef = React.useRef<any>(null); + + const currentPlayTime = playTimes[currentTry]; + + const [play, setPlay] = React.useState<boolean>(false); + + const [currentTime, setCurrentTime] = React.useState<number>(0); + + const [isReady, setIsReady] = React.useState<boolean>(false); + + React.useEffect(() => { + setInterval(() => { + playerRef.current?.internalPlayer + .getCurrentTime() + .then((time: number) => { + setCurrentTime(time); + }); + }, 250); + }, []); + + React.useEffect(() => { + if (play) { + if (currentTime * 1000 >= currentPlayTime) { + playerRef.current?.internalPlayer.pauseVideo(); + playerRef.current?.internalPlayer.seekTo(0); + setPlay(false); + } + } + }, [play, currentTime]); + + // don't call play video each time currentTime changes + const startPlayback = React.useCallback(() => { + playerRef.current?.internalPlayer.playVideo(); + setPlay(true); + }, []); + + const setReady = React.useCallback(() => { + setIsReady(true); + }, []); + + return ( + <> + <YouTube opts={opts} videoId={id} onReady={setReady} ref={playerRef} /> + {isReady ? ( + <> + <Styled.ProgressBackground> + {currentTime !== 0 && <Styled.Progress value={currentTime} />} + {playTimes.map((playTime) => ( + <Styled.Separator + style={{ left: `${(playTime / 16000) * 100}%` }} + key={playTime} + /> + ))} + </Styled.ProgressBackground> + <Styled.TimeStamps> + <Styled.TimeStamp>1s</Styled.TimeStamp> + <Styled.TimeStamp>16s</Styled.TimeStamp> + </Styled.TimeStamps> + {!play && ( + <IoPlay + style={{ cursor: "pointer" }} + size={36} + color="var(--cl-green-6)" + onClick={startPlayback} + /> + )} + {play && ( + <IoPause + style={{ cursor: "pointer" }} + size={36} + color="var(--cl-green-6)" + onClick={startPlayback} + /> + )} + </> + ) : ( + <p>Loading player...</p> + )} + </> + ); +} |
