diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx index 9d827cd..7c9581c 100644 --- a/src/components/menu/menu.tsx +++ b/src/components/menu/menu.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useMemo, useCallback } from 'react'; import { IoMenu, IoClose } from 'react-icons/io5/index'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -20,22 +20,52 @@ import { Notepad, Pomodoro } from '@/components/toolbox'; import { fade, mix, slideY } from '@/lib/motion'; import styles from './menu.module.css'; +import { useCloseListener } from '@/hooks/use-close-listener'; export function Menu() { const [isOpen, setIsOpen] = useState(false); - const [showPresets, setShowPresets] = useState(false); - const [showShareLink, setShowShareLink] = useState(false); - const [showNotepad, setShowNotepad] = useState(false); - const [showPomodoro, setShowPomodoro] = useState(false); + const initial = useMemo( + () => ({ + notepad: false, + pomodoro: false, + presets: false, + shareLink: false, + }), + [], + ); - const variants = mix(fade(), slideY()); + const [modals, setModals] = useState<{ + notepad: boolean; + pomodoro: boolean; + presets: boolean; + shareLink: boolean; + }>(initial); + + const close = useCallback((name: string) => { + setModals(prev => ({ ...prev, [name]: false })); + }, []); + + const closeAll = useCallback(() => setModals(initial), [initial]); + + const open = useCallback( + (name: string) => { + closeAll(); + setIsOpen(false); + setModals(prev => ({ ...prev, [name]: true })); + }, + [closeAll], + ); useHotkeys('shift+m', () => setIsOpen(prev => !prev)); - useHotkeys('shift+n', () => setShowNotepad(prev => !prev)); - useHotkeys('shift+p', () => setShowPomodoro(prev => !prev)); - useHotkeys('shift+alt+p', () => setShowPresets(prev => !prev)); - useHotkeys('shift+s', () => setShowShareLink(prev => !prev)); + useHotkeys('shift+n', () => open('notepad')); + useHotkeys('shift+p', () => open('pomodoro')); + useHotkeys('shift+alt+p', () => open('presets')); + useHotkeys('shift+s', () => open('shareLink')); + + useCloseListener(closeAll); + + const variants = mix(fade(), slideY()); return ( <> @@ -64,12 +94,12 @@ export function Menu() { initial="hidden" variants={variants} > - setShowPresets(true)} /> - setShowShareLink(true)} /> + open('presets')} /> + open('shareLink')} /> - setShowNotepad(true)} /> - setShowPomodoro(true)} /> + open('notepad')} /> + open('pomodoro')} /> @@ -82,12 +112,16 @@ export function Menu() { setShowShareLink(false)} + show={modals.shareLink} + onClose={() => close('shareLink')} + /> + close('presets')} /> + close('notepad')} /> + open('pomodoro')} + show={modals.pomodoro} + onClose={() => close('pomodoro')} /> - setShowPresets(false)} /> - setShowNotepad(false)} /> - setShowPomodoro(false)} /> ); } diff --git a/src/components/modal/modal.tsx b/src/components/modal/modal.tsx index c6113cc..2049620 100644 --- a/src/components/modal/modal.tsx +++ b/src/components/modal/modal.tsx @@ -40,7 +40,7 @@ export function Modal({ useEffect(() => { function keyListener(e: KeyboardEvent) { - if (e.key === 'escape') { + if (show && e.key === 'Escape') { onClose(); } } @@ -48,7 +48,7 @@ export function Modal({ document.addEventListener('keydown', keyListener); return () => document.removeEventListener('keydown', keyListener); - }, [onClose]); + }, [onClose, show]); return ( diff --git a/src/components/modals/shared/shared.tsx b/src/components/modals/shared/shared.tsx index f70cfa8..7dfb232 100644 --- a/src/components/modals/shared/shared.tsx +++ b/src/components/modals/shared/shared.tsx @@ -4,6 +4,7 @@ import { Modal } from '@/components/modal'; import { useSoundStore } from '@/store'; import { useSnackbar } from '@/contexts/snackbar'; +import { useCloseListener } from '@/hooks/use-close-listener'; import { cn } from '@/helpers/styles'; import { sounds } from '@/data/sounds'; @@ -77,6 +78,8 @@ export function SharedModal() { showSnackbar('Done! You can now play the new selection.'); }; + useCloseListener(() => setIsOpen(false)); + return ( setIsOpen(false)}>

New sound mix detected!

diff --git a/src/components/toolbox/pomodoro/pomodoro.tsx b/src/components/toolbox/pomodoro/pomodoro.tsx index aad94e5..072df5c 100644 --- a/src/components/toolbox/pomodoro/pomodoro.tsx +++ b/src/components/toolbox/pomodoro/pomodoro.tsx @@ -16,10 +16,11 @@ import styles from './pomodoro.module.css'; interface PomodoroProps { onClose: () => void; + open: () => void; show: boolean; } -export function Pomodoro({ onClose, show }: PomodoroProps) { +export function Pomodoro({ onClose, open, show }: PomodoroProps) { const [showSetting, setShowSetting] = useState(false); const [selectedTab, setSelectedTab] = useState('pomodoro'); @@ -125,7 +126,10 @@ export function Pomodoro({ onClose, show }: PomodoroProps) {