mirror of
https://github.com/remvze/moodist.git
synced 2025-12-17 00:44:14 +00:00
feat: add basic audio player
This commit is contained in:
parent
c9e8bd41fd
commit
5a7a58e883
4 changed files with 61 additions and 6 deletions
|
|
@ -1,20 +1,31 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { useSound } from '@/hooks/use-sound';
|
||||
import { cn } from '@/helpers/styles';
|
||||
|
||||
import styles from './sound.module.css';
|
||||
|
||||
interface SoundProps {
|
||||
sound: { label: string; src: string };
|
||||
label: string;
|
||||
src: string;
|
||||
}
|
||||
|
||||
export function Sound({ sound }: SoundProps) {
|
||||
export function Sound({ label, src }: SoundProps) {
|
||||
const [isSelected, setIsSelected] = useState(false);
|
||||
const [volume, setVolume] = useState(0.5);
|
||||
|
||||
const sound = useSound(src, { loop: true, volume });
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSelected) setVolume(0.5);
|
||||
}, [isSelected]);
|
||||
if (!isSelected) {
|
||||
sound?.pause();
|
||||
setVolume(0.5);
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
sound?.play();
|
||||
}
|
||||
}, [isSelected, sound]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -22,8 +33,9 @@ export function Sound({ sound }: SoundProps) {
|
|||
onClick={() => setIsSelected(prev => !prev)}
|
||||
onKeyDown={() => setIsSelected(prev => !prev)}
|
||||
>
|
||||
<h3>{sound.label}</h3>
|
||||
<h3>{label}</h3>
|
||||
<input
|
||||
autoComplete="off"
|
||||
disabled={!isSelected}
|
||||
max={100}
|
||||
min={0}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function Sounds({ sounds }: SoundsProps) {
|
|||
return (
|
||||
<div className={styles.sounds}>
|
||||
{sounds.map(sound => (
|
||||
<Sound key={sound.label} sound={sound} />
|
||||
<Sound key={sound.label} {...sound} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
32
src/hooks/use-sound.ts
Normal file
32
src/hooks/use-sound.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { useMemo, useEffect } from 'react';
|
||||
|
||||
import { useSSR } from './use-ssr';
|
||||
|
||||
export function useSound(
|
||||
src: string,
|
||||
options: { volume?: number; loop?: boolean } = {},
|
||||
): HTMLAudioElement | null {
|
||||
const { isBrowser } = useSSR();
|
||||
const sound = useMemo<HTMLAudioElement | null>(() => {
|
||||
let sound: HTMLAudioElement | null = null;
|
||||
|
||||
if (isBrowser) {
|
||||
sound = new Audio(src);
|
||||
sound.preload = 'none';
|
||||
}
|
||||
|
||||
return sound;
|
||||
}, [src, isBrowser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sound)
|
||||
sound.loop = typeof options.loop === 'boolean' ? options.loop : false;
|
||||
}, [sound, options.loop]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sound)
|
||||
sound.volume = typeof options.volume === 'number' ? options.volume : 0.5;
|
||||
}, [sound, options.volume]);
|
||||
|
||||
return sound;
|
||||
}
|
||||
11
src/hooks/use-ssr.ts
Normal file
11
src/hooks/use-ssr.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export function useSSR() {
|
||||
const isDOM =
|
||||
typeof window !== 'undefined' &&
|
||||
window.document &&
|
||||
window.document.documentElement;
|
||||
|
||||
return {
|
||||
isBrowser: isDOM,
|
||||
isServer: !isDOM,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue