feat: Markdown Editor Keyboard Shortcuts (#2763)

* Add bold and italic keyboard shortcut

* Add hyperlink keyboard shortcut support
pull/2757/head^2
Noah Alderton 1 year ago committed by GitHub
parent cd3a98c095
commit 728a9705ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
import useLocalStorage from "react-use/lib/useLocalStorage";
import { memoServiceClient } from "@/grpcweb";
import { TAB_SPACE_WIDTH, UNKNOWN_ID } from "@/helpers/consts";
import { isValidUrl } from "@/helpers/utils";
import { useGlobalStore, useResourceStore } from "@/store/module";
import { useMemoStore, useUserStore } from "@/store/v1";
import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v2/memo_relation_service";
@ -115,6 +116,20 @@ const MemoEditor = (props: Props) => {
handleSaveBtnClick();
return;
}
if (event.key === "b") {
const boldDelimiter = "**";
event.preventDefault();
styleHighlightedText(editorRef.current, boldDelimiter);
}
if (event.key === "i") {
const italicsDelimiter = "*";
event.preventDefault();
styleHighlightedText(editorRef.current, italicsDelimiter);
}
if (event.key === "k") {
event.preventDefault();
hyperlinkHighlightedTest(editorRef.current);
}
}
if (event.key === "Tab") {
event.preventDefault();
@ -239,6 +254,9 @@ const MemoEditor = (props: Props) => {
if (event.clipboardData && event.clipboardData.files.length > 0) {
event.preventDefault();
await uploadMultiFiles(event.clipboardData.files);
} else if (editorRef.current != null && isValidUrl(event.clipboardData.getData("Text"))) {
event.preventDefault();
hyperlinkHighlightedTest(editorRef.current, event.clipboardData.getData("Text"));
}
};
@ -339,6 +357,33 @@ const MemoEditor = (props: Props) => {
editorRef.current?.focus();
};
const styleHighlightedText = (editor: EditorRefActions, delimiter: string) => {
const cursorPosition = editor.getCursorPosition();
const selectedContent = editor.getSelectedContent();
if (selectedContent.startsWith(delimiter) && selectedContent.endsWith(delimiter)) {
editor.insertText(selectedContent.slice(delimiter.length, -delimiter.length));
const newContentLength = selectedContent.length - delimiter.length * 2;
editor.setCursorPosition(cursorPosition, cursorPosition + newContentLength);
} else {
editor.insertText(`${delimiter}${selectedContent}${delimiter}`);
editor.setCursorPosition(cursorPosition + delimiter.length, cursorPosition + delimiter.length + selectedContent.length);
}
};
const hyperlinkHighlightedTest = (editor: EditorRefActions, url?: string) => {
const cursorPosition = editor.getCursorPosition();
const selectedContent = editor.getSelectedContent();
const blankURL = "url";
url = url ?? blankURL;
editor.insertText(`[${selectedContent}](${url})`);
if (url === blankURL) {
const newCursorStart = cursorPosition + selectedContent.length + 3;
editor.setCursorPosition(newCursorStart, newCursorStart + url.length);
}
};
const editorConfig = useMemo(
() => ({
className: editorClassName ?? "",

@ -83,3 +83,12 @@ export const formatBytes = (bytes: number) => {
i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
};
export const isValidUrl = (url: string): boolean => {
try {
new URL(url);
return true;
} catch (err) {
return false;
}
};

Loading…
Cancel
Save