diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index cc098f68a..f3cb28abe 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -234,35 +234,6 @@
"untitledNote": "Untitled",
"placeholder": "← Start by entering a title here\n===\nVisit {{host}}features if you don't know what to do.\nHappy hacking :)",
"infoToc": "Structure your note with headings to see a table-of-contents here.",
- "help": {
- "shortcuts": {
- "title": "Shortcuts",
- "bold": "Make selection bold",
- "italic": "Make selection italic",
- "underline": "Underline selection",
- "strikethrough": "Strike selection through",
- "mark": "Mark selection",
- "link": "Add link around selection",
- "view": "Show only View",
- "both": "Show View and Edit",
- "edit": "Show only Edit"
- },
- "links": {
- "title": "Links"
- },
- "contacts": {
- "title": "Contacts",
- "community": "Join the community",
- "meetUsOn": "Meet us on {{service}}",
- "helpTranslating": "Help us translating",
- "reportIssue": "Report an issue"
- },
- "documents": {
- "title": "Documents",
- "yamlMetadata": "YAML Metadata",
- "slideExample": "Slide Example"
- }
- },
"onlineStatus": {
"online": "Online",
"you": "(You)"
@@ -513,6 +484,15 @@
"editNote": "Edit this note"
}
},
+ "appbar": {
+ "help": {
+ "help": {
+ "header": "Help",
+ "shortcuts": "Shortcuts",
+ "cheatsheet": "Cheatsheet"
+ }
+ }
+ },
"common": {
"yes": "Yes",
"no": "No",
@@ -643,6 +623,24 @@
}
}
},
+ "shortcuts": {
+ "title": "Shortcuts",
+ "editor": {
+ "header": "Editor",
+ "bold": "Make selection bold",
+ "italic": "Make selection italic",
+ "underline": "Underline selection",
+ "strikethrough": "Strike selection through",
+ "mark": "Mark selection",
+ "link": "Add link around selection"
+ },
+ "viewMode": {
+ "header": "View Mode",
+ "view": "Show only View",
+ "both": "Show View and Edit",
+ "edit": "Show only Edit"
+ }
+ },
"cheatsheet": {
"button": "Open Cheatsheet",
"search": "Search for Cheatsheets",
diff --git a/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx b/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx
index 5fd4ecacf..2c00ee0ee 100644
--- a/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx
+++ b/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -8,13 +8,13 @@ import { useTranslatedText } from '../../../../hooks/common/use-translated-text'
import { useOutlineButtonVariant } from '../../../../hooks/dark-mode/use-outline-button-variant'
import { cypressId } from '../../../../utils/cypress-attribute'
import { IconButton } from '../../../common/icon-button/icon-button'
-import { HelpModal } from './help-modal'
+import { ShortcutsModal } from '../../../global-dialogs/shortcuts-modal/shortcuts-modal'
import React, { Fragment } from 'react'
import { QuestionCircle as IconQuestionCircle } from 'react-bootstrap-icons'
import { Trans } from 'react-i18next'
/**
- * Renders the button to open the {@link HelpModal}.
+ * Renders the button to open the shortcuts modal.
*/
export const HelpButton: React.FC = () => {
const [modalVisibility, showModal, closeModal] = useBooleanState()
@@ -33,7 +33,7 @@ export const HelpButton: React.FC = () => {
onClick={showModal}>
-
+
)
}
diff --git a/frontend/src/components/editor-page/app-bar/help-button/help-modal.tsx b/frontend/src/components/editor-page/app-bar/help-button/help-modal.tsx
deleted file mode 100644
index 76b401ee2..000000000
--- a/frontend/src/components/editor-page/app-bar/help-button/help-modal.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
-import { CommonModal } from '../../../common/modals/common-modal'
-import { LinksTabContent } from './links-tab-content'
-import { ShortcutTabContent } from './shortcuts-tab-content'
-import React, { useMemo, useState } from 'react'
-import { Button, Modal } from 'react-bootstrap'
-import { QuestionCircle as IconQuestionCircle } from 'react-bootstrap-icons'
-import { Trans, useTranslation } from 'react-i18next'
-
-export enum HelpTabStatus {
- Shortcuts = 'shortcuts.title',
- Links = 'links.title'
-}
-
-/**
- * Renders the help modal.
- * This modal shows the user the markdown cheatsheet, shortcuts and different links with further help.
- *
- * @see CheatsheetTabContent
- * @see ShortcutTabContent
- * @see LinksTabContent
- *
- * @param show If the modal should be shown
- * @param onHide A callback when the modal should be closed again
- */
-export const HelpModal: React.FC = ({ show, onHide }) => {
- const [tab, setTab] = useState(HelpTabStatus.Shortcuts)
- const { t } = useTranslation()
-
- const tabContent = useMemo(() => {
- switch (tab) {
- case HelpTabStatus.Shortcuts:
- return
- case HelpTabStatus.Links:
- return
- }
- }, [tab])
-
- const modalTitle = useMemo(() => t('editor.documentBar.help') + ' - ' + t(`editor.help.${tab}`), [t, tab])
-
- return (
-
-
-
- {tabContent}
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/help-button/links-tab-content.tsx b/frontend/src/components/editor-page/app-bar/help-button/links-tab-content.tsx
deleted file mode 100644
index 136e3a07d..000000000
--- a/frontend/src/components/editor-page/app-bar/help-button/links-tab-content.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import links from '../../../../links.json'
-import { IconMatrixOrg } from '../../../common/icons/additional/icon-matrix-org'
-import { TranslatedExternalLink } from '../../../common/links/translated-external-link'
-import { TranslatedInternalLink } from '../../../common/links/translated-internal-link'
-import React from 'react'
-import { Col, Row } from 'react-bootstrap'
-import { Dot as IconDot, Flag as IconFlag, PeopleFill as IconPeopleFill, Tag as IconTag } from 'react-bootstrap-icons'
-import { Trans, useTranslation } from 'react-i18next'
-
-/**
- * Renders a bunch of links, where further help can be requested.
- */
-export const LinksTabContent: React.FC = () => {
- useTranslation()
-
- return (
-
-
-
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/help-button/shortcuts-tab-content.tsx b/frontend/src/components/editor-page/app-bar/help-button/shortcuts-tab-content.tsx
deleted file mode 100644
index 4d259dda1..000000000
--- a/frontend/src/components/editor-page/app-bar/help-button/shortcuts-tab-content.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { isMac } from '../../utils'
-import React, { Fragment, useMemo } from 'react'
-import { Card, ListGroup, Row } from 'react-bootstrap'
-import { Trans } from 'react-i18next'
-
-/**
- * Renders a list of shortcuts usable in HedgeDoc.
- */
-export const ShortcutTabContent: React.FC = () => {
- const modifierKey = useMemo(() => (isMac() ? ⌘ : Ctrl), [])
- const altKey = useMemo(() => (isMac() ? ⌥ : Alt), [])
-
- const shortcutMap: { [category: string]: { [functionName: string]: JSX.Element[] } } = {
- 'View Mode': {
- 'editor.help.shortcuts.view': [Ctrl, <> + >, altKey, <> + >, V],
- 'editor.help.shortcuts.both': [Ctrl, <> + >, altKey, <> + >, B],
- 'editor.help.shortcuts.edit': [Ctrl, <> + >, altKey, <> + >, E]
- },
- Editor: {
- 'editor.help.shortcuts.bold': [modifierKey, <> + >, B],
- 'editor.help.shortcuts.italic': [modifierKey, <> + >, I],
- 'editor.help.shortcuts.underline': [modifierKey, <> + >, U],
- 'editor.help.shortcuts.strikethrough': [modifierKey, <> + >, D],
- 'editor.help.shortcuts.mark': [modifierKey, <> + >, M],
- 'editor.help.shortcuts.link': [modifierKey, <> + >, K]
- }
- }
- return (
-
- {Object.keys(shortcutMap).map((category) => {
- return (
-
- {category}
-
- {Object.entries(shortcutMap[category]).map(([functionName, shortcuts]) => {
- return (
-
-
-
-
-
- {shortcuts.map((shortcut, shortcutIndex) => (
- {shortcut}
- ))}
-
-
- )
- })}
-
-
- )
- })}
-
- )
-}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/alt-key.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/alt-key.tsx
new file mode 100644
index 000000000..1a107b45d
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/alt-key.tsx
@@ -0,0 +1,14 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { isMac } from '../../editor-page/utils'
+import React from 'react'
+
+/**
+ * Renders a keyboard alt/option key hint depending on if the browser is running on macOS or not.
+ */
+export const AltKey: React.FC = () => {
+ return isMac() ? ⌥ : Alt
+}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/category-card.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/category-card.tsx
new file mode 100644
index 000000000..58f4a330f
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/category-card.tsx
@@ -0,0 +1,32 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import type { PropsWithChildren } from 'react'
+import React from 'react'
+import { Card, ListGroup } from 'react-bootstrap'
+import { Trans, useTranslation } from 'react-i18next'
+
+interface CategoryProps extends PropsWithChildren {
+ headerI18nKey: string
+}
+
+/**
+ * Renders a group of shortcut lines
+ *
+ * @param headerI18nKey The i18n key of the header
+ * @param children The lines to include
+ */
+export const CategoryCard: React.FC = ({ headerI18nKey, children }) => {
+ useTranslation()
+
+ return (
+
+
+
+
+ {children}
+
+ )
+}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/modifier-key.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/modifier-key.tsx
new file mode 100644
index 000000000..3cb58f781
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/modifier-key.tsx
@@ -0,0 +1,14 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { isMac } from '../../editor-page/utils'
+import React from 'react'
+
+/**
+ * Renders a keyboard control/command key hint depending on if the browser is running on macOS or not.
+ */
+export const ModifierKey: React.FC = () => {
+ return isMac() ? ⌘ : Ctrl
+}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/shortcut-line.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/shortcut-line.tsx
new file mode 100644
index 000000000..3ae02c853
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/shortcut-line.tsx
@@ -0,0 +1,56 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { ShowIf } from '../../common/show-if/show-if'
+import { AltKey } from './alt-key'
+import { ModifierKey } from './modifier-key'
+import React from 'react'
+import { ListGroup } from 'react-bootstrap'
+import { Trans, useTranslation } from 'react-i18next'
+
+interface ShortcutLineProps {
+ functionNameI18nKey: string
+ showModifierKey: boolean
+ showAltKey: boolean
+ functionKeyCode: string
+}
+
+/**
+ * Renders one shortcut hint for the modal
+ *
+ * @param functionNameI18nKey The i18n key of the function name that is associated to the shortcut
+ * @param showAltKey Defines if the shortcut requires the alt/option key
+ * @param showModifierKey Defines if the shortcut requires the control/command key
+ * @param functionKeyCode The actual key of the shortcut
+ */
+export const ShortcutLine: React.FC = ({
+ functionNameI18nKey,
+ showAltKey,
+ showModifierKey,
+ functionKeyCode
+}) => {
+ useTranslation()
+
+ return (
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ {functionKeyCode.toUpperCase()}
+
+
+ )
+}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-content.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-content.tsx
new file mode 100644
index 000000000..14a1250b0
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-content.tsx
@@ -0,0 +1,78 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { CategoryCard } from './category-card'
+import { ShortcutLine } from './shortcut-line'
+import React from 'react'
+import { Container } from 'react-bootstrap'
+
+/**
+ * Renders a list of shortcuts usable in HedgeDoc.
+ */
+export const ShortcutsContent: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-modal.tsx b/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-modal.tsx
new file mode 100644
index 000000000..000c7135a
--- /dev/null
+++ b/frontend/src/components/global-dialogs/shortcuts-modal/shortcuts-modal.tsx
@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import { useTranslatedText } from '../../../hooks/common/use-translated-text'
+import type { ModalVisibilityProps } from '../../common/modals/common-modal'
+import { CommonModal } from '../../common/modals/common-modal'
+import { ShortcutsContent } from './shortcuts-content'
+import React from 'react'
+import { Modal } from 'react-bootstrap'
+import { QuestionCircle as IconQuestionCircle } from 'react-bootstrap-icons'
+
+/**
+ * Renders the keyboard shortcuts overview modal.
+ * @param show True when the modal should be shown
+ * @param onHide Callback when the modal should be hidden
+ */
+export const ShortcutsModal: React.FC = ({ show, onHide }) => {
+ const title = useTranslatedText('shortcuts.title')
+
+ return (
+
+
+
+
+
+ )
+}