global: add keyboard shortcuts

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

global: (wip) move keyboard shortcuts metadata into common package
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

common: refactor keybindings.ts
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

global: (wip) more refactoring
* minor refactor dialog
* refactor logic out from script file to keybindings file

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

common: filter keybindings based on platform && minor ui changes

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

editor: use keyboard keys from common package
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

web: remove unrelated title-box change
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

editor: add TODO:remove comments
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2025-02-24 16:10:27 +05:00
committed by Abdullah Atta
parent 20138505c4
commit 4b2fb80c23
21 changed files with 803 additions and 54 deletions

View File

@@ -23,6 +23,8 @@ import { useStore as useSearchStore } from "../stores/search-store";
import { useEditorManager } from "../components/editor/manager";
import { CommandPaletteDialog } from "../dialogs/command-palette";
import { hashNavigate } from "../navigation";
import { keybindings } from "@notesnook/common";
import { KeyboardShortcutsDialog } from "../dialogs/keyboard-shortcuts-dialog";
function isInEditor(e: KeyboardEvent) {
return (
@@ -62,43 +64,28 @@ const KEYMAP = [
// },
// },
{
keys: [
"command+option+right",
"ctrl+alt+right",
"command+option+shift+right",
"ctrl+alt+shift+right",
"ctrl+tab",
"command+tab"
],
description: "Go to next tab",
keys: keybindings.nextTab.keys(IS_DESKTOP_APP),
description: keybindings.nextTab.description,
action: () => useEditorStore.getState().focusNextTab()
},
{
keys: [
"command+option+left",
"ctrl+alt+left",
"command+option+shift+left",
"ctrl+alt+shift+left",
"ctrl+shift+tab",
"command+shift+tab"
],
description: "Go to previous tab",
keys: keybindings.previousTab.keys(IS_DESKTOP_APP),
description: keybindings.previousTab.description,
action: () => useEditorStore.getState().focusPreviousTab()
},
{
keys: ["ctrl+t", "command+t"],
description: "Create a new tab",
keys: keybindings.newTab.keys(IS_DESKTOP_APP),
description: keybindings.newTab.description,
action: () => useEditorStore.getState().addTab()
},
{
keys: ["ctrl+n", "command+n"],
description: "Create a new note",
keys: keybindings.newNote.keys(IS_DESKTOP_APP),
description: keybindings.newNote.description,
action: () => useEditorStore.getState().newSession()
},
{
keys: ["ctrl+w", "command+w"],
description:
"Close active tab or focus previously activated tab if active tab pinned",
keys: keybindings.closeActiveTab.keys(IS_DESKTOP_APP),
description: keybindings.closeActiveTab.description,
action: () => {
const activeTab = useEditorStore.getState().getActiveTab();
if (activeTab?.pinned) {
@@ -109,13 +96,13 @@ const KEYMAP = [
}
},
{
keys: ["ctrl+shift+w", "command+shift+w"],
description: "Close all tabs",
keys: keybindings.closeAllTabs.keys(IS_DESKTOP_APP),
description: keybindings.closeAllTabs.description,
action: () => useEditorStore.getState().closeAllTabs()
},
{
keys: ["command+f", "ctrl+f"],
description: "Search all notes",
keys: keybindings.searchInNotes.keys(IS_DESKTOP_APP),
description: keybindings.searchInNotes.description,
global: false,
action: (e: KeyboardEvent) => {
if (isInEditor(e)) {
@@ -198,8 +185,10 @@ const KEYMAP = [
// },
// },
{
keys: ["ctrl+k", "cmd+k", "ctrl+p", "cmd+p"],
description: "Open command palette",
keys: keybindings.openCommandPalette
.keys(IS_DESKTOP_APP)
.concat(keybindings.openQuickOpen.keys(IS_DESKTOP_APP)),
description: keybindings.openCommandPalette.description,
action: (e: KeyboardEvent) => {
e.preventDefault();
CommandPaletteDialog.close();
@@ -209,9 +198,14 @@ const KEYMAP = [
}
},
{
keys: ["ctrl+,", "command+,"],
description: "Open settings",
keys: keybindings.openSettings.keys(IS_DESKTOP_APP),
description: keybindings.openSettings.description,
action: () => hashNavigate("/settings", { replace: true })
},
{
keys: keybindings.openKeyboardShortcuts.keys(IS_DESKTOP_APP),
description: keybindings.openKeyboardShortcuts.description,
action: () => KeyboardShortcutsDialog.show({})
}
];
@@ -220,7 +214,9 @@ export function registerKeyMap() {
return true;
};
console.log("KEYMAP", KEYMAP);
KEYMAP.forEach((key) => {
if (key.keys.length === 0) return;
hotkeys(key.keys.join(","), (e) => {
e.preventDefault();
key.action?.(e);

View File

@@ -0,0 +1,116 @@
/*
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 { formatKey, getGroupedKeybindings } from "@notesnook/common";
import { Flex, Text } from "@theme-ui/components";
import { DialogManager } from "../common/dialog-manager";
import Dialog from "../components/dialog";
import { isMac } from "../utils/platform";
const groupedKeybindings = getGroupedKeybindings(IS_DESKTOP_APP, isMac());
export const KeyboardShortcutsDialog = DialogManager.register(
function KeyboardShortcutsDialog(props) {
return (
<Dialog
isOpen={true}
title={"Keyboard Shortcuts"}
width={750}
onClose={() => props.onClose(false)}
>
<Flex
sx={{
flexDirection: "column",
flexWrap: "nowrap",
height: 650
}}
>
{Object.entries(groupedKeybindings).map(([group, shortcuts]) => {
if (
shortcuts.length === 0 ||
shortcuts.every((s) => s.keys.length === 0)
) {
return null;
}
return (
<Flex key={group} sx={{ flexDirection: "column", mb: 2 }}>
<Text sx={{ mt: 1, fontWeight: "bold" }}>{group}</Text>
<hr
style={{
width: "100%",
background: "var(--background-secondary)"
}}
/>
{shortcuts.map((shortcut) => {
if (shortcut.keys.length === 0) return null;
return (
<Flex
key={shortcut.description}
sx={{
mb: 2,
flexDirection: "row",
justifyContent: "space-between"
}}
>
<Text
variant="subtitle"
sx={{
fontWeight: "normal"
}}
>
{shortcut.description}
</Text>
<Text as="p">
{shortcut.keys.map((k, i) => (
<>
<Keys keys={formatKey(k)} />
{shortcut.keys.length - 1 !== i && (
<Text as="span" sx={{ mx: 1, fontSize: "0.8em" }}>
/
</Text>
)}
</>
))}
</Text>
</Flex>
);
})}
</Flex>
);
})}
</Flex>
</Dialog>
);
}
);
function Keys({ keys }: { keys: string }) {
return keys.split(" ").map((k) => (
<kbd
style={{
margin: "0 1px",
background: "var(--background-secondary)",
fontSize: "0.8em",
fontWeight: "bold"
}}
>
{k}
</kbd>
));
}

View File

@@ -0,0 +1,80 @@
---
title: Keyboard Shortcuts
description: Keyboard shortcuts for Notesnook
---
The following keyboard shortcuts will help you navigate Notesnook faster.
### Navigation
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Next tab | Ctrl Alt right / Ctrl Alt Shift right | Ctrl tab | Command tab |
| Previous tab | Ctrl Alt left / Ctrl Alt Shift left | Ctrl Shift tab | Command Shift tab |
| New tab | - | Ctrl t | Command t |
| Close active tab | - | Ctrl w | Command w |
| Close all tabs | - | Ctrl Shift w | Command Shift w |
| Search in notes list view if editor is not focused | Ctrl f | Ctrl f | Command f |
| Command palette | Ctrl k | Ctrl k | Command k |
| Quick open | Ctrl p | Ctrl p | Command p |
### Note
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| New note | - | Ctrl n | Command n |
### General
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Settings | Ctrl , | Ctrl , | Command , |
| Keyboard shortcuts | Ctrl / | Ctrl / | Command / |
### Editor
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Add attachment | Ctrl Shift A | Ctrl Shift A | Command Shift A |
| Insert blockquote | Ctrl Shift B | Ctrl Shift B | Command Shift B |
| Toggle bold | Ctrl b | Ctrl b | Command b |
| Toggle bullet list | Ctrl Shift 8 | Ctrl Shift 8 | Command Shift 8 |
| Toggle check list | Ctrl Shift 9 | Ctrl Shift 9 | Command Shift 9 |
| Split list item | Enter | Enter | Enter |
| Lift list item | Shift Tab | Shift Tab | Shift Tab |
| Sink list item | Ctrl Shift Down | Ctrl Shift Down | Command Shift Down |
| Toggle code | Ctrl e | Ctrl e | Command e |
| Toggle code block | Ctrl Shift C | Ctrl Shift C | Command Shift C |
| Insert date | Alt d | Alt d | Option d |
| Insert time | Alt t | Alt t | Option t |
| Insert date and time | Ctrl Alt d | Ctrl Alt d | Command Option d |
| Insert date and time with timezone | Ctrl Alt z | Ctrl Alt z | Command Option z |
| Increase font size | Ctrl [ | Ctrl [ | Command [ |
| Decrease font size | Ctrl ] | Ctrl ] | Command ] |
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | Command Option 1 |
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | Command Option 2 |
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | Command Option 3 |
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | Command Option 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | Command Option 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | Command Option 6 |
| Undo | Ctrl z | Ctrl z | Command z |
| Redo | Ctrl Shift z / Ctrl y | Ctrl Shift z / Ctrl y | Command Shift z / Command y |
| Add image | Ctrl Shift I | Ctrl Shift I | Command Shift I |
| Toggle italic | Ctrl i | Ctrl i | Command i |
| Remove formatting in selection | Ctrl \ | Ctrl \ | Command \ |
| Insert internal link | Ctrl Shift L | Ctrl Shift L | Command Shift L |
| Insert link | Ctrl Shift K | Ctrl Shift K | Command Shift K |
| Insert math block | Ctrl Shift M | Ctrl Shift M | Command Shift M |
| Toggle ordered list | Ctrl Shift 7 | Ctrl Shift 7 | Command Shift 7 |
| Toggle outline list | Ctrl Shift O | Ctrl Shift O | Command Shift O |
| Toggle outline list expand | Ctrl Space | Ctrl Space | Command Space |
| Open search | Ctrl F | Ctrl F | Command F |
| Toggle strike | Ctrl Shift S | Ctrl Shift S | Command Shift S |
| Toggle subscript | Ctrl , | Ctrl , | Command , |
| Toggle superscript | Ctrl . | Ctrl . | Command . |
| Toggle task list | Ctrl Shift T | Ctrl Shift T | Command Shift T |
| Text align center | Ctrl Shift E | Ctrl Shift E | Command Shift E |
| Text align justify | Ctrl Shift J | Ctrl Shift J | Command Shift J |
| Text align left | Ctrl Shift L | Ctrl Shift L | Command Shift L |
| Text align right | Ctrl Shift R | Ctrl Shift R | Command Shift R |
| Underline | Ctrl u | Ctrl u | Command u |

View File

@@ -0,0 +1,25 @@
console.log("Generating keyboard shortcuts documentation...");
import { writeFileSync } from "fs";
import { getGroupedTableKeybindingsMarkdown } from "./packages/common/src/utils/keybindings";
const keyboardShortcutFilePath = "./docs/help/contents/keyboard-shortcuts.md";
const frontmatter = `---
title: Keyboard Shortcuts
description: Keyboard shortcuts for Notesnook
---
`;
const content =
"The following keyboard shortcuts will help you navigate Notesnook faster.";
const markdownTable = getGroupedTableKeybindingsMarkdown();
writeFileSync(
keyboardShortcutFilePath,
frontmatter + "\n" + content + "\n\n" + markdownTable,
"utf-8"
);
console.log("Keyboard shortcuts documentation updated successfully!");

View File

@@ -28,3 +28,4 @@ export * from "./migrate-toolbar.js";
export * from "./export-notes.js";
export * from "./dataurl.js";
export * from "./tab-session-history.js";
export * from "./keybindings.js";

View File

@@ -0,0 +1,474 @@
interface Hotkeys {
keys: (isDesktop: boolean) => string[];
description: string;
category: string;
type: "hotkeys";
}
interface TipTapKey {
keys: string | string[];
description: string;
category: string;
type: "tiptap";
}
/**
* consumed by hotkeys-js
*/
export const hotkeys = {
nextTab: {
keys: normalizeKeys({
web: ["ctrl+alt+right", "ctrl+alt+shift+right"],
desktop: ["ctrl+tab"]
}),
description: "Next tab",
category: "Navigation",
type: "hotkeys"
},
previousTab: {
keys: normalizeKeys({
web: ["ctrl+alt+left", "ctrl+alt+shift+left"],
desktop: ["ctrl+shift+tab"]
}),
description: "Previous tab",
category: "Navigation",
type: "hotkeys"
},
newTab: {
keys: normalizeKeys({
desktop: ["ctrl+t"]
}),
description: "New tab",
category: "Navigation",
type: "hotkeys"
},
closeActiveTab: {
keys: normalizeKeys({
desktop: ["ctrl+w"]
}),
description: "Close active tab",
category: "Navigation",
type: "hotkeys"
},
closeAllTabs: {
keys: normalizeKeys({
desktop: ["ctrl+shift+w"]
}),
description: "Close all tabs",
category: "Navigation",
type: "hotkeys"
},
newNote: {
keys: normalizeKeys({
desktop: ["ctrl+n"]
}),
description: "New note",
category: "Note",
type: "hotkeys"
},
searchInNotes: {
keys: normalizeKeys(["ctrl+f"]),
description: "Search in notes list view if editor is not focused",
category: "General",
type: "hotkeys"
},
openCommandPalette: {
keys: normalizeKeys(["ctrl+k"]),
description: "Command palette",
category: "Navigation",
type: "hotkeys"
},
openQuickOpen: {
keys: normalizeKeys(["ctrl+p"]),
description: "Quick open",
category: "Navigation",
type: "hotkeys"
},
openSettings: {
keys: normalizeKeys(["ctrl+,"]),
description: "Settings",
category: "General",
type: "hotkeys"
},
openKeyboardShortcuts: {
keys: normalizeKeys(["ctrl+/"]),
description: "Keyboard shortcuts",
category: "General",
type: "hotkeys"
}
} satisfies Record<string, Hotkeys>;
/**
* consumed by tiptap
*/
export const tiptapKeys = {
addAttachment: {
keys: "Mod-Shift-A",
description: "Add attachment",
category: "Editor",
type: "tiptap"
},
insertBlockquote: {
keys: "Mod-Shift-B",
description: "Insert blockquote",
category: "Editor",
type: "tiptap"
},
toggleBold: {
keys: "Mod-b",
description: "Toggle bold",
category: "Editor",
type: "tiptap"
},
toggleBulletList: {
keys: "Mod-Shift-8",
description: "Toggle bullet list",
category: "Editor",
type: "tiptap"
},
toggleCheckList: {
keys: "Mod-Shift-9",
description: "Toggle check list",
category: "Editor",
type: "tiptap"
},
splitListItem: {
keys: "Enter",
description: "Split list item",
category: "Editor",
type: "tiptap"
},
liftListItem: {
keys: "Shift-Tab",
description: "Lift list item",
category: "Editor",
type: "tiptap"
},
sinkListItem: {
keys: "Mod-Shift-Down",
description: "Sink list item",
category: "Editor",
type: "tiptap"
},
toggleCode: {
keys: "Mod-e",
description: "Toggle code",
category: "Editor",
type: "tiptap"
},
toggleCodeBlock: {
keys: "Mod-Shift-C",
description: "Toggle code block",
category: "Editor",
type: "tiptap"
},
insertDate: {
keys: "Alt-d",
description: "Insert date",
category: "Editor",
type: "tiptap"
},
insertTime: {
keys: "Alt-t",
description: "Insert time",
category: "Editor",
type: "tiptap"
},
insertDateTime: {
keys: "Mod-Alt-d",
description: "Insert date and time",
category: "Editor",
type: "tiptap"
},
insertDateTimeWithTimezone: {
keys: "Mod-Alt-z",
description: "Insert date and time with timezone",
category: "Editor",
type: "tiptap"
},
increaseFontSize: {
keys: "Ctrl-[",
description: "Increase font size",
category: "Editor",
type: "tiptap"
},
decreaseFontSize: {
keys: "Ctrl-]",
description: "Decrease font size",
category: "Editor",
type: "tiptap"
},
insertHeading1: {
keys: "Mod-Alt-1",
description: "Insert heading 1",
category: "Editor",
type: "tiptap"
},
insertHeading2: {
keys: "Mod-Alt-2",
description: "Insert heading 2",
category: "Editor",
type: "tiptap"
},
insertHeading3: {
keys: "Mod-Alt-3",
description: "Insert heading 3",
category: "Editor",
type: "tiptap"
},
insertHeading4: {
keys: "Mod-Alt-4",
description: "Insert heading 4",
category: "Editor",
type: "tiptap"
},
insertHeading5: {
keys: "Mod-Alt-5",
description: "Insert heading 5",
category: "Editor",
type: "tiptap"
},
insertHeading6: {
keys: "Mod-Alt-6",
description: "Insert heading 6",
category: "Editor",
type: "tiptap"
},
undo: {
keys: "Mod-z",
description: "Undo",
category: "Editor",
type: "tiptap"
},
redo: {
keys: ["Mod-Shift-z", "Mod-y"],
description: "Redo",
category: "Editor",
type: "tiptap"
},
addImage: {
keys: "Mod-Shift-I",
description: "Add image",
category: "Editor",
type: "tiptap"
},
toggleItalic: {
keys: "Mod-i",
description: "Toggle italic",
category: "Editor",
type: "tiptap"
},
removeFormattingInSelection: {
keys: "Mod-\\",
description: "Remove formatting in selection",
category: "Editor",
type: "tiptap"
},
insertInternalLink: {
keys: "Mod-Shift-L",
description: "Insert internal link",
category: "Editor",
type: "tiptap"
},
insertLink: {
keys: "Mod-Shift-K",
description: "Insert link",
category: "Editor",
type: "tiptap"
},
insertMathBlock: {
keys: "Mod-Shift-M",
description: "Insert math block",
category: "Editor",
type: "tiptap"
},
toggleOrderedList: {
keys: "Mod-Shift-7",
description: "Toggle ordered list",
category: "Editor",
type: "tiptap"
},
toggleOutlineList: {
keys: "Mod-Shift-O",
description: "Toggle outline list",
category: "Editor",
type: "tiptap"
},
toggleOutlineListExpand: {
keys: "Mod-Space",
description: "Toggle outline list expand",
category: "Editor",
type: "tiptap"
},
openSearch: {
keys: "Mod-F",
description: "Open search",
category: "Editor",
type: "tiptap"
},
toggleStrike: {
keys: "Mod-Shift-S",
description: "Toggle strike",
category: "Editor",
type: "tiptap"
},
toggleSubscript: {
keys: "Mod-,",
description: "Toggle subscript",
category: "Editor",
type: "tiptap"
},
toggleSuperscript: {
keys: "Mod-.",
description: "Toggle superscript",
category: "Editor",
type: "tiptap"
},
toggleTaskList: {
keys: "Mod-Shift-T",
description: "Toggle task list",
category: "Editor",
type: "tiptap"
},
textAlignCenter: {
keys: "Mod-Shift-E",
description: "Text align center",
category: "Editor",
type: "tiptap"
},
textAlignJustify: {
keys: "Mod-Shift-J",
description: "Text align justify",
category: "Editor",
type: "tiptap"
},
textAlignLeft: {
keys: "Mod-Shift-L",
description: "Text align left",
category: "Editor",
type: "tiptap"
},
textAlignRight: {
keys: "Mod-Shift-R",
description: "Text align right",
category: "Editor",
type: "tiptap"
},
underline: {
keys: "Mod-u",
description: "Underline",
category: "Editor",
type: "tiptap"
}
} satisfies Record<string, TipTapKey>;
export const keybindings = {
...hotkeys,
...tiptapKeys
};
function normalizeKeys(
keys: string[] | { web?: string[]; desktop?: string[] }
): (isDesktop?: boolean) => string[] {
return (isDesktop = false) => {
let keyList: string[] = [];
if (Array.isArray(keys)) {
keyList = keys;
} else {
keyList = isDesktop ? keys.desktop ?? [] : keys.web ?? [];
}
return keyList;
};
}
function macify(key: string) {
return key
.replace(/ctrl/gi, "Command")
.replace(/alt/gi, "Option")
.replace(/mod/gi, "Command");
}
export function formatKey(key: string) {
return key
.replace(/\+|-/g, " ")
.replace(/\bcommand\b/gi, "Command")
.replace(/\bctrl\b/gi, "Ctrl")
.replace(/\bshift\b/gi, "Shift")
.replace(/\balt\b/gi, "Alt")
.replace(/\bmod\b/gi, "Ctrl")
.trim();
}
export function getGroupedKeybindings(isDesktop: boolean, isMac: boolean) {
const grouped: Record<string, { keys: string[]; description: string }[]> = {};
const allKeybindings = { ...hotkeys, ...tiptapKeys };
for (const key in allKeybindings) {
const binding = allKeybindings[key as keyof typeof allKeybindings];
let keys =
typeof binding.keys === "function"
? binding.keys(isDesktop)
: binding.keys;
if (isMac) {
keys = Array.isArray(keys) ? keys.map(macify) : macify(keys);
}
if (!grouped[binding.category]) {
grouped[binding.category] = [];
}
grouped[binding.category].push({
keys: Array.isArray(keys) ? keys : [keys],
description: binding.description
});
}
return grouped;
}
export function getGroupedTableKeybindingsMarkdown(): string {
const desktopKeybindings = getGroupedKeybindings(true, false);
const webKeybindings = getGroupedKeybindings(false, false);
const header = `| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |`;
return Object.keys({ ...webKeybindings, ...desktopKeybindings })
.map((category) => {
const webShortcuts = webKeybindings[category] || [];
const desktopShortcuts = desktopKeybindings[category] || [];
const mergedShortcuts: Record<
string,
{ web?: string[]; desktop?: string[] }
> = {};
webShortcuts.forEach(({ description, keys }) => {
if (!mergedShortcuts[description]) {
mergedShortcuts[description] = {};
}
mergedShortcuts[description].web = keys.map(formatKey);
});
desktopShortcuts.forEach(({ description, keys }) => {
if (!mergedShortcuts[description]) {
mergedShortcuts[description] = {};
}
mergedShortcuts[description].desktop = keys.map(formatKey);
});
const rows = Object.entries(mergedShortcuts)
.map(([description, { web, desktop }]) => {
const webKeys = web?.join(" / ") || "-";
const windowsLinuxKeys = desktop?.join(" / ") || "-";
const macKeys =
desktop?.map(macify).map(formatKey).join(" / ") || "-";
return `| ${description} | ${webKeys} | ${windowsLinuxKeys} | ${macKeys} |`;
})
.join("\n");
return `### ${category}\n\n${header}\n${rows}`;
})
.join("\n\n");
}

View File

@@ -22,6 +22,7 @@ import { Attribute } from "@tiptap/core";
import { createNodeView } from "../react/index.js";
import { AttachmentComponent } from "./component.js";
import { Attachment } from "./types.js";
import { tiptapKeys } from "@notesnook/common";
export type AttachmentType = "image" | "file" | "camera";
export interface AttachmentOptions {
@@ -161,7 +162,7 @@ export const AttachmentNode = Node.create<AttachmentOptions>({
addKeyboardShortcuts() {
return {
"Mod-Shift-A": () =>
[tiptapKeys.addAttachment.keys]: () =>
this.editor.storage.openAttachmentPicker?.("file") || true
};
}

View File

@@ -16,6 +16,7 @@ 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 { tiptapKeys } from "@notesnook/common";
import { getParentAttributes } from "../../utils/prosemirror.js";
import { wrappingInputRule } from "@tiptap/core";
import TiptapBlockquote, { inputRegex } from "@tiptap/extension-blockquote";
@@ -47,5 +48,13 @@ export const Blockquote = TiptapBlockquote.extend({
getAttributes: () => getParentAttributes(this.editor)
})
];
},
addKeyboardShortcuts() {
return {
...this.parent?.(),
[tiptapKeys.insertBlockquote.keys]: () =>
this.editor.commands.toggleBlockquote()
};
}
});

View File

@@ -20,6 +20,7 @@ import { mergeAttributes, Node, wrappingInputRule } from "@tiptap/core";
import { inputRegex } from "@tiptap/extension-task-item";
import { getParentAttributes } from "../../utils/prosemirror.js";
import { ListItem } from "../list-item/index.js";
import { tiptapKeys } from "@notesnook/common";
export interface CheckListOptions {
itemTypeName: string;
@@ -123,7 +124,8 @@ export const CheckList = Node.create<CheckListOptions>({
addKeyboardShortcuts() {
return {
"Mod-Shift-9": () => this.editor.commands.toggleCheckList()
[tiptapKeys.toggleCheckList.keys]: () =>
this.editor.commands.toggleCheckList()
};
}
});

View File

@@ -36,6 +36,7 @@ import stripIndent from "strip-indent";
import { nanoid } from "nanoid";
import Languages from "./languages.json";
import { CaretPosition, CodeLine } from "./utils.js";
import { tiptapKeys } from "@notesnook/common";
interface Indent {
type: "tab" | "space";
@@ -292,7 +293,8 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
addKeyboardShortcuts() {
return {
"Mod-Shift-C": () => this.editor.commands.toggleCodeBlock(),
[tiptapKeys.toggleCodeBlock.keys]: () =>
this.editor.commands.toggleCodeBlock(),
"Mod-a": ({ editor }) => {
const { $anchor } = this.editor.state.selection;
if ($anchor.parent.type.name !== this.name) {

View File

@@ -23,7 +23,7 @@ import {
InputRuleFinder,
ExtendedRegExpMatchArray
} from "@tiptap/core";
import { formatDate } from "@notesnook/common";
import { formatDate, tiptapKeys } from "@notesnook/common";
declare module "@tiptap/core" {
interface Commands<ReturnType> {
@@ -67,10 +67,14 @@ export const DateTime = Extension.create<DateTimeOptions>({
addKeyboardShortcuts() {
return {
"Alt-t": ({ editor }) => editor.commands.insertTime(),
"Alt-d": ({ editor }) => editor.commands.insertDate(),
"Mod-Alt-d": ({ editor }) => editor.commands.insertDateTime(),
"Mod-Alt-z": ({ editor }) => editor.commands.insertDateTimeWithTimeZone()
[tiptapKeys.insertTime.keys]: ({ editor }) =>
editor.commands.insertTime(),
[tiptapKeys.insertDate.keys]: ({ editor }) =>
editor.commands.insertDate(),
[tiptapKeys.insertDateTime.keys]: ({ editor }) =>
editor.commands.insertDateTime(),
[tiptapKeys.insertDateTimeWithTimezone.keys]: ({ editor }) =>
editor.commands.insertDateTimeWithTimeZone()
};
},

View File

@@ -17,6 +17,7 @@ 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 { tiptapKeys } from "@notesnook/common";
import { useToolbarStore } from "../../toolbar/stores/toolbar-store.js";
import { Editor, Extension } from "@tiptap/core";
@@ -86,7 +87,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
},
addKeyboardShortcuts() {
return {
"ctrl-]": ({ editor }) => {
[tiptapKeys.decreaseFontSize.keys]: ({ editor }) => {
editor
.chain()
.focus()
@@ -94,7 +95,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
.run();
return true;
},
"Ctrl-[": ({ editor }) => {
[tiptapKeys.increaseFontSize.keys]: ({ editor }) => {
editor
.chain()
.focus()

View File

@@ -17,6 +17,7 @@ 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 { tiptapKeys } from "@notesnook/common";
import { textblockTypeInputRule } from "@tiptap/core";
import { Heading as TiptapHeading } from "@tiptap/extension-heading";
@@ -49,7 +50,8 @@ export const Heading = TiptapHeading.extend({
(items, level) => ({
...items,
...{
[`Mod-Alt-${level}`]: () => this.editor.commands.setHeading({ level })
[tiptapKeys[`insertHeading${level}`].keys]: () =>
this.editor.commands.setHeading({ level })
}
}),
{}

View File

@@ -27,6 +27,7 @@ import {
import { createNodeView } from "../react/index.js";
import { TextDirections } from "../text-direction/index.js";
import { ImageComponent } from "./component.js";
import { tiptapKeys } from "@notesnook/common";
export interface ImageOptions {
inline: boolean;
@@ -199,7 +200,7 @@ export const ImageNode = Node.create<ImageOptions>({
addKeyboardShortcuts() {
return {
"Mod-Shift-I": () =>
[tiptapKeys.addImage.keys]: () =>
this.editor.storage.openAttachmentPicker?.("image") || true
};
}

View File

@@ -22,6 +22,7 @@ import { isInTable } from "@tiptap/pm/tables";
import { CodeBlock } from "../code-block/index.js";
import { showLinkPopup } from "../../toolbar/popups/link-popup.js";
import { isListActive } from "../../utils/list.js";
import { tiptapKeys } from "@notesnook/common";
export const KeyMap = Extension.create({
name: "key-map",
@@ -42,7 +43,7 @@ export const KeyMap = Extension.create({
if (isListActive(editor)) return false;
return true;
},
"Mod-\\": ({ editor }) => {
[tiptapKeys.removeFormattingInSelection.keys]: ({ editor }) => {
editor
.chain()
.focus()
@@ -52,7 +53,7 @@ export const KeyMap = Extension.create({
.run();
return true;
},
"Shift-Mod-L": ({ editor }) => {
[tiptapKeys.insertInternalLink.keys]: ({ editor }) => {
editor.storage.createInternalLink?.().then((link) => {
if (!link) return;
@@ -67,7 +68,7 @@ export const KeyMap = Extension.create({
});
return true;
},
"Shift-Mod-k": ({ editor }) => {
[tiptapKeys.insertLink.keys]: ({ editor }) => {
showLinkPopup(editor);
return true;
}

View File

@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Node, mergeAttributes } from "@tiptap/core";
import { insertMathNode } from "./plugin/index.js";
import { NodeSelection } from "prosemirror-state";
import { tiptapKeys } from "@notesnook/common";
declare module "@tiptap/core" {
interface Commands<ReturnType> {
@@ -66,7 +67,8 @@ export const MathBlock = Node.create({
addKeyboardShortcuts() {
return {
"Mod-Shift-M": () => this.editor.commands.insertMathBlock()
[tiptapKeys.insertMathBlock.keys]: () =>
this.editor.commands.insertMathBlock()
};
},

View File

@@ -24,6 +24,7 @@ import {
} from "@tiptap/core";
import { findParentNodeOfTypeClosestToPos } from "../../utils/prosemirror.js";
import { OutlineList } from "../outline-list/outline-list.js";
import { tiptapKeys } from "@notesnook/common";
export interface ListItemOptions {
HTMLAttributes: Record<string, unknown>;
@@ -75,7 +76,7 @@ export const OutlineListItem = Node.create<ListItemOptions>({
addKeyboardShortcuts() {
return {
"Mod-Space": ({ editor }) => {
[tiptapKeys.toggleOutlineListExpand.keys]: ({ editor }) => {
const { selection } = editor.state;
const { $from, empty } = selection;

View File

@@ -17,6 +17,7 @@ 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 { tiptapKeys } from "@notesnook/common";
import { getParentAttributes } from "../../utils/prosemirror.js";
import { Node, mergeAttributes, wrappingInputRule } from "@tiptap/core";
@@ -100,7 +101,8 @@ export const OutlineList = Node.create<OutlineListOptions>({
addKeyboardShortcuts() {
return {
"Mod-Shift-O": () => this.editor.commands.toggleOutlineList()
[tiptapKeys.toggleOutlineList.keys]: () =>
this.editor.commands.toggleOutlineList()
};
},

View File

@@ -27,6 +27,7 @@ import {
TextSelection
} from "prosemirror-state";
import { SearchSettings } from "../../toolbar/stores/search-store.js";
import { tiptapKeys } from "@notesnook/common";
type DispatchFn = (tr: Transaction) => void;
declare module "@tiptap/core" {
@@ -354,7 +355,8 @@ export const SearchReplace = Extension.create<SearchOptions, SearchStorage>({
addKeyboardShortcuts() {
return {
"Mod-f": ({ editor }) => editor.commands.startSearch(),
[tiptapKeys.openSearch.keys]: ({ editor }) =>
editor.commands.startSearch(),
Escape: ({ editor }) => editor.commands.endSearch()
};
},

View File

@@ -40,6 +40,7 @@ import {
import { Node as ProsemirrorNode } from "@tiptap/pm/model";
import { TaskItemNode } from "../task-item/index.js";
import { ListItem } from "../list-item/list-item.js";
import { tiptapKeys } from "@notesnook/common";
type TaskListStats = { checked: number; total: number };
export type TaskListAttributes = {
@@ -368,7 +369,8 @@ export const TaskListNode = TaskList.extend({
addKeyboardShortcuts() {
return {
"Mod-Shift-T": () => this.editor.commands.toggleTaskList()
[tiptapKeys.toggleTaskList.keys]: () =>
this.editor.commands.toggleTaskList()
};
}
});

View File

@@ -17,7 +17,14 @@ 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 { EditorOptions, Editor as TiptapEditor } from "@tiptap/core";
import {
AnyConfig,
EditorOptions,
Editor as TiptapEditor,
createDocument,
getExtensionField,
resolveFocusPosition
} from "@tiptap/core";
import { DependencyList, useEffect, useMemo, useRef, useState } from "react";
import { Editor } from "../types.js";
import { useToolbarStore } from "../toolbar/stores/toolbar-store.js";
@@ -29,6 +36,9 @@ function useForceUpdate() {
return () => setValue((value) => value + 1);
}
// TODO: remove
const bindings: Record<any, any> = {};
export const useEditor = (
options: Partial<EditorOptions> = {},
deps: DependencyList = []
@@ -37,6 +47,21 @@ export const useEditor = (
const forceUpdate = useForceUpdate();
const editorRef = useRef<TiptapEditor>(editor);
// TODO: remove
const resolvedExtensions = editor.extensionManager.extensions;
for (const extension of resolvedExtensions) {
const addKeyboardShortcuts = getExtensionField<
AnyConfig["addKeyboardShortcuts"]
>(extension, "addKeyboardShortcuts", {
name: extension.name,
options: extension.options,
storage: extension.storage,
editor
});
bindings[extension.name] = addKeyboardShortcuts?.();
}
console.log("bindings", bindings);
useEffect(
() => {
if (editor.view.isDestroyed) return;