diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index d8b888cd..9d51c208 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -4,3 +4,5 @@ export { default as ZodJSONCoder } from "./ZodJSONCoder" export { default as listFromCommaSeparatedString } from "./listFromCommaSeparatedString" export { default as env } from "./env" export { default as getBaseFilename } from "./getBaseFilename" +export { default as isMac } from "./isMac" +export { default as useKeyboardShortcut } from "./useKeyboardShortcut" diff --git a/src/common/utils/isMac.ts b/src/common/utils/isMac.ts new file mode 100644 index 00000000..4864bfa5 --- /dev/null +++ b/src/common/utils/isMac.ts @@ -0,0 +1,5 @@ +const isMac = () => { + return window.navigator.userAgent.toLowerCase().includes("mac") +} + +export default isMac \ No newline at end of file diff --git a/src/common/utils/useKeyboardShortcut.ts b/src/common/utils/useKeyboardShortcut.ts new file mode 100644 index 00000000..afc377f2 --- /dev/null +++ b/src/common/utils/useKeyboardShortcut.ts @@ -0,0 +1,19 @@ +"use client" + +import { useEffect } from "react" + +const useKeyboardShortcut = ( + handleKeyDown: (event: KeyboardEvent) => void, + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + dependencies: any[] +) => { + useEffect(() => { + window.addEventListener("keydown", handleKeyDown) + return () => { + window.removeEventListener("keydown", handleKeyDown) + } + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [handleKeyDown, ...dependencies]) +} + +export default useKeyboardShortcut \ No newline at end of file diff --git a/src/features/sidebar/view/base/SecondaryHeader.tsx b/src/features/sidebar/view/base/SecondaryHeader.tsx index a906f589..32048015 100644 --- a/src/features/sidebar/view/base/SecondaryHeader.tsx +++ b/src/features/sidebar/view/base/SecondaryHeader.tsx @@ -1,9 +1,10 @@ import { ReactNode } from "react" import { SxProps } from "@mui/system" -import { Box, Divider, IconButton } from "@mui/material" +import { Box, Divider, IconButton, Tooltip } from "@mui/material" import { useTheme } from "@mui/material/styles" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faBars, faChevronLeft } from "@fortawesome/free-solid-svg-icons" +import { isMac, useKeyboardShortcut } from "@/common" export default function SecondaryHeader({ showOpenSidebar, @@ -20,6 +21,18 @@ export default function SecondaryHeader({ children?: ReactNode sx?: SxProps }) { + useKeyboardShortcut(event => { + const isActionKey = isMac() ? event.metaKey : event.ctrlKey + if (isActionKey && event.key === ".") { + event.preventDefault() + if (showOpenSidebar) { + onToggleSidebarOpen(true) + } else if (showCloseSidebar) { + onToggleSidebarOpen(false) + } + } + }, [showOpenSidebar, showCloseSidebar, onToggleSidebarOpen]) + const openCloseShortcutString = isMac() ? " (⌘ + .)" : "(^ + .)" const theme = useTheme() return ( {showOpenSidebar && - onToggleSidebarOpen(true)} - edge="start" - > - - + + onToggleSidebarOpen(true)} + edge="start" + > + + + } {showCloseSidebar && - onToggleSidebarOpen(false)} - edge="start" - > - - + + onToggleSidebarOpen(false)} + edge="start" + > + + + } {trailingItem}