-
-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathPlayer.tsx
More file actions
123 lines (108 loc) · 3.74 KB
/
Player.tsx
File metadata and controls
123 lines (108 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { useEffect, useState, useRef } from 'preact/hooks';
import { currentEpisode, isMuted, isPlaying } from '../components/state';
import MuteButton from './player/MuteButton';
import PlayButton from './player/PlayButton';
import PlaybackRateButton from './player/PlaybackRateButton';
import ForwardButton from './player/ForwardButton';
import RewindButton from './player/RewindButton';
import Slider from './player/Slider';
export default function Player() {
const audioPlayer = useRef<HTMLAudioElement | null>(null);
const progressRef = useRef<number | null>(null);
const [progress, setProgress] = useState(0);
if (currentEpisode.value === null) {
return;
}
const { audio, episodeNumber, title } = currentEpisode.value;
function whilePlaying() {
if (audioPlayer.current?.duration) {
const percentage =
(audioPlayer.current.currentTime / audioPlayer.current.duration) * 100;
setProgress(percentage);
const slider = document.querySelector('.slider');
const particles = document.querySelector('.ship-particles');
if (slider) {
(slider as HTMLElement).style.setProperty(
'--seek-before-width',
`${percentage}%`
);
}
if (particles && slider) {
const pxOffset = slider.clientWidth * (percentage / 100);
(particles as HTMLElement).style.setProperty(
'--seek-particles-left',
`${pxOffset - 10}px` // -5 to put the dots into the track
);
}
}
progressRef.current = requestAnimationFrame(whilePlaying);
}
useEffect(() => {
if (audioPlayer.current) {
audioPlayer.current.src = audio.src;
audioPlayer.current.currentTime = 0;
audioPlayer.current.play();
}
}, [audio]);
useEffect(() => {
if (isPlaying.value) {
audioPlayer.current?.play();
progressRef.current = requestAnimationFrame(whilePlaying);
} else {
audioPlayer.current?.pause();
cancelAnimationFrame(progressRef.current as number);
}
}, [isPlaying.value]);
useEffect(() => {
if (progress >= 99.99) {
isPlaying.value = false;
setProgress(0);
}
}, [progress]);
return (
<div class="player fixed inset-x-0 bottom-0 z-50 lg:left-112 xl:left-120">
<div
class="flex items-center gap-6 bg-light-player/90 px-4 py-4 backdrop-blur-xs md:px-6 dark:bg-dark-player/90"
role="region"
style={{ viewTransitionName: 'player' }}
>
<div class="hidden self-start md:block">
<PlayButton />
</div>
<div class="flex flex-1 flex-col gap-3 overflow-hidden p-1">
<a
href={`/${episodeNumber}`}
class="truncate text-center text-sm font-bold leading-6 md:text-left"
title={title}
>
{title}
</a>
<div class="flex justify-between gap-6">
<div class="flex items-center md:hidden">
<MuteButton />
</div>
<div class="flex flex-none items-center gap-4">
<RewindButton audioPlayer={audioPlayer} />
<div class="md:hidden">
<PlayButton />
</div>
<ForwardButton audioPlayer={audioPlayer} />
</div>
<Slider audioPlayer={audioPlayer} progress={progress} />
<div class="flex items-center gap-4">
<div class="flex items-center">
<PlaybackRateButton audioPlayer={audioPlayer} />
</div>
<div class="hidden items-center md:flex">
<MuteButton />
</div>
</div>
</div>
<div class="hidden">
<audio muted={isMuted} ref={audioPlayer} />
</div>
</div>
</div>
</div>
);
}