From 6ce766af47389e9e3e57226b956b8593a4af06d4 Mon Sep 17 00:00:00 2001 From: MAZE Date: Tue, 30 Apr 2024 17:47:49 +0330 Subject: [PATCH] feat: add basic fading effect --- .../modals/sleep-timer/sleep-timer.tsx | 5 +++- src/hooks/use-sound.ts | 28 +++++++++++++++++-- src/lib/event.ts | 20 +++++++++---- src/lib/modal.ts | 6 ++-- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/components/modals/sleep-timer/sleep-timer.tsx b/src/components/modals/sleep-timer/sleep-timer.tsx index 5eb3e0b..d590864 100644 --- a/src/components/modals/sleep-timer/sleep-timer.tsx +++ b/src/components/modals/sleep-timer/sleep-timer.tsx @@ -2,6 +2,7 @@ import { useEffect, useState, useRef, useMemo } from 'react'; import { Modal } from '@/components/modal'; import { Timer } from '@/components/timer'; +import { dispatch } from '@/lib/event'; import { useSoundStore } from '@/store'; import { cn } from '@/helpers/styles'; @@ -56,7 +57,9 @@ export function SleepTimerModal({ onClose, show }: SleepTimerModalProps) { useEffect(() => { if (timeLeft === 0) { setRunning(false); - pause(); + // pause(); + dispatch('fadeOut', { duration: 5000 }); + setTimeSpent(0); if (timerId.current) clearInterval(timerId.current); diff --git a/src/hooks/use-sound.ts b/src/hooks/use-sound.ts index eb1e501..ba8761e 100644 --- a/src/hooks/use-sound.ts +++ b/src/hooks/use-sound.ts @@ -1,13 +1,16 @@ import { useMemo, useEffect, useCallback, useState } from 'react'; import { Howl } from 'howler'; -import { useLoadingStore } from '@/store'; +import { useSoundStore, useLoadingStore } from '@/store'; +import { subscribe } from '@/lib/event'; import { useSSR } from './use-ssr'; export function useSound( src: string, options: { loop?: boolean; volume?: number } = {}, ) { + const pauseAll = useSoundStore(state => state.pause); + const [hasLoaded, setHasLoaded] = useState(false); const isLoading = useLoadingStore(state => state.loaders[src]); const setIsLoading = useLoadingStore(state => state.set); @@ -62,9 +65,28 @@ export function useSound( if (sound) sound.pause(); }, [sound]); + const fadeOut = useCallback( + (duration: number) => { + sound?.fade(sound.volume(), 0, duration); + + setTimeout(() => { + pauseAll(); + + sound?.volume(options.volume || 0.5); + }, duration); + }, + [options.volume, sound, pauseAll], + ); + + useEffect(() => { + const listener = (e: { duration: number }) => fadeOut(e.duration); + + return subscribe('fadeOut', listener); + }, [fadeOut]); + const control = useMemo( - () => ({ isLoading, pause, play, stop }), - [play, stop, pause, isLoading], + () => ({ fadeOut, isLoading, pause, play, stop }), + [play, stop, pause, isLoading, fadeOut], ); return control; diff --git a/src/lib/event.ts b/src/lib/event.ts index 0243bcb..8580ac8 100644 --- a/src/lib/event.ts +++ b/src/lib/event.ts @@ -1,13 +1,23 @@ -export function dispatch(eventName: string) { - const event = new Event(eventName); +export function dispatch(eventName: string, detail?: T) { + const event = new CustomEvent(eventName, { detail }); document.dispatchEvent(event); } -export function subscribe(eventName: string, listener: () => void) { - document.addEventListener(eventName, listener); +export function subscribe(eventName: string, listener: (e: T) => void) { + const handler = (event: Event) => { + if ('detail' in event) { + const payload = event.detail as T; + + listener(payload); + } + }; + + document.addEventListener(eventName, handler); + + return () => unsubscribe(eventName, handler); } -export function unsubscribe(eventName: string, listener: () => void) { +export function unsubscribe(eventName: string, listener: (e: Event) => void) { document.removeEventListener(eventName, listener); } diff --git a/src/lib/modal.ts b/src/lib/modal.ts index 1d13e86..0931cfc 100644 --- a/src/lib/modal.ts +++ b/src/lib/modal.ts @@ -1,11 +1,11 @@ -import { dispatch, subscribe, unsubscribe } from './event'; +import { dispatch, subscribe } from './event'; export function closeModals() { dispatch('closeModals'); } export function onCloseModals(listener: () => void) { - subscribe('closeModals', listener); + const unsubscribe = subscribe('closeModals', listener); - return () => unsubscribe('closeModals', listener); + return unsubscribe; }