diff --git a/app/renderer/App.tsx b/app/renderer/App.tsx index fe543a7..c0c6e90 100644 --- a/app/renderer/App.tsx +++ b/app/renderer/App.tsx @@ -5,7 +5,7 @@ import { SidebarPane, PreviewPane, MainPane, Modals } from './panes'; import theme from './theme/theme'; import GlobalStyles from './theme/globalStyles'; import { WinControls } from './controls'; -import { useOpenProject } from './hooks'; +import { useOpenProject, useProjectHotkeys } from './hooks'; const AppContainer = styled.div` display: flex; @@ -19,6 +19,7 @@ const AppContainer = styled.div` const App = () => { useOpenProject(); + useProjectHotkeys(); return ( {window.windowApi.os() === 'win32' && } diff --git a/app/renderer/components/MoreOptionsSidebarMenu.tsx b/app/renderer/components/MoreOptionsSidebarMenu.tsx index 22ae7bc..756f002 100644 --- a/app/renderer/components/MoreOptionsSidebarMenu.tsx +++ b/app/renderer/components/MoreOptionsSidebarMenu.tsx @@ -17,6 +17,7 @@ import { } from '../icons'; import useStore from '../store/useStore'; import { saveProject } from '../utils/projectUtils'; +import { useCommandKeyString } from '../hooks'; const StyledMenuDivider = styled.div` height: 2px; @@ -29,6 +30,7 @@ const MoreOptionsSidebarMenu = () => { const theme = useTheme(); const [showMenu, setShowMenu] = useState(false); const buttonRef = useRef(null); + const commandKeyString = useCommandKeyString(); const isProjectOpen = useStore((state) => state.isProjectOpen); const activeSectionId = useStore((state) => state.activeSectionId); const previewEnabled = useStore((state) => state.previewEnabled); @@ -75,7 +77,7 @@ const MoreOptionsSidebarMenu = () => { } - rightElement={⌘N} + rightElement={{commandKeyString}N} label="New Book" onClick={() => { setShowMenu(false); @@ -85,7 +87,7 @@ const MoreOptionsSidebarMenu = () => { } - rightElement={⌘O} + rightElement={{commandKeyString}O} label="Open Book" onClick={() => { setShowMenu(false); @@ -97,7 +99,7 @@ const MoreOptionsSidebarMenu = () => { } - rightElement={⌘S} + rightElement={{commandKeyString}S} label="Save Book" onClick={() => { if (isProjectOpen) { @@ -109,7 +111,7 @@ const MoreOptionsSidebarMenu = () => { } - rightElement={⌘G} + rightElement={{commandKeyString}G} label="Generate Book" onClick={() => { setShowMenu(false); diff --git a/app/renderer/hooks/index.ts b/app/renderer/hooks/index.ts index 1a7ed79..cc3c67d 100644 --- a/app/renderer/hooks/index.ts +++ b/app/renderer/hooks/index.ts @@ -7,3 +7,5 @@ export { default as useOnWheel } from './useOnWheel'; export { default as useOnClickOutside } from './useOnClickOutside'; export { default as useIsHovering } from './useIsHovering'; export { default as useOnBookPdfGenerated } from './useOnBookPdfGenerated'; +export { default as useProjectHotkeys } from './useProjectHotkeys'; +export { default as useCommandKeyString } from './useCommandKeyString'; diff --git a/app/renderer/hooks/useCommandKeyString.ts b/app/renderer/hooks/useCommandKeyString.ts new file mode 100644 index 0000000..41252cf --- /dev/null +++ b/app/renderer/hooks/useCommandKeyString.ts @@ -0,0 +1,5 @@ +const useCommandKeyString = () => { + return window.windowApi.os() === 'darwin' ? '⌘' : 'Ctrl'; +}; + +export default useCommandKeyString; diff --git a/app/renderer/hooks/useProjectHotkeys.ts b/app/renderer/hooks/useProjectHotkeys.ts new file mode 100644 index 0000000..50ac767 --- /dev/null +++ b/app/renderer/hooks/useProjectHotkeys.ts @@ -0,0 +1,53 @@ +import { useEffect, useCallback, useMemo } from 'react'; +import useStore from '../store/useStore'; +import { saveProject } from '../utils/projectUtils'; + +const useProjectHotkeys = () => { + const { setGenerateBookModalOpen, setPreviewEnabled, setNewBookModalOpen } = + useStore.getState(); + const isProjectOpen = useStore((state) => state.isProjectOpen); + const isPreviewEnabled = useStore((state) => state.previewEnabled); + const activeSectionId = useStore((state) => state.activeSectionId); + + const shortcuts = useMemo( + () => ({ + o: window.projectApi.openProject, + g: () => { + if (isProjectOpen) { + setGenerateBookModalOpen(true); + } + }, + s: saveProject, + n: () => { + setNewBookModalOpen(true); + }, + p: () => { + if (isProjectOpen && activeSectionId !== '') { + setPreviewEnabled(!isPreviewEnabled); + } + }, + }), + [isProjectOpen, isPreviewEnabled, activeSectionId] + ); + const handleKeypress = useCallback( + (event: KeyboardEvent) => { + const commandKeyPressed = + window.windowApi.os() === 'darwin' ? event.metaKey : event.ctrlKey; + if (commandKeyPressed) { + if (event.key in shortcuts) { + shortcuts[event.key](); + } + } + }, + [isProjectOpen, isPreviewEnabled, activeSectionId] + ); + + useEffect(() => { + document.addEventListener('keydown', handleKeypress); + return () => { + document.removeEventListener('keydown', handleKeypress); + }; + }, [handleKeypress]); +}; + +export default useProjectHotkeys; diff --git a/app/renderer/panes/MainPane.tsx b/app/renderer/panes/MainPane.tsx index 108933a..2bd41e5 100644 --- a/app/renderer/panes/MainPane.tsx +++ b/app/renderer/panes/MainPane.tsx @@ -2,6 +2,7 @@ import styled from 'styled-components'; import Color from 'color'; import { Editor } from '../components'; import useStore from '../store/useStore'; +import { useCommandKeyString } from '../hooks'; const MainContent = styled.div` --top-padding: calc( @@ -70,6 +71,7 @@ const MainPane = () => { const isProjectOpen = useStore((state) => state.isProjectOpen); const activeSectionId = useStore((state) => state.activeSectionId); const activeSectionName = useStore((state) => state.activeSectionName); + const commandKeyString = useCommandKeyString(); return ( {isProjectOpen && activeSectionId !== '' ? ( @@ -86,11 +88,11 @@ const MainPane = () => { Open a project - ⌘O + {commandKeyString}O Start a new project - ⌘N + {commandKeyString}N diff --git a/release/app/package.json b/release/app/package.json index 954244a..4c773dc 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -1,6 +1,6 @@ { "name": "calamus", - "version": "0.5.7-pre-alpha", + "version": "0.5.8-pre-alpha", "description": "Write and Publish Books with Ease", "main": "./dist/main/main.js", "author": {