From 3b829fce07ed7adf11ca9993c33e33caab285763 Mon Sep 17 00:00:00 2001 From: MAZE Date: Sun, 13 Oct 2024 21:54:52 +0330 Subject: [PATCH] feat: add global volume --- src/components/sounds/sound/sound.tsx | 12 ++++++++--- src/components/toolbar/menu/menu.module.css | 18 ++++++++++++++++ src/components/toolbar/menu/menu.tsx | 23 +++++++++++++++++++++ src/stores/sound/index.ts | 5 ++++- src/stores/sound/sound.actions.ts | 7 +++++++ src/stores/sound/sound.state.ts | 2 ++ 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/components/sounds/sound/sound.tsx b/src/components/sounds/sound/sound.tsx index b7927bb..8ba190f 100644 --- a/src/components/sounds/sound/sound.tsx +++ b/src/components/sounds/sound/sound.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, forwardRef } from 'react'; +import { useCallback, useEffect, forwardRef, useMemo } from 'react'; import { ImSpinner9 } from 'react-icons/im/index'; import { Range } from './range'; @@ -31,13 +31,19 @@ export const Sound = forwardRef(function Sound( const selectSound = useSoundStore(state => state.select); const unselectSound = useSoundStore(state => state.unselect); const setVolume = useSoundStore(state => state.setVolume); - const volume = useSoundStore(state => state.sounds[id].volume); const isSelected = useSoundStore(state => state.sounds[id].isSelected); const locked = useSoundStore(state => state.locked); + const volume = useSoundStore(state => state.sounds[id].volume); + const globalVolume = useSoundStore(state => state.globalVolume); + const adjustedVolume = useMemo( + () => volume * globalVolume, + [volume, globalVolume], + ); + const isLoading = useLoadingStore(state => state.loaders[src]); - const sound = useSound(src, { loop: true, volume }); + const sound = useSound(src, { loop: true, volume: adjustedVolume }); useEffect(() => { if (locked) return; diff --git a/src/components/toolbar/menu/menu.module.css b/src/components/toolbar/menu/menu.module.css index 22802a5..6f1f399 100644 --- a/src/components/toolbar/menu/menu.module.css +++ b/src/components/toolbar/menu/menu.module.css @@ -40,3 +40,21 @@ border: 1px solid var(--color-neutral-300); border-radius: 8px; } + +.globalVolume { + width: 100%; + padding: 12px; + + & label { + display: block; + margin-bottom: 8px; + font-size: var(--font-sm); + font-weight: 500; + color: var(--color-foreground-subtle); + } + + & input { + width: 100%; + min-width: 0; + } +} diff --git a/src/components/toolbar/menu/menu.tsx b/src/components/toolbar/menu/menu.tsx index 5ce64ff..bafd25e 100644 --- a/src/components/toolbar/menu/menu.tsx +++ b/src/components/toolbar/menu/menu.tsx @@ -40,6 +40,8 @@ export function Menu() { const [isOpen, setIsOpen] = useState(false); const noSelected = useSoundStore(state => state.noSelected()); + const globalVolume = useSoundStore(state => state.globalVolume); + const setGlobalVolume = useSoundStore(state => state.setGlobalVolume); const initial = useMemo( () => ({ @@ -136,6 +138,27 @@ export function Menu() { open('shortcuts')} /> + + +
+ + + e.preventDefault()} + > + + setGlobalVolume(Number(e.target.value) / 100) + } + /> + +
diff --git a/src/stores/sound/index.ts b/src/stores/sound/index.ts index 99da050..915e937 100644 --- a/src/stores/sound/index.ts +++ b/src/stores/sound/index.ts @@ -19,7 +19,10 @@ export const useSoundStore = create()( persisted, ), name: 'moodist-sounds', - partialize: state => ({ sounds: state.sounds }), + partialize: state => ({ + globalVolume: state.globalVolume, + sounds: state.sounds, + }), skipHydration: true, storage: createJSONStorage(() => localStorage), version: 0, diff --git a/src/stores/sound/sound.actions.ts b/src/stores/sound/sound.actions.ts index 4f6a73c..58fb993 100644 --- a/src/stores/sound/sound.actions.ts +++ b/src/stores/sound/sound.actions.ts @@ -11,6 +11,7 @@ export interface SoundActions { play: () => void; restoreHistory: () => void; select: (id: string) => void; + setGlobalVolume: (volume: number) => void; setVolume: (id: string, volume: number) => void; shuffle: () => void; toggleFavorite: (id: string) => void; @@ -72,6 +73,12 @@ export const createActions: StateCreator< }); }, + setGlobalVolume(volume) { + set({ + globalVolume: volume, + }); + }, + setVolume(id, volume) { set({ sounds: { diff --git a/src/stores/sound/sound.state.ts b/src/stores/sound/sound.state.ts index d73fa68..3c20e64 100644 --- a/src/stores/sound/sound.state.ts +++ b/src/stores/sound/sound.state.ts @@ -6,6 +6,7 @@ import { sounds } from '@/data/sounds'; export interface SoundState { getFavorites: () => Array; + globalVolume: number; history: { [id: string]: { isFavorite: boolean; @@ -39,6 +40,7 @@ export const createState: StateCreator< return favorites; }, + globalVolume: 1, history: null, isPlaying: false, locked: false,