From aaccbee3d7dd1d4469ee26cea14df7132e8e9e0d Mon Sep 17 00:00:00 2001 From: MAZE Date: Tue, 28 Nov 2023 14:23:08 +0330 Subject: [PATCH] feat: add loading state for sounds --- src/components/sound/sound.module.css | 18 ++++++++++++++++++ src/components/sound/sound.tsx | 11 ++++++++++- src/hooks/use-sound.ts | 26 +++++++++++++++++++++----- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/components/sound/sound.module.css b/src/components/sound/sound.module.css index 3d0e2db..5073802 100644 --- a/src/components/sound/sound.module.css +++ b/src/components/sound/sound.module.css @@ -77,6 +77,14 @@ & .icon { color: #34d399; + + & .spinner { + animation-duration: 1s; + animation-iteration-count: infinite; + animation-name: spinner; + animation-timing-function: linear; + line-height: 0; + } } } @@ -89,3 +97,13 @@ line-height: 1.6; } } + +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/sound/sound.tsx b/src/components/sound/sound.tsx index 93742bc..92d441b 100644 --- a/src/components/sound/sound.tsx +++ b/src/components/sound/sound.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect } from 'react'; +import { ImSpinner9 } from 'react-icons/im/index'; import { Range } from './range'; import { Favorite } from './favorite'; @@ -78,7 +79,15 @@ export function Sound({ onKeyDown={toggle} > -
{icon}
+
+ {sound.isLoading ? ( + + + + ) : ( + icon + )} +

{label}

diff --git a/src/hooks/use-sound.ts b/src/hooks/use-sound.ts index dae8f39..3221853 100644 --- a/src/hooks/use-sound.ts +++ b/src/hooks/use-sound.ts @@ -1,4 +1,4 @@ -import { useMemo, useEffect, useCallback } from 'react'; +import { useMemo, useEffect, useCallback, useState } from 'react'; import { Howl } from 'howler'; import { useSSR } from './use-ssr'; @@ -7,12 +7,21 @@ export function useSound( src: string, options: { loop?: boolean; volume?: number } = {}, ) { + const [hasLoaded, setHasLoaded] = useState(false); + const [isLoading, setIsLoading] = useState(false); const { isBrowser } = useSSR(); const sound = useMemo(() => { let sound: Howl | null = null; if (isBrowser) { - sound = new Howl({ preload: false, src: src }); + sound = new Howl({ + onload: () => { + setIsLoading(false); + setHasLoaded(true); + }, + preload: false, + src: src, + }); } return sound; @@ -31,10 +40,14 @@ export function useSound( const play = useCallback(() => { if (sound) { - sound.load(); + if (!hasLoaded) { + setIsLoading(true); + sound.load(); + } + sound.play(); } - }, [sound]); + }, [sound, hasLoaded]); const stop = useCallback(() => { if (sound) sound.stop(); @@ -44,7 +57,10 @@ export function useSound( if (sound) sound.pause(); }, [sound]); - const control = useMemo(() => ({ pause, play, stop }), [play, stop, pause]); + const control = useMemo( + () => ({ isLoading, pause, play, stop }), + [play, stop, pause, isLoading], + ); return control; }