chore: simplify memo editor component (#1079)

This commit is contained in:
boojack 2023-02-12 16:34:42 +08:00 committed by GitHub
parent c28d35d8f7
commit a997e1d10d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 115 deletions

View File

@ -31,7 +31,7 @@ const CreateTagDialog: React.FC<Props> = (props: Props) => {
getTagSuggestionList().then(({ data }) => { getTagSuggestionList().then(({ data }) => {
setSuggestTagNameList(data.data.filter((tag) => validateTagName(tag))); setSuggestTagNameList(data.data.filter((tag) => validateTagName(tag)));
}); });
}, []); }, [tagNameList]);
const handleTagNameInputKeyDown = (event: React.KeyboardEvent) => { const handleTagNameInputKeyDown = (event: React.KeyboardEvent) => {
if (event.key === "Enter") { if (event.key === "Enter") {

View File

@ -17,7 +17,6 @@ import "../less/memo-editor.less";
const listItemSymbolList = ["- [ ] ", "- [x] ", "- [X] ", "* ", "- "]; const listItemSymbolList = ["- [ ] ", "- [x] ", "- [X] ", "* ", "- "];
const emptyOlReg = /^(\d+)\. $/; const emptyOlReg = /^(\d+)\. $/;
const pairSymbols = ["[]", "()", '""', "''", "{}", "``", "”“", "", "【】", "", "《》"];
const getEditorContentCache = (): string => { const getEditorContentCache = (): string => {
return storage.get(["editorContentCache"]).editorContentCache ?? ""; return storage.get(["editorContentCache"]).editorContentCache ?? "";
@ -29,12 +28,6 @@ const setEditorContentCache = (content: string) => {
}); });
}; };
const setEditingMemoVisibilityCache = (visibility: Visibility) => {
storage.set({
editingMemoVisibilityCache: visibility,
});
};
interface State { interface State {
fullscreen: boolean; fullscreen: boolean;
isUploadingResource: boolean; isUploadingResource: boolean;
@ -51,8 +44,8 @@ const MemoEditor = () => {
const resourceStore = useResourceStore(); const resourceStore = useResourceStore();
const [state, setState] = useState<State>({ const [state, setState] = useState<State>({
isUploadingResource: false,
fullscreen: false, fullscreen: false,
isUploadingResource: false,
isRequesting: false, isRequesting: false,
}); });
const [allowSave, setAllowSave] = useState<boolean>(false); const [allowSave, setAllowSave] = useState<boolean>(false);
@ -62,7 +55,6 @@ const MemoEditor = () => {
const tagSelectorRef = useRef<HTMLDivElement>(null); const tagSelectorRef = useRef<HTMLDivElement>(null);
const user = userStore.state.user as User; const user = userStore.state.user as User;
const setting = user.setting; const setting = user.setting;
const localSetting = user.localSetting;
const tags = tagStore.state.tags; const tags = tagStore.state.tags;
const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => { const memoVisibilityOptionSelectorItems = VISIBILITY_SELECTOR_ITEMS.map((item) => {
return { return {
@ -72,12 +64,9 @@ const MemoEditor = () => {
}); });
useEffect(() => { useEffect(() => {
const { editingMemoIdCache, editingMemoVisibilityCache } = storage.get(["editingMemoIdCache", "editingMemoVisibilityCache"]); const { editingMemoIdCache } = storage.get(["editingMemoIdCache"]);
if (editingMemoIdCache) { if (editingMemoIdCache) {
editorStore.setEditMemoWithId(editingMemoIdCache); editorStore.setEditMemoWithId(editingMemoIdCache);
}
if (editingMemoVisibilityCache) {
editorStore.setMemoVisibility(editingMemoVisibilityCache as "PUBLIC" | "PROTECTED" | "PRIVATE");
} else { } else {
editorStore.setMemoVisibility(setting.memoVisibility); editorStore.setMemoVisibility(setting.memoVisibility);
} }
@ -109,8 +98,7 @@ const MemoEditor = () => {
} }
const isMetaKey = event.ctrlKey || event.metaKey; const isMetaKey = event.ctrlKey || event.metaKey;
const isShiftKey = event.shiftKey; if (isMetaKey) {
if (!isShiftKey && isMetaKey) {
if (event.key === "Enter") { if (event.key === "Enter") {
handleSaveBtnClick(); handleSaveBtnClick();
return; return;
@ -141,8 +129,7 @@ const MemoEditor = () => {
} }
} }
} }
if (event.key === "Enter") {
if (!isShiftKey && event.key === "Enter") {
const cursorPosition = editorRef.current.getCursorPosition(); const cursorPosition = editorRef.current.getCursorPosition();
const contentBeforeCursor = editorRef.current.getContent().slice(0, cursorPosition); const contentBeforeCursor = editorRef.current.getContent().slice(0, cursorPosition);
const rowValue = last(contentBeforeCursor.split("\n")); const rowValue = last(contentBeforeCursor.split("\n"));
@ -179,7 +166,7 @@ const MemoEditor = () => {
} }
return; return;
} }
if (!isShiftKey && event.key === "Escape") { if (event.key === "Escape") {
if (state.fullscreen) { if (state.fullscreen) {
handleFullscreenBtnClick(); handleFullscreenBtnClick();
} }
@ -190,57 +177,37 @@ const MemoEditor = () => {
const tabSpace = " ".repeat(TAB_SPACE_WIDTH); const tabSpace = " ".repeat(TAB_SPACE_WIDTH);
const cursorPosition = editorRef.current.getCursorPosition(); const cursorPosition = editorRef.current.getCursorPosition();
const selectedContent = editorRef.current.getSelectedContent(); const selectedContent = editorRef.current.getSelectedContent();
if (isShiftKey) {
const beforeContent = editorRef.current.getContent().slice(0, cursorPosition);
for (let i = beforeContent.length - 1; i >= 0; i--) {
if (beforeContent[i] !== "\n") {
continue;
}
const rowStart = i + 1;
const isTabSpace = beforeContent.substring(rowStart, i + TAB_SPACE_WIDTH + 1) === tabSpace;
const isSpace = beforeContent.substring(rowStart, i + 2) === " ";
if (!isTabSpace && !isSpace) {
break;
}
const removeLength = isTabSpace ? TAB_SPACE_WIDTH : 1;
editorRef.current.removeText(rowStart, removeLength);
const startPos = cursorPosition - removeLength;
let endPos = startPos;
if (selectedContent) {
endPos += selectedContent.length;
}
editorRef.current.setCursorPosition(startPos, endPos);
}
return;
} else {
editorRef.current.insertText(tabSpace); editorRef.current.insertText(tabSpace);
if (selectedContent) { if (selectedContent) {
editorRef.current.setCursorPosition(cursorPosition + TAB_SPACE_WIDTH); editorRef.current.setCursorPosition(cursorPosition + TAB_SPACE_WIDTH);
} }
return; return;
} }
};
const handleUploadResource = async (file: File) => {
setState((state) => {
return {
...state,
isUploadingResource: true,
};
});
let resource = undefined;
try {
resource = await resourceStore.createResourceWithBlob(file);
} catch (error: any) {
console.error(error);
toastHelper.error(error.response.data.message);
} }
if (localSetting.enablePowerfulEditor) { setState((state) => {
for (const symbol of pairSymbols) { return {
if (event.key === symbol[0]) { ...state,
event.preventDefault(); isUploadingResource: false,
editorRef.current.insertText("", symbol[0], symbol[1]); };
return; });
} return resource;
}
if (event.key === "Backspace") {
const cursor = editorRef.current.getCursorPosition();
const content = editorRef.current.getContent();
const deleteChar = content?.slice(cursor - 1, cursor);
const nextChar = content?.slice(cursor, cursor + 1);
if (pairSymbols.includes(`${deleteChar}${nextChar}`)) {
event.preventDefault();
editorRef.current.removeText(cursor - 1, 2);
}
return;
}
}
}; };
const uploadMultiFiles = async (files: FileList) => { const uploadMultiFiles = async (files: FileList) => {
@ -274,32 +241,6 @@ const MemoEditor = () => {
} }
}; };
const handleUploadResource = async (file: File) => {
setState((state) => {
return {
...state,
isUploadingResource: true,
};
});
let resource = undefined;
try {
resource = await resourceStore.createResourceWithBlob(file);
} catch (error: any) {
console.error(error);
toastHelper.error(error.response.data.message);
}
setState((state) => {
return {
...state,
isUploadingResource: false,
};
});
return resource;
};
const scrollToEditingMemo = useCallback(() => { const scrollToEditingMemo = useCallback(() => {
if (editorState.editMemoId) { if (editorState.editMemoId) {
const memoElements = document.getElementsByClassName(`memos-${editorState.editMemoId}`); const memoElements = document.getElementsByClassName(`memos-${editorState.editMemoId}`);
@ -369,9 +310,7 @@ const MemoEditor = () => {
}); });
editorStore.clearResourceList(); editorStore.clearResourceList();
setEditorContentCache(""); setEditorContentCache("");
storage.remove(["editingMemoVisibilityCache"]);
editorRef.current?.setContent(""); editorRef.current?.setContent("");
scrollToEditingMemo(); scrollToEditingMemo();
}; };
@ -381,10 +320,8 @@ const MemoEditor = () => {
editorStore.clearResourceList(); editorStore.clearResourceList();
editorRef.current?.setContent(""); editorRef.current?.setContent("");
setEditorContentCache(""); setEditorContentCache("");
storage.remove(["editingMemoVisibilityCache"]);
}
scrollToEditingMemo(); scrollToEditingMemo();
}
}; };
const handleContentChange = (content: string) => { const handleContentChange = (content: string) => {
@ -439,11 +376,8 @@ const MemoEditor = () => {
}); });
}; };
const handleTagSelectorClick = useCallback((event: React.MouseEvent) => { const handleTagSelectorClick = useCallback((tag: string) => {
if (tagSelectorRef.current !== event.target && tagSelectorRef.current?.contains(event.target as Node)) { editorRef.current?.insertText(`#${tag} `);
editorRef.current?.insertText(`#${(event.target as HTMLElement).textContent} ` ?? "");
editorRef.current?.scrollToCursor();
}
}, []); }, []);
const handleDeleteResource = async (resourceId: ResourceId) => { const handleDeleteResource = async (resourceId: ResourceId) => {
@ -456,7 +390,6 @@ const MemoEditor = () => {
const handleMemoVisibilityOptionChanged = async (value: string) => { const handleMemoVisibilityOptionChanged = async (value: string) => {
const visibilityValue = value as Visibility; const visibilityValue = value as Visibility;
editorStore.setMemoVisibility(visibilityValue); editorStore.setMemoVisibility(visibilityValue);
setEditingMemoVisibilityCache(visibilityValue);
}; };
const handleEditorFocus = () => { const handleEditorFocus = () => {
@ -495,12 +428,12 @@ const MemoEditor = () => {
<div className="common-tools-container"> <div className="common-tools-container">
<div className="action-btn tag-action"> <div className="action-btn tag-action">
<Icon.Hash className="icon-img" /> <Icon.Hash className="icon-img" />
<div ref={tagSelectorRef} className="tag-list" onClick={handleTagSelectorClick}> <div ref={tagSelectorRef} className="tag-list">
{tags.length > 0 ? ( {tags.length > 0 ? (
tags.map((tag) => { tags.map((tag) => {
return ( return (
<span className="item-container" key={tag}> <span className="item-container" onClick={() => handleTagSelectorClick(tag)} key={tag}>
{tag} #{tag}
</span> </span>
); );
}) })

View File

@ -16,7 +16,7 @@ const MemoResource: React.FC<Props> = (props: Props) => {
return ( return (
<> <>
<div className={`w-auto flex flex-row justify-start items-center ${className}`}> <div className={`w-auto flex flex-row justify-start items-center hover:opacity-80 ${className}`}>
{resource.type.startsWith("audio") ? ( {resource.type.startsWith("audio") ? (
<> <>
<audio className="h-8" src={resourceUrl} controls></audio> <audio className="h-8" src={resourceUrl} controls></audio>
@ -24,7 +24,7 @@ const MemoResource: React.FC<Props> = (props: Props) => {
) : ( ) : (
<> <>
<Icon.FileText className="w-4 h-auto mr-1 text-gray-500" /> <Icon.FileText className="w-4 h-auto mr-1 text-gray-500" />
<span className="text-gray-500 text-sm max-w-xs truncate font-mono cursor-pointer" onClick={handlePreviewBtnClick}> <span className="text-gray-500 text-sm max-w-[256px] truncate font-mono cursor-pointer" onClick={handlePreviewBtnClick}>
{resource.filename} {resource.filename}
</span> </span>
</> </>

View File

@ -6,8 +6,6 @@ interface StorageData {
editorContentCache: string; editorContentCache: string;
// Editing memo id cache // Editing memo id cache
editingMemoIdCache: MemoId; editingMemoIdCache: MemoId;
// Editing memo visibility
editingMemoVisibilityCache: Visibility;
// locale // locale
locale: Locale; locale: Locale;
// appearance // appearance

View File

@ -37,7 +37,7 @@
@apply flex flex-row justify-start items-center; @apply flex flex-row justify-start items-center;
> .action-btn { > .action-btn {
@apply flex flex-row justify-center items-center p-1 w-auto h-auto mr-1 select-none rounded cursor-pointer dark:text-gray-200 opacity-60 hover:opacity-90 hover:bg-gray-300 dark:hover:bg-zinc-800 hover:shadow; @apply flex flex-row justify-center items-center p-1 w-auto h-auto mr-1 select-none rounded cursor-pointer text-gray-600 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-zinc-800 hover:shadow;
&.tag-action { &.tag-action {
@apply relative; @apply relative;
@ -49,14 +49,14 @@
} }
> .tag-list { > .tag-list {
@apply hidden flex-col justify-start items-start absolute top-6 left-0 mt-1 p-1 z-1 rounded w-36 max-h-52 overflow-auto font-mono bg-black; @apply hidden flex-row justify-start items-start flex-wrap absolute top-6 left-0 mt-1 p-1 z-1 rounded w-52 h-auto max-h-48 overflow-y-auto font-mono shadow bg-zinc-200 dark:bg-zinc-600;
> .item-container { > .item-container {
@apply w-full text-white cursor-pointer rounded text-sm leading-6 px-2 truncate hover:bg-gray-700 shrink-0; @apply w-auto max-w-full truncate text-black dark:text-gray-300 cursor-pointer rounded text-sm leading-6 px-2 truncate hover:bg-zinc-300 dark:hover:bg-zinc-700 shrink-0;
} }
> .tip-text { > .tip-text {
@apply w-full text-sm text-gray-200 leading-6 px-2 cursor-default; @apply w-auto text-sm text-gray-200 leading-6 px-2 cursor-default;
} }
} }
} }