aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/YTPlayer
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2026-06-03 17:22:48 -0700
committerPinapelz <yukais@pinapelz.com>2026-06-03 17:22:48 -0700
commit14172f9dd64ce91ba5cf51f82c53deb6a81d68a6 (patch)
tree5e12ce4e30ecaed9a2aac48d2959d99a4d8b4ef7 /src/components/YTPlayer
parent818db3ef4aadf489dba5ba8ba4f3bb4e150f0b22 (diff)
create daily/unlimited mode, CDN audio file for daily mode
Diffstat (limited to 'src/components/YTPlayer')
-rw-r--r--src/components/YTPlayer/index.styled.ts39
-rw-r--r--src/components/YTPlayer/index.tsx100
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>
+ )}
+ </>
+ );
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage