fix: auto complete in memo editor (#720)

pull/721/head
boojack 2 years ago committed by GitHub
parent 387799b31c
commit ab8c7b9d8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -51,7 +51,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
}; };
return ( return (
<div className={`memo-wrapper archived-memo ${"memos-" + memo.id}`} onMouseLeave={handleMouseLeaveMemoWrapper}> <div className={`memo-wrapper archived ${"memos-" + memo.id}`} onMouseLeave={handleMouseLeaveMemoWrapper}>
<div className="memo-top-wrapper"> <div className="memo-top-wrapper">
<span className="time-text"> <span className="time-text">
{t("common.archived-at")} {utils.getDateTimeString(memo.updatedTs)} {t("common.archived-at")} {utils.getDateTimeString(memo.updatedTs)}

@ -5,6 +5,7 @@ import "../../less/editor.less";
export interface EditorRefActions { export interface EditorRefActions {
focus: FunctionType; focus: FunctionType;
insertText: (text: string, prefix?: string, suffix?: string) => void; insertText: (text: string, prefix?: string, suffix?: string) => void;
removeText: (start: number, length: number) => void;
setContent: (text: string) => void; setContent: (text: string) => void;
getContent: () => string; getContent: () => string;
getSelectedContent: () => string; getSelectedContent: () => string;
@ -67,6 +68,19 @@ const Editor = forwardRef(function Editor(props: Props, ref: React.ForwardedRef<
handleContentChangeCallback(editorRef.current.value); handleContentChangeCallback(editorRef.current.value);
refresh(); refresh();
}, },
removeText: (start: number, length: number) => {
if (!editorRef.current) {
return;
}
const prevValue = editorRef.current.value;
const value = prevValue.slice(0, start) + prevValue.slice(start + length);
editorRef.current.value = value;
editorRef.current.focus();
editorRef.current.selectionEnd = start;
handleContentChangeCallback(editorRef.current.value);
refresh();
},
setContent: (text: string) => { setContent: (text: string) => {
if (editorRef.current) { if (editorRef.current) {
editorRef.current.value = text; editorRef.current.value = text;

@ -1,4 +1,4 @@
import { toLower } from "lodash"; import { last, toLower } from "lodash";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { deleteMemoResource, upsertMemoResource } from "../helpers/api"; import { deleteMemoResource, upsertMemoResource } from "../helpers/api";
@ -14,6 +14,8 @@ import ResourceIcon from "./ResourceIcon";
import showResourcesSelectorDialog from "./ResourcesSelectorDialog"; import showResourcesSelectorDialog from "./ResourcesSelectorDialog";
import "../less/memo-editor.less"; import "../less/memo-editor.less";
const listItemSymbolList = ["* ", "- ", "- [ ] ", "- [x] ", "- [X] "];
const getEditorContentCache = (): string => { const getEditorContentCache = (): string => {
return storage.get(["editorContentCache"]).editorContentCache ?? ""; return storage.get(["editorContentCache"]).editorContentCache ?? "";
}; };
@ -48,7 +50,7 @@ const MemoEditor = () => {
shouldShowEmojiPicker: false, shouldShowEmojiPicker: false,
}); });
const [allowSave, setAllowSave] = useState<boolean>(false); const [allowSave, setAllowSave] = useState<boolean>(false);
const prevGlobalStateRef = useRef(editorState); const prevEditorStateRef = useRef(editorState);
const editorRef = useRef<EditorRefActions>(null); const editorRef = useRef<EditorRefActions>(null);
const tagSelectorRef = useRef<HTMLDivElement>(null); const tagSelectorRef = useRef<HTMLDivElement>(null);
const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => { const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
@ -87,10 +89,14 @@ const MemoEditor = () => {
storage.remove(["editingMemoIdCache"]); storage.remove(["editingMemoIdCache"]);
} }
prevGlobalStateRef.current = editorState; prevEditorStateRef.current = editorState;
}, [editorState.editMemoId]); }, [editorState.editMemoId]);
const handleKeyDown = (event: React.KeyboardEvent) => { const handleKeyDown = (event: React.KeyboardEvent) => {
if (!editorRef.current) {
return;
}
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
if (event.key === "Enter") { if (event.key === "Enter") {
handleSaveBtnClick(); handleSaveBtnClick();
@ -98,39 +104,36 @@ const MemoEditor = () => {
} }
if (event.key === "b") { if (event.key === "b") {
event.preventDefault(); event.preventDefault();
editorRef.current?.insertText("", "**", "**"); editorRef.current.insertText("", "**", "**");
return; return;
} }
if (event.key === "i") { if (event.key === "i") {
event.preventDefault(); event.preventDefault();
editorRef.current?.insertText("", "*", "*"); editorRef.current.insertText("", "*", "*");
return; return;
} }
if (event.key === "e") { if (event.key === "e") {
event.preventDefault(); event.preventDefault();
editorRef.current?.insertText("", "`", "`"); editorRef.current.insertText("", "`", "`");
return; return;
} }
} }
if (event.key === "Enter") { if (event.key === "Enter") {
if (!editorRef.current) {
return;
}
const cursorPosition = editorRef.current.getCursorPosition(); const cursorPosition = editorRef.current.getCursorPosition();
const prevValue = editorRef.current.getContent().slice(0, cursorPosition); const contentBeforeCursor = editorRef.current.getContent().slice(0, cursorPosition);
const prevRows = prevValue.split("\n"); const rowValue = last(contentBeforeCursor.split("\n"));
const prevRowValue = prevRows[prevRows.length - 1]; if (rowValue) {
if (prevRowValue === "- " || prevRowValue === "- [ ] " || prevRowValue === "- [x] " || prevRowValue === "- [X] ") { if (listItemSymbolList.includes(rowValue)) {
event.preventDefault();
prevRows[prevRows.length - 1] = "";
editorRef.current.setContent(prevRows.join("\n"));
} else {
if (prevRowValue.startsWith("- [ ] ") || prevRowValue.startsWith("- [x] ") || prevRowValue.startsWith("- [X] ")) {
event.preventDefault(); event.preventDefault();
editorRef.current.insertText("", "\n- [ ] "); editorRef.current.removeText(cursorPosition - rowValue.length, rowValue.length);
} else if (prevRowValue.startsWith("- ")) { } else {
event.preventDefault(); for (const listItemSymbol of listItemSymbolList) {
editorRef.current.insertText("", "\n- "); if (rowValue.startsWith(listItemSymbol)) {
event.preventDefault();
editorRef.current.insertText("", `\n${listItemSymbol}`);
}
}
} }
} }
return; return;
@ -138,14 +141,14 @@ const MemoEditor = () => {
if (event.key === "Escape") { if (event.key === "Escape") {
if (state.fullscreen) { if (state.fullscreen) {
handleFullscreenBtnClick(); handleFullscreenBtnClick();
} else { } else if (editorState.editMemoId) {
handleCancelEdit(); handleCancelEdit();
} }
return; return;
} }
if (event.key === "Tab") { if (event.key === "Tab") {
event.preventDefault(); event.preventDefault();
editorRef.current?.insertText(" ".repeat(TAB_SPACE_WIDTH)); editorRef.current.insertText(" ".repeat(TAB_SPACE_WIDTH));
return; return;
} }
}; };
@ -251,11 +254,13 @@ const MemoEditor = () => {
}; };
const handleCancelEdit = () => { const handleCancelEdit = () => {
editorStateService.clearEditMemo(); if (editorState.editMemoId) {
editorStateService.clearResourceList(); editorStateService.clearEditMemo();
editorRef.current?.setContent(""); editorStateService.clearResourceList();
setEditorContentCache(""); editorRef.current?.setContent("");
storage.remove(["editingMemoVisibilityCache"]); setEditorContentCache("");
storage.remove(["editingMemoVisibilityCache"]);
}
}; };
const handleContentChange = (content: string) => { const handleContentChange = (content: string) => {

@ -117,20 +117,16 @@ const SystemSection = () => {
<span className="normal-text"> <span className="normal-text">
{t("setting.system-section.database-file-size")}: <span className="font-mono font-medium">{formatBytes(state.dbSize)}</span> {t("setting.system-section.database-file-size")}: <span className="font-mono font-medium">{formatBytes(state.dbSize)}</span>
</span> </span>
<Button size="sm" onClick={handleVacuumBtnClick}> <Button onClick={handleVacuumBtnClick}>{t("common.vacuum")}</Button>
{t("common.vacuum")}
</Button>
</label> </label>
<p className="title-text">{t("sidebar.setting")}</p> <p className="title-text">{t("sidebar.setting")}</p>
<label className="form-label"> <label className="form-label">
<span className="normal-text">{t("setting.system-section.allow-user-signup")}</span> <span className="normal-text">{t("setting.system-section.allow-user-signup")}</span>
<Switch size="sm" checked={state.allowSignUp} onChange={(event) => handleAllowSignUpChanged(event.target.checked)} /> <Switch checked={state.allowSignUp} onChange={(event) => handleAllowSignUpChanged(event.target.checked)} />
</label> </label>
<div className="form-label"> <div className="form-label">
<span className="normal-text">{t("setting.system-section.additional-style")}</span> <span className="normal-text">{t("setting.system-section.additional-style")}</span>
<Button size="sm" onClick={handleSaveAdditionalStyle}> <Button onClick={handleSaveAdditionalStyle}>{t("common.save")}</Button>
{t("common.save")}
</Button>
</div> </div>
<Textarea <Textarea
className="w-full" className="w-full"
@ -139,16 +135,14 @@ const SystemSection = () => {
fontSize: "14px", fontSize: "14px",
}} }}
minRows={4} minRows={4}
maxRows={10} maxRows={4}
placeholder={t("setting.system-section.additional-style-placeholder")} placeholder={t("setting.system-section.additional-style-placeholder")}
value={state.additionalStyle} value={state.additionalStyle}
onChange={(event) => handleAdditionalStyleChanged(event.target.value)} onChange={(event) => handleAdditionalStyleChanged(event.target.value)}
/> />
<div className="form-label mt-2"> <div className="form-label mt-2">
<span className="normal-text">{t("setting.system-section.additional-script")}</span> <span className="normal-text">{t("setting.system-section.additional-script")}</span>
<Button size="sm" onClick={handleSaveAdditionalScript}> <Button onClick={handleSaveAdditionalScript}>{t("common.save")}</Button>
{t("common.save")}
</Button>
</div> </div>
<Textarea <Textarea
className="w-full" className="w-full"
@ -158,7 +152,7 @@ const SystemSection = () => {
fontSize: "14px", fontSize: "14px",
}} }}
minRows={4} minRows={4}
maxRows={10} maxRows={4}
placeholder={t("setting.system-section.additional-script-placeholder")} placeholder={t("setting.system-section.additional-script-placeholder")}
value={state.additionalScript} value={state.additionalScript}
onChange={(event) => handleAdditionalScriptChanged(event.target.value)} onChange={(event) => handleAdditionalScriptChanged(event.target.value)}

@ -5,6 +5,10 @@
@apply border-gray-200 border-2 dark:border-zinc-600; @apply border-gray-200 border-2 dark:border-zinc-600;
} }
&.archived {
@apply border-gray-200 dark:border-zinc-600;
}
> .corner-container { > .corner-container {
@apply absolute top-0 right-0 z-1; @apply absolute top-0 right-0 z-1;

Loading…
Cancel
Save