From 8d14f89ce4e54105ee6e021b185ed2ce8fadcffa Mon Sep 17 00:00:00 2001 From: blinko Date: Sun, 10 Nov 2024 12:55:42 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9Efix:=20refactor=20tagPop=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BlinkoEditor/index.tsx | 1 - .../Common/Editor/editorPlugins.tsx | 4 +- src/components/Common/Editor/index.tsx | 51 ++++++++++++++++--- .../Common/MdxPlugin/hashTagPlugin/index.ts | 2 + src/components/Common/TagSelectPop.tsx | 4 +- src/lib/helper.ts | 2 +- src/server/routers/note.ts | 2 +- 7 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/components/BlinkoEditor/index.tsx b/src/components/BlinkoEditor/index.tsx index 884d906b..4b7fba91 100644 --- a/src/components/BlinkoEditor/index.tsx +++ b/src/components/BlinkoEditor/index.tsx @@ -22,7 +22,6 @@ export const BlinkoEditor = observer(({ mode, onSended, onHeightChange }: IProps originFiles={!isCreateMode ? blinko.curSelectedNote?.attachments : []} content={isCreateMode ? blinko.noteContent! : blinko.curSelectedNote?.content!} onChange={v => { - console.log(v, 'onChange is empty??') if (v == '') { onHeightChange?.(editorRef.current?.clientHeight < 90 ? editorRef.current?.clientHeight : 90) } else { diff --git a/src/components/Common/Editor/editorPlugins.tsx b/src/components/Common/Editor/editorPlugins.tsx index ffc546d8..e88b7ae3 100644 --- a/src/components/Common/Editor/editorPlugins.tsx +++ b/src/components/Common/Editor/editorPlugins.tsx @@ -1,7 +1,6 @@ import { codeMirrorPlugin, linkPlugin, sandpackPlugin } from '@mdxeditor/editor'; import { simpleSandpackConfig } from './type'; const { codeBlockPlugin, tablePlugin, listsPlugin, quotePlugin, markdownShortcutPlugin } = await import('@mdxeditor/editor') -import { hashTagPlugin } from '../MdxPlugin/hashTagPlugin'; export const MyPlugins = [ codeBlockPlugin({ defaultCodeBlockLanguage: 'js' }), @@ -11,6 +10,5 @@ export const MyPlugins = [ linkPlugin(), quotePlugin(), tablePlugin(), - markdownShortcutPlugin(), - hashTagPlugin(), + markdownShortcutPlugin() ] \ No newline at end of file diff --git a/src/components/Common/Editor/index.tsx b/src/components/Common/Editor/index.tsx index e1fe8898..7e03b1ab 100644 --- a/src/components/Common/Editor/index.tsx +++ b/src/components/Common/Editor/index.tsx @@ -23,6 +23,7 @@ import { useMediaQuery } from 'usehooks-ts'; import { api } from '@/lib/trpc'; import { NoteType, type Attachment } from '@/server/types'; import { UPLOAD_FILE_PATH } from '@/lib/constant'; +import { showTagSelectPop } from '../TagSelectPop'; const { MDXEditor } = await import('@mdxeditor/editor') // https://mdxeditor.dev/editor/docs/theming @@ -81,20 +82,26 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot, const store = RootStore.Local(() => ({ files: [] as FileType[], + lastRange: null as Range | null, + lastRangeText: '', get canSend() { if (store.files.length == 0) return true return store.files?.every(i => !i?.uploadPromise?.loading?.value) }, replaceMarkdownTag(text) { if (mdxEditorRef.current) { - const Mycontent = mdxEditorRef.current!.getMarkdown().replace(helper.regex.isEndsWithHashTag, "#" + text + ' ') - mdxEditorRef.current.setMarkdown(Mycontent) - mdxEditorRef.current.focus(() => { - setTimeout(() => eventBus.emit('hashpop:hidden'), 100) - onChange?.(Mycontent) - }, { - defaultSelection: 'rootEnd' - }) + if (store.lastRange) { + const selection = window.getSelection(); + const currentTextBeforeRange = store.lastRangeText.replace(/ /g, " ") ?? '' + const currentText = mdxEditorRef.current!.getMarkdown().replace(/\\/g, '').replace(/ /g, " ") + const tag = currentTextBeforeRange.replace(helper.regex.isEndsWithHashTag, "#" + text + ' ') + const MyContent = currentText.replace(currentTextBeforeRange, tag) + mdxEditorRef.current.setMarkdown(MyContent) + onChange?.(MyContent) + mdxEditorRef.current!.focus() + // selection!.removeAllRanges(); + // selection!.addRange(store.lastRange); + } } }, insertMarkdown(text) { @@ -118,6 +125,7 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot, inertHash() { mdxEditorRef.current!.insertMarkdown(" #") mdxEditorRef.current!.focus() + store.handlePopTag() }, async speechToText(filePath) { if (!blinko.showAi) { @@ -166,6 +174,32 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot, lastModified: Date.now(), // 可以指定最后修改时间为当前时间 }); store.uploadFiles([mp3File]) + }, + handlePopTag() { + const selection = window.getSelection(); + if (selection!.rangeCount > 0) { + let lastRange = selection!.getRangeAt(0); + store.lastRange = lastRange + store.lastRangeText = lastRange.endContainer.textContent?.slice(0, lastRange.endOffset) ?? '' + console.log(store.lastRange, 'lastRangeText!!!') + const hasHashTagRegex = /#[^\s#]+/g + const endsWithBankRegex = /\s$/g + const currentText = store.lastRange.startContainer.textContent?.slice(0, store.lastRange.endOffset) ?? '' + const isEndsWithBank = endsWithBankRegex.test(currentText) + const isEndsWithHashTag = helper.regex.isEndsWithHashTag.test(currentText) + if (currentText == '' || !isEndsWithHashTag) { + setTimeout(() => eventBus.emit('hashpop:hidden')) + return + } + if (isEndsWithHashTag && currentText != '' && !isEndsWithBank) { + const match = currentText.match(hasHashTagRegex) + let searchText = match?.[match?.length - 1] ?? '' + if (currentText.endsWith("#")) { + searchText = '' + } + showTagSelectPop(searchText.toLowerCase()) + } + } } })) @@ -221,6 +255,7 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot, contentEditableClassName='prose' onChange={v => { onChange?.(v) + store.handlePopTag() }} autoFocus={{ defaultSelection: 'rootEnd' diff --git a/src/components/Common/MdxPlugin/hashTagPlugin/index.ts b/src/components/Common/MdxPlugin/hashTagPlugin/index.ts index 42ac5d6e..c7498930 100644 --- a/src/components/Common/MdxPlugin/hashTagPlugin/index.ts +++ b/src/components/Common/MdxPlugin/hashTagPlugin/index.ts @@ -7,6 +7,8 @@ import { } from "@mdxeditor/editor"; import { TextNode } from "lexical"; import { showTagSelectPop } from "../../TagSelectPop"; + +//@deprecated export const hashTagPlugin = realmPlugin({ init(realm): void { realm.pubIn({ diff --git a/src/components/Common/TagSelectPop.tsx b/src/components/Common/TagSelectPop.tsx index 4303b236..bb76726e 100644 --- a/src/components/Common/TagSelectPop.tsx +++ b/src/components/Common/TagSelectPop.tsx @@ -32,10 +32,12 @@ const TagSelectPop = observer(() => { height: 200, maxWith: 250, get tagList() { + console.log(store.searchText, store.searchText == '' || !store.searchText) if (store.searchText == '' || !store.searchText) { return blinko.tagList?.value?.pathTags } - return blinko.tagList?.value?.pathTags?.filter(i => i.includes(store.searchText.replace("#", ''))) + console.log(store.searchText, JSON.parse(JSON.stringify(blinko.tagList?.value?.pathTags.map(i => i.toLowerCase())))) + return blinko.tagList?.value?.pathTags.filter(i => i.toLowerCase().includes(store.searchText.toLowerCase().replace("#", ''))) }, hidden() { store.show = false diff --git a/src/lib/helper.ts b/src/lib/helper.ts index caefe457..449e83b0 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -15,7 +15,7 @@ export interface TagTreeNode { export type TagTreeDBNode = Tag & { children?: TagTreeDBNode[]; metadata: { icon: string, path: string } } export const helper = { regex: { - isEndsWithHashTag: /#[\w\u4e00-\u9fa5]*$/, + isEndsWithHashTag: /#[/\w\p{L}\p{N}]*$/u, //lookbehind assertions in ios regex is not supported isContainHashTag: /#[^\s#]*(?:[*?.。]|$)/g }, diff --git a/src/server/routers/note.ts b/src/server/routers/note.ts index e7bb7be1..d7c2384f 100644 --- a/src/server/routers/note.ts +++ b/src/server/routers/note.ts @@ -10,7 +10,7 @@ import { UPLOAD_FILE_PATH } from '@/lib/constant'; import { unlink } from 'fs/promises'; const extractHashtags = (input: string): string[] => { - const hashtagRegex = /#[^\s#]*(?