From 63e843e2d6712a0dc0f744e00b343f036ba12dfe Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Fri, 25 Apr 2025 20:04:12 -0500 Subject: [PATCH] Move key commands to , fix auto-focus tooltip issue --- app/layout.tsx | 2 -- src/app/AppKeyListener.tsx | 28 --------------------- src/app/AppViewSwitcher.tsx | 43 +++++++++++++++++++++----------- src/components/Modal.tsx | 5 +++- src/components/SwitcherItem.tsx | 7 ++++-- src/components/more/MoreMenu.tsx | 1 + src/photo/PhotoEscapeHandler.tsx | 4 +-- src/utility/useEscapeHandler.ts | 6 ++--- 8 files changed, 42 insertions(+), 54 deletions(-) delete mode 100644 src/app/AppKeyListener.tsx diff --git a/app/layout.tsx b/app/layout.tsx index 2a423ce1..be93992a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -24,7 +24,6 @@ import AdminUploadPanel from '@/admin/upload/AdminUploadPanel'; import { revalidatePath } from 'next/cache'; import RecipeModal from '@/recipe/RecipeModal'; import ThemeColors from '@/app/ThemeColors'; -import AppKeyListener from '@/app/AppKeyListener'; import '../tailwind.css'; @@ -115,7 +114,6 @@ export default function RootLayout({ - diff --git a/src/app/AppKeyListener.tsx b/src/app/AppKeyListener.tsx deleted file mode 100644 index 178dac73..00000000 --- a/src/app/AppKeyListener.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client'; - -import useKeydownHandler from '@/utility/useKeydownHandler'; -import { PATH_FEED_INFERRED, PATH_GRID_INFERRED } from './paths'; -import { useCallback } from 'react'; -import { useRouter, usePathname } from 'next/navigation'; - -const PATH_MAPS = { - G: PATH_GRID_INFERRED, - F: PATH_FEED_INFERRED, -}; - -export default function AppKeyListener() { - const pathname = usePathname(); - - const router = useRouter(); - - const onKeyDown = useCallback((e: KeyboardEvent) => { - const path = PATH_MAPS[e.key.toLocaleUpperCase() as keyof typeof PATH_MAPS]; - if (path && pathname !== path) { - router.push(path); - } - }, [router, pathname]); - - useKeydownHandler({ onKeyDown }); - - return null; -} diff --git a/src/app/AppViewSwitcher.tsx b/src/app/AppViewSwitcher.tsx index 58972cdb..5e3c5018 100644 --- a/src/app/AppViewSwitcher.tsx +++ b/src/app/AppViewSwitcher.tsx @@ -12,7 +12,9 @@ import { GRID_HOMEPAGE_ENABLED } from './config'; import AdminAppMenu from '@/admin/AdminAppMenu'; import Spinner from '@/components/Spinner'; import clsx from 'clsx/lite'; -import { useState, useRef, useEffect } from 'react'; +import { useCallback, useRef, useState } from 'react'; +import useKeydownHandler from '@/utility/useKeydownHandler'; +import { usePathname } from 'next/navigation'; export type SwitcherSelection = 'feed' | 'grid' | 'admin'; @@ -23,32 +25,39 @@ export default function AppViewSwitcher({ currentSelection?: SwitcherSelection className?: string }) { + const pathname = usePathname(); + const { isUserSignedIn, isUserSignedInEager, setIsCommandKOpen, } = useAppState(); - const hasAdminMenuOpenedOnce = useRef(false); - const [isAdminMenuOpen, setIsAdminMenuOpen] = useState(false); + const refHrefFeed = useRef(null); + const refHrefGrid = useRef(null); - useEffect(() => { - if (isAdminMenuOpen) { - hasAdminMenuOpenedOnce.current = true; - } else if (hasAdminMenuOpenedOnce.current) { - // Blur admin menu button to avoid tooltip on dismiss - setTimeout(() => { - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - }, 50); + const onKeyDown = useCallback((e: KeyboardEvent) => { + switch (e.key.toLocaleUpperCase()) { + case 'F': + if (pathname !== PATH_FEED_INFERRED) { refHrefFeed.current?.click(); } + break; + case 'G': + if (pathname !== PATH_GRID_INFERRED) { refHrefGrid.current?.click(); } + break; + case 'A': + if (isUserSignedIn) { setIsAdminMenuOpen(true); } + break; } - }, [isAdminMenuOpen]); + }, [pathname, isUserSignedIn]); + useKeydownHandler({ onKeyDown }); + + const [isAdminMenuOpen, setIsAdminMenuOpen] = useState(false); const renderItemFeed = } href={PATH_FEED_INFERRED} + hrefRef={refHrefFeed} active={currentSelection === 'feed'} tooltip={{ content: 'Feed', @@ -61,6 +70,7 @@ export default function AppViewSwitcher({ } href={PATH_GRID_INFERRED} + hrefRef={refHrefGrid} active={currentSelection === 'grid'} tooltip={{ content: 'Grid', @@ -93,7 +103,10 @@ export default function AppViewSwitcher({ isOpen={isAdminMenuOpen} setIsOpen={setIsAdminMenuOpen} />} - tooltip={{ content: !isAdminMenuOpen ? 'Admin Menu' : undefined }} + tooltip={{ + content: !isAdminMenuOpen ? 'Admin Menu' : undefined, + keyCommand: !isAdminMenuOpen ? 'A' : undefined, + }} noPadding />} diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index a93e82e8..190e33cd 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -61,7 +61,10 @@ export default function Modal({ }, }); - useEscapeHandler(onClose, true); + useEscapeHandler({ + onKeyDown: onClose, + ignoreShouldRespondToKeyboardCommands: true, + }); return ( className?: string onClick?: () => void active?: boolean @@ -57,6 +59,7 @@ export default function SwitcherItem({ const content = href ? {content} diff --git a/src/components/more/MoreMenu.tsx b/src/components/more/MoreMenu.tsx index 4cb4c4f9..17e56e05 100644 --- a/src/components/more/MoreMenu.tsx +++ b/src/components/more/MoreMenu.tsx @@ -75,6 +75,7 @@ export default function MoreMenu({ e.preventDefault()} align={align} sideOffset={sideOffset} className={clsx( diff --git a/src/photo/PhotoEscapeHandler.tsx b/src/photo/PhotoEscapeHandler.tsx index c52223af..89047a76 100644 --- a/src/photo/PhotoEscapeHandler.tsx +++ b/src/photo/PhotoEscapeHandler.tsx @@ -12,11 +12,11 @@ export default function PhotoEscapeHandler() { const escapePath = getEscapePath(pathname); - const escapeHandler = useCallback(() => { + const onKeyDown = useCallback(() => { if (escapePath) { router.push(escapePath, { scroll: false }); } }, [escapePath, router]); - useEscapeHandler(escapeHandler); + useEscapeHandler({ onKeyDown }); return null; } diff --git a/src/utility/useEscapeHandler.ts b/src/utility/useEscapeHandler.ts index 8eaf9ea3..fd37d3f3 100644 --- a/src/utility/useEscapeHandler.ts +++ b/src/utility/useEscapeHandler.ts @@ -1,12 +1,10 @@ import useKeydownHandler from '@/utility/useKeydownHandler'; export default function useEscapeHandler( - onKeyDown?: (e: KeyboardEvent) => void, - ignoreShouldRespondToKeyboardCommands?: boolean, + args: Omit[0], 'keys'>, ) { useKeydownHandler({ - onKeyDown, + ...args, keys: ['ESCAPE'], - ignoreShouldRespondToKeyboardCommands, }); }