diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx
index 883fce49a..1d7f8aed8 100644
--- a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx
+++ b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx
@@ -23,6 +23,7 @@ import { useRequiredBoard } from "@homarr/boards/context";
import { useEditMode } from "@homarr/boards/edit-mode";
import { revalidatePathActionAsync } from "@homarr/common/client";
import { env } from "@homarr/common/env";
+import { hotkeys } from "@homarr/definitions";
import { useConfirmModal, useModalAction } from "@homarr/modals";
import { AppSelectModal } from "@homarr/modals-collection";
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
@@ -165,7 +166,7 @@ const EditModeMenu = () => {
open();
}, [board, isEditMode, saveBoard, open]);
- useHotkeys([["mod+e", toggle]]);
+ useHotkeys([[hotkeys.toggleBoardEdit, toggle]]);
usePreventLeaveWithDirty(isEditMode);
return (
diff --git a/apps/nextjs/src/app/[locale]/manage/about/page.tsx b/apps/nextjs/src/app/[locale]/manage/about/page.tsx
index ece275534..8e336449d 100644
--- a/apps/nextjs/src/app/[locale]/manage/about/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/about/page.tsx
@@ -11,14 +11,23 @@ import {
Center,
Flex,
Group,
+ Kbd,
List,
ListItem,
Stack,
+ Table,
+ TableTbody,
+ TableTd,
+ TableTh,
+ TableThead,
+ TableTr,
Text,
Title,
} from "@mantine/core";
-import { IconLanguage, IconLibrary, IconUsers } from "@tabler/icons-react";
+import { IconKeyboard, IconLanguage, IconLibrary, IconUsers } from "@tabler/icons-react";
+import { capitalize, objectEntries } from "@homarr/common";
+import { hotkeys } from "@homarr/definitions";
import { getScopedI18n } from "@homarr/translation/server";
import { homarrLogoPath } from "~/components/layout/logo/homarr-logo";
@@ -149,6 +158,45 @@ export default async function AboutPage() {
+
+ }>
+
+ {t("accordion.hotkeys.title")}
+
+ {t("accordion.hotkeys.subtitle")}
+
+
+
+
+
+
+
+ {t("accordion.hotkeys.field.shortcut")}
+ {t("accordion.hotkeys.field.action")}
+
+
+
+ {objectEntries(hotkeys).map(([key, shortcut]) => (
+
+
+
+ {shortcut
+ .split("+")
+ .map((key) => capitalize(key.trim()))
+ .join(" + ")}
+
+
+ {t(`accordion.hotkeys.action.${key}`)}
+
+ ))}
+
+
+
+
+ {t("accordion.hotkeys.note")}
+
+
+
);
diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx
index b0f9c6a10..9b3e3647a 100644
--- a/apps/nextjs/src/components/user-avatar-menu.tsx
+++ b/apps/nextjs/src/components/user-avatar-menu.tsx
@@ -19,6 +19,7 @@ import {
import type { RouterOutputs } from "@homarr/api";
import { signOut, useSession } from "@homarr/auth/client";
+import { hotkeys } from "@homarr/definitions";
import { createModal, useModalAction } from "@homarr/modals";
import { useScopedI18n } from "@homarr/translation/client";
@@ -34,7 +35,7 @@ interface UserAvatarMenuProps {
export const UserAvatarMenu = ({ children, availableUpdatesPromise }: UserAvatarMenuProps) => {
const t = useScopedI18n("common.userAvatar.menu");
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
- useHotkeys([["mod+J", toggleColorScheme]]);
+ useHotkeys([[hotkeys.toggleColorScheme, toggleColorScheme]]);
const ColorSchemeIcon = colorScheme === "dark" ? IconSun : IconMoon;
diff --git a/packages/definitions/src/hotkeys.ts b/packages/definitions/src/hotkeys.ts
new file mode 100644
index 000000000..b3a8cab42
--- /dev/null
+++ b/packages/definitions/src/hotkeys.ts
@@ -0,0 +1,6 @@
+export const hotkeys = {
+ toggleBoardEdit: "mod+e",
+ toggleColorScheme: "mod+j",
+ saveNotebook: "mod+s",
+ openSpotlight: "mod+k",
+};
diff --git a/packages/definitions/src/index.ts b/packages/definitions/src/index.ts
index 22ca76b84..3eb639ba6 100644
--- a/packages/definitions/src/index.ts
+++ b/packages/definitions/src/index.ts
@@ -13,3 +13,4 @@ export * from "./cookie";
export * from "./search-engine";
export * from "./onboarding";
export * from "./emptysuperjson";
+export * from "./hotkeys";
diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx
index 1f4158076..c99a76973 100644
--- a/packages/spotlight/src/components/spotlight.tsx
+++ b/packages/spotlight/src/components/spotlight.tsx
@@ -6,6 +6,7 @@ import { ActionIcon, Center, Group, Kbd } from "@mantine/core";
import { Spotlight as MantineSpotlight } from "@mantine/spotlight";
import { IconQuestionMark, IconSearch, IconX } from "@tabler/icons-react";
+import { hotkeys } from "@homarr/definitions";
import type { TranslationObject } from "@homarr/translation";
import { useI18n } from "@homarr/translation/client";
@@ -49,6 +50,7 @@ const SpotlightWithActiveMode = ({ modeState, activeMode }: SpotlightWithActiveM
return (
{
setMode(defaultMode);
diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json
index 0fad66d35..043cf8af3 100644
--- a/packages/translation/src/lang/en.json
+++ b/packages/translation/src/lang/en.json
@@ -3446,6 +3446,21 @@
"libraries": {
"title": "Libraries",
"subtitle": "{count} used in the Code of Homarr"
+ },
+ "hotkeys": {
+ "title": "Hotkeys",
+ "subtitle": "Keyboard shortcuts to enhance your workflow",
+ "field": {
+ "shortcut": "Shortcut",
+ "action": "Action"
+ },
+ "action": {
+ "toggleBoardEdit": "Toggle board edit mode",
+ "toggleColorScheme": "Toggle light/dark mode",
+ "saveNotebook": "Save notebook (only inside notebook widget)",
+ "openSpotlight": "Open search"
+ },
+ "note": "Tip: Mod refers to both Ctrl key and ⌘ key on macOS"
}
}
}
diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx
index af8062945..09bad2b5f 100644
--- a/packages/widgets/src/notebook/notebook.tsx
+++ b/packages/widgets/src/notebook/notebook.tsx
@@ -72,6 +72,7 @@ import "./notebook.css";
import { useSession } from "@homarr/auth/client";
import { constructBoardPermissions } from "@homarr/auth/shared";
import { useRequiredBoard } from "@homarr/boards/context";
+import { hotkeys } from "@homarr/definitions";
import { useConfirmModal } from "@homarr/modals";
const iconProps = {
@@ -266,7 +267,7 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
p={0}
mt={0}
h="100%"
- onKeyDown={isEditing ? getHotkeyHandler([["mod+s", handleEditToggle]]) : undefined}
+ onKeyDown={isEditing ? getHotkeyHandler([[hotkeys.saveNotebook, handleEditToggle]]) : undefined}
editor={editor}
styles={(theme) => ({
root: {