common: getGroupedKeybindings should return an array

this is so the groups are always ordered. It also makes it easier to iterate
over the groups.
This commit is contained in:
Abdullah Atta
2025-07-22 13:26:27 +05:00
parent c41dfa3185
commit 1abf51ae2b
4 changed files with 112 additions and 86 deletions

View File

@@ -41,24 +41,20 @@ export const KeyboardShortcutsDialog = DialogManager.register(
height: 650 height: 650
}} }}
> >
{Object.entries(groupedKeybindings).map(([group, shortcuts]) => { {groupedKeybindings.map((group) => {
if (
shortcuts.length === 0 ||
shortcuts.every((s) => s.keys.length === 0)
) {
return null;
}
return ( return (
<Flex key={group} sx={{ flexDirection: "column", mb: 2 }}> <Flex key={group.category} sx={{ flexDirection: "column" }}>
<Text sx={{ mt: 1, fontWeight: "bold" }}>{group}</Text> <Text
<hr variant="subtitle"
style={{ sx={{
width: "100%", borderBottom: "1px solid var(--border)",
background: "var(--background-secondary)" mb: 1,
pb: 1
}} }}
/> >
{shortcuts.map((shortcut) => { {group.category}
if (shortcut.keys.length === 0) return null; </Text>
{group.shortcuts.map((shortcut) => {
return ( return (
<Flex <Flex
key={shortcut.description} key={shortcut.description}

View File

@@ -5,31 +5,26 @@ description: Keyboard shortcuts for Notesnook
The following keyboard shortcuts will help you navigate Notesnook faster. The following keyboard shortcuts will help you navigate Notesnook faster.
### General
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
| New note | - | Ctrl N | ⌘ N |
### Navigation ### Navigation
| Description | Web | Windows/Linux | Mac | | Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab | | Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab | | Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
| New tab | - | Ctrl t | ⌘ t | | Command palette | Ctrl K | Ctrl K | ⌘ K |
| Close active tab | - | Ctrl w | ⌘ w | | Quick open | Ctrl P | Ctrl P | ⌘ P |
| Close all tabs | - | Ctrl ⇧ w | ⌘ ⇧ w | | New tab | - | Ctrl T | ⌘ T |
| Command palette | Ctrl k | Ctrl k | ⌘ k | | Close active tab | - | Ctrl W | ⌘ W |
| Quick open | Ctrl p | Ctrl p | ⌘ p | | Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
### Note
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| New note | - | Ctrl n | ⌘ n |
### General
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Search in notes list view if editor is not focused | Ctrl f | Ctrl f | ⌘ f |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
### Editor ### Editor
@@ -37,18 +32,18 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A | | Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B | | Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
| Toggle bold | Ctrl b | Ctrl b | ⌘ b | | Toggle bold | Ctrl B | Ctrl B | ⌘ B |
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 | | Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 | | Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
| Split list item | ↵ | ↵ | ↵ | | Split list item | ↵ | ↵ | ↵ |
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab | | Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down | | Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
| Toggle code | Ctrl e | Ctrl e | ⌘ e | | Toggle code | Ctrl E | Ctrl E | ⌘ E |
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C | | Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
| Insert date | Alt d | Alt d | ⌥ d | | Insert date | Alt D | Alt D | ⌥ D |
| Insert time | Alt t | Alt t | ⌥ t | | Insert time | Alt T | Alt T | ⌥ T |
| Insert date and time | Ctrl Alt d | Ctrl Alt d | ⌘ ⌥ d | | Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
| Insert date and time with timezone | Ctrl Alt z | Ctrl Alt z | ⌘ ⌥ z | | Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ | | Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] | | Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
| Insert paragraph | Ctrl ⇧ 0 | Ctrl ⇧ 0 | ⌘ ⇧ 0 | | Insert paragraph | Ctrl ⇧ 0 | Ctrl ⇧ 0 | ⌘ ⇧ 0 |
@@ -58,10 +53,10 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 | | Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 | | Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 | | Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
| Undo | Ctrl z | Ctrl z | ⌘ z | | Undo | Ctrl Z | Ctrl Z | ⌘ Z |
| Redo | Ctrl ⇧ z / Ctrl y | Ctrl ⇧ z / Ctrl y | ⌘ ⇧ z / ⌘ y | | Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I | | Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
| Toggle italic | Ctrl i | Ctrl i | ⌘ i | | Toggle italic | Ctrl I | Ctrl I | ⌘ I |
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ | | Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
| Insert internal link | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L | | Insert internal link | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Insert link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K | | Insert link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
@@ -78,4 +73,4 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J | | Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L | | Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R | | Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
| Underline | Ctrl u | Ctrl u | ⌘ u | | Underline | Ctrl U | Ctrl U | ⌘ U |

View File

@@ -1,5 +1,29 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { writeFileSync } from "fs"; import { writeFileSync } from "fs";
import { getGroupedKeybindings, formatKey, macify } from "@notesnook/common"; import {
getGroupedKeybindings,
formatKey,
macify,
CATEGORIES
} from "@notesnook/common";
console.log("Generating keyboard shortcuts documentation..."); console.log("Generating keyboard shortcuts documentation...");
@@ -34,42 +58,42 @@ function getGroupedTableKeybindingsMarkdown() {
const header = `| Description | Web | Windows/Linux | Mac | const header = `| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |`; | --- | --- | --- | --- |`;
return Object.keys({ ...webKeybindings, ...desktopKeybindings }) return CATEGORIES.map((category) => {
.map((category) => { const webShortcuts =
const webShortcuts = webKeybindings[category] || []; webKeybindings.find((g) => g.category === category)?.shortcuts || [];
const desktopShortcuts = desktopKeybindings[category] || []; const desktopShortcuts =
desktopKeybindings.find((g) => g.category === category)?.shortcuts || [];
const mergedShortcuts = {}; const mergedShortcuts = {};
webShortcuts.forEach(({ description, keys }) => { webShortcuts.forEach(({ description, keys }) => {
if (!mergedShortcuts[description]) { if (!mergedShortcuts[description]) {
mergedShortcuts[description] = {}; mergedShortcuts[description] = {};
} }
mergedShortcuts[description].web = keys; mergedShortcuts[description].web = keys;
}); });
desktopShortcuts.forEach(({ description, keys }) => { desktopShortcuts.forEach(({ description, keys }) => {
if (!mergedShortcuts[description]) { if (!mergedShortcuts[description]) {
mergedShortcuts[description] = {}; mergedShortcuts[description] = {};
} }
mergedShortcuts[description].desktop = keys; mergedShortcuts[description].desktop = keys;
}); });
const rows = Object.entries(mergedShortcuts) const rows = Object.entries(mergedShortcuts)
.map(([description, { web, desktop }]) => { .map(([description, { web, desktop }]) => {
const webKeys = web?.map((k) => formatKey(k)).join(" / ") || "-"; const webKeys = web?.map((k) => formatKey(k)).join(" / ") || "-";
const windowsLinuxKeys = const windowsLinuxKeys =
desktop?.map((k) => formatKey(k)).join(" / ") || "-"; desktop?.map((k) => formatKey(k)).join(" / ") || "-";
const macKeys = const macKeys =
desktop desktop
?.map(macify) ?.map(macify)
.map((k) => formatKey(k, true)) .map((k) => formatKey(k, true))
.join(" / ") || "-"; .join(" / ") || "-";
return `| ${description} | ${webKeys} | ${windowsLinuxKeys} | ${macKeys} |`; return `| ${description} | ${webKeys} | ${windowsLinuxKeys} | ${macKeys} |`;
}) })
.join("\n"); .join("\n");
return `### ${category}\n\n${header}\n${rows}`; return `### ${category}\n\n${header}\n${rows}`;
}) }).join("\n\n");
.join("\n\n");
} }

View File

@@ -1,17 +1,21 @@
interface Hotkeys { interface Hotkeys {
keys: (isDesktop: boolean) => string[]; keys: (isDesktop: boolean) => string[];
description: string; description: string;
category: string; category: Category;
type: "hotkeys"; type: "hotkeys";
} }
interface TipTapKey { interface TipTapKey {
keys: string | string[]; keys: string | string[];
description: string; description: string;
category: string; category: Category;
type: "tiptap"; type: "tiptap";
} }
type Category = (typeof CATEGORIES)[number];
export const CATEGORIES = ["General", "Navigation", "Editor"] as const;
/** /**
* consumed by hotkeys-js * consumed by hotkeys-js
*/ */
@@ -427,7 +431,13 @@ export function formatKey(key: string, isMac = false, separator = " ") {
} }
export function getGroupedKeybindings(isDesktop: boolean, isMac: boolean) { export function getGroupedKeybindings(isDesktop: boolean, isMac: boolean) {
const grouped: Record<string, { keys: string[]; description: string }[]> = {}; const grouped: {
shortcuts: { keys: string[]; description: string }[];
category: Category;
}[] = CATEGORIES.map((c) => ({
category: c,
shortcuts: []
}));
const allKeybindings = { ...hotkeys, ...tiptapKeys }; const allKeybindings = { ...hotkeys, ...tiptapKeys };
@@ -437,15 +447,16 @@ export function getGroupedKeybindings(isDesktop: boolean, isMac: boolean) {
typeof binding.keys === "function" typeof binding.keys === "function"
? binding.keys(isDesktop) ? binding.keys(isDesktop)
: binding.keys; : binding.keys;
if (!keys || !keys.length) continue;
if (isMac) { if (isMac) {
keys = Array.isArray(keys) ? keys.map(macify) : macify(keys); keys = Array.isArray(keys) ? keys.map(macify) : macify(keys);
} }
if (!grouped[binding.category]) { const group = grouped.find((g) => g.category === binding.category);
grouped[binding.category] = []; if (!group) throw new Error("Invalid group category: " + binding.category);
}
grouped[binding.category].push({ group.shortcuts.push({
keys: Array.isArray(keys) ? keys : [keys], keys: Array.isArray(keys) ? keys : [keys],
description: binding.description description: binding.description
}); });