From b6b1b5249f8a05d50c2d0fa1aefabcbf687ce5ca Mon Sep 17 00:00:00 2001 From: Zeng1998 <1129142694@qq.com> Date: Mon, 21 Nov 2022 15:56:08 +0800 Subject: [PATCH] feat: highlight the searched text --- web/src/components/Memo.tsx | 4 +++- web/src/components/MemoContent.tsx | 5 +++-- web/src/components/MemoList.tsx | 4 +++- web/src/labs/marked/index.ts | 15 ++++++++++++--- web/src/labs/marked/parser/Blockquote.ts | 7 +++++-- web/src/labs/marked/parser/Bold.ts | 7 ++++--- web/src/labs/marked/parser/BoldEmphasis.ts | 7 ++++--- web/src/labs/marked/parser/CodeBlock.ts | 5 ++++- web/src/labs/marked/parser/DoneList.ts | 4 ++-- web/src/labs/marked/parser/Emphasis.ts | 7 ++++--- web/src/labs/marked/parser/InlineCode.ts | 5 +++-- web/src/labs/marked/parser/Link.ts | 10 +++++++--- web/src/labs/marked/parser/OrderedList.ts | 4 ++-- web/src/labs/marked/parser/Paragraph.ts | 5 ++--- web/src/labs/marked/parser/PlainLink.ts | 8 ++++++-- web/src/labs/marked/parser/PlainText.ts | 5 +++-- web/src/labs/marked/parser/Table.ts | 8 +++++--- web/src/labs/marked/parser/Tag.ts | 5 +++-- web/src/labs/marked/parser/TodoList.ts | 4 ++-- web/src/labs/marked/parser/UnorderedList.ts | 4 ++-- web/src/labs/marked/parser/index.ts | 1 + web/src/labs/marked/parser/utils.ts | 7 +++++++ web/src/less/memo.less | 4 ++++ 23 files changed, 91 insertions(+), 44 deletions(-) create mode 100644 web/src/labs/marked/parser/utils.ts diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index 25f05bc10..c6d6dae0b 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -18,6 +18,7 @@ dayjs.extend(relativeTime); interface Props { memo: Memo; + highlightWord: string | undefined; } export const getFormatedMemoTimeStr = (time: number, locale = "en"): string => { @@ -29,7 +30,7 @@ export const getFormatedMemoTimeStr = (time: number, locale = "en"): string => { }; const Memo: React.FC = (props: Props) => { - const memo = props.memo; + const { memo, highlightWord } = props; const { t, i18n } = useTranslation(); const navigate = useNavigate(); const [displayTimeStr, setDisplayTimeStr] = useState(getFormatedMemoTimeStr(memo.displayTs, i18n.language)); @@ -232,6 +233,7 @@ const Memo: React.FC = (props: Props) => { diff --git a/web/src/components/MemoContent.tsx b/web/src/components/MemoContent.tsx index 249dd88b9..3714798eb 100644 --- a/web/src/components/MemoContent.tsx +++ b/web/src/components/MemoContent.tsx @@ -12,6 +12,7 @@ export interface DisplayConfig { interface Props { content: string; + highlightWord: string | undefined; className?: string; displayConfig?: Partial; onMemoContentClick?: (e: React.MouseEvent) => void; @@ -29,7 +30,7 @@ const defaultDisplayConfig: DisplayConfig = { }; const MemoContent: React.FC = (props: Props) => { - const { className, content, onMemoContentClick, onMemoContentDoubleClick } = props; + const { className, content, highlightWord, onMemoContentClick, onMemoContentDoubleClick } = props; const foldedContent = useMemo(() => { const firstHorizontalRuleIndex = content.search(/^---$|^\*\*\*$|^___$/m); return firstHorizontalRuleIndex !== -1 ? content.slice(0, firstHorizontalRuleIndex) : content; @@ -86,7 +87,7 @@ const MemoContent: React.FC = (props: Props) => { className={`memo-content-text ${state.expandButtonStatus === 0 ? "expanded" : ""}`} onClick={handleMemoContentClick} onDoubleClick={handleMemoContentDoubleClick} - dangerouslySetInnerHTML={{ __html: marked(state.expandButtonStatus === 0 ? foldedContent : content) }} + dangerouslySetInnerHTML={{ __html: marked(state.expandButtonStatus === 0 ? foldedContent : content, highlightWord) }} > {state.expandButtonStatus !== -1 && (
diff --git a/web/src/components/MemoList.tsx b/web/src/components/MemoList.tsx index 161cf3143..ab285c84b 100644 --- a/web/src/components/MemoList.tsx +++ b/web/src/components/MemoList.tsx @@ -20,6 +20,7 @@ const MemoList = () => { const { tag: tagQuery, duration, type: memoType, text: textQuery, shortcutId, visibility } = query ?? {}; const shortcut = shortcutId ? shortcutService.getShortcutById(shortcutId) : null; const showMemoFilter = Boolean(tagQuery || (duration && duration.from < duration.to) || memoType || textQuery || shortcut || visibility); + const [highlightWord, setHighlightWord] = useState(""); const shownMemos = showMemoFilter || shortcut @@ -103,6 +104,7 @@ const MemoList = () => { if (pageWrapper) { pageWrapper.scrollTo(0, 0); } + setHighlightWord(textQuery?.toLowerCase()); }, [query]); useEffect(() => { @@ -131,7 +133,7 @@ const MemoList = () => { return (
{sortedMemos.map((memo) => ( - + ))} {isFetching ? (
diff --git a/web/src/labs/marked/index.ts b/web/src/labs/marked/index.ts index 24473a96c..3b0849682 100644 --- a/web/src/labs/marked/index.ts +++ b/web/src/labs/marked/index.ts @@ -10,7 +10,12 @@ const match = (rawStr: string, regex: RegExp): number => { return matchStr.length; }; -export const marked = (markdownStr: string, blockParsers = blockElementParserList, inlineParsers = inlineElementParserList): string => { +export const marked = ( + markdownStr: string, + highlightWord: string | undefined, + blockParsers = blockElementParserList, + inlineParsers = inlineElementParserList +): string => { for (const parser of blockParsers) { const startIndex = markdownStr.search(parser.regex); const matchedLength = match(markdownStr, parser.regex); @@ -19,7 +24,11 @@ export const marked = (markdownStr: string, blockParsers = blockElementParserLis const prefixStr = markdownStr.slice(0, startIndex); const matchedStr = markdownStr.slice(startIndex, startIndex + matchedLength); const suffixStr = markdownStr.slice(startIndex + matchedLength); - return marked(prefixStr, blockParsers, inlineParsers) + parser.renderer(matchedStr) + marked(suffixStr, blockParsers, inlineParsers); + return ( + marked(prefixStr, highlightWord, blockParsers, inlineParsers) + + parser.renderer(matchedStr, highlightWord) + + marked(suffixStr, highlightWord, blockParsers, inlineParsers) + ); } } @@ -47,7 +56,7 @@ export const marked = (markdownStr: string, blockParsers = blockElementParserLis const prefixStr = markdownStr.slice(0, matchedIndex); const matchedStr = markdownStr.slice(matchedIndex, matchedIndex + matchedLength); const suffixStr = markdownStr.slice(matchedIndex + matchedLength); - return prefixStr + matchedInlineParser.renderer(matchedStr) + marked(suffixStr, [], inlineParsers); + return prefixStr + matchedInlineParser.renderer(matchedStr, highlightWord) + marked(suffixStr, highlightWord, [], inlineParsers); } return markdownStr; diff --git a/web/src/labs/marked/parser/Blockquote.ts b/web/src/labs/marked/parser/Blockquote.ts index 6b172f5d1..e7b29be62 100644 --- a/web/src/labs/marked/parser/Blockquote.ts +++ b/web/src/labs/marked/parser/Blockquote.ts @@ -1,14 +1,17 @@ import { escape } from "lodash"; +import { renderWithHighlightWord } from "./utils"; export const BLOCKQUOTE_REG = /^>\s+(.+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(BLOCKQUOTE_REG); if (!matchResult) { return rawStr; } - return `
${escape(matchResult[1])}
${matchResult[2]}`; + const result = renderWithHighlightWord(escape(matchResult[1]), highlightWord); + + return `
${result}
${matchResult[2]}`; }; export default { diff --git a/web/src/labs/marked/parser/Bold.ts b/web/src/labs/marked/parser/Bold.ts index 1a4083a93..5ab19a3b2 100644 --- a/web/src/labs/marked/parser/Bold.ts +++ b/web/src/labs/marked/parser/Bold.ts @@ -1,16 +1,17 @@ import { marked } from ".."; import Link from "./Link"; +import { renderWithHighlightWord } from "./utils"; export const BOLD_REG = /\*\*(.+?)\*\*/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(BOLD_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], [Link]); - return `${parsedContent}`; + const parsedContent = marked(matchResult[1], highlightWord, [], [Link]); + return `${renderWithHighlightWord(parsedContent, highlightWord)}`; }; export default { diff --git a/web/src/labs/marked/parser/BoldEmphasis.ts b/web/src/labs/marked/parser/BoldEmphasis.ts index 6d5e73613..5342c66ee 100644 --- a/web/src/labs/marked/parser/BoldEmphasis.ts +++ b/web/src/labs/marked/parser/BoldEmphasis.ts @@ -1,16 +1,17 @@ import { marked } from ".."; import Link from "./Link"; +import { renderWithHighlightWord } from "./utils"; export const BOLD_EMPHASIS_REG = /\*\*\*(.+?)\*\*\*/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(BOLD_EMPHASIS_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], [Link]); - return `${parsedContent}`; + const parsedContent = marked(matchResult[1], highlightWord, [], [Link]); + return `${renderWithHighlightWord(parsedContent, highlightWord)}`; }; export default { diff --git a/web/src/labs/marked/parser/CodeBlock.ts b/web/src/labs/marked/parser/CodeBlock.ts index 52e945401..81a9c5223 100644 --- a/web/src/labs/marked/parser/CodeBlock.ts +++ b/web/src/labs/marked/parser/CodeBlock.ts @@ -1,9 +1,10 @@ import { escape } from "lodash-es"; import hljs from "highlight.js"; +import { renderWithHighlightWord } from "./utils"; export const CODE_BLOCK_REG = /^```(\S*?)\s([\s\S]*?)```(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(CODE_BLOCK_REG); if (!matchResult) { return rawStr; @@ -21,6 +22,8 @@ const renderer = (rawStr: string): string => { // do nth } + highlightedCode = renderWithHighlightWord(highlightedCode, highlightWord); + return `
${highlightedCode}
${matchResult[3]}`; }; diff --git a/web/src/labs/marked/parser/DoneList.ts b/web/src/labs/marked/parser/DoneList.ts index e366f3ab6..a9a303002 100644 --- a/web/src/labs/marked/parser/DoneList.ts +++ b/web/src/labs/marked/parser/DoneList.ts @@ -3,13 +3,13 @@ import { marked } from ".."; export const DONE_LIST_REG = /^- \[x\] (.+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(DONE_LIST_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], inlineElementParserList); + const parsedContent = marked(matchResult[1], highlightWord, [], inlineElementParserList); return `

${parsedContent}

${matchResult[2]}`; }; diff --git a/web/src/labs/marked/parser/Emphasis.ts b/web/src/labs/marked/parser/Emphasis.ts index f51e7c634..8186e6bdc 100644 --- a/web/src/labs/marked/parser/Emphasis.ts +++ b/web/src/labs/marked/parser/Emphasis.ts @@ -1,16 +1,17 @@ import { marked } from ".."; import Link from "./Link"; +import { renderWithHighlightWord } from "./utils"; export const EMPHASIS_REG = /\*(.+?)\*/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(EMPHASIS_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], [Link]); - return `${parsedContent}`; + const parsedContent = marked(matchResult[1], highlightWord, [], [Link]); + return `${renderWithHighlightWord(parsedContent, highlightWord)}`; }; export default { diff --git a/web/src/labs/marked/parser/InlineCode.ts b/web/src/labs/marked/parser/InlineCode.ts index 4c40fbe8d..febb846df 100644 --- a/web/src/labs/marked/parser/InlineCode.ts +++ b/web/src/labs/marked/parser/InlineCode.ts @@ -1,14 +1,15 @@ import { escape } from "lodash-es"; +import { renderWithHighlightWord } from "./utils"; export const INLINE_CODE_REG = /`(.+?)`/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(INLINE_CODE_REG); if (!matchResult) { return rawStr; } - return `${escape(matchResult[1])}`; + return `${renderWithHighlightWord(escape(matchResult[1]), highlightWord)}`; }; export default { diff --git a/web/src/labs/marked/parser/Link.ts b/web/src/labs/marked/parser/Link.ts index e25b8142c..614588305 100644 --- a/web/src/labs/marked/parser/Link.ts +++ b/web/src/labs/marked/parser/Link.ts @@ -4,16 +4,20 @@ import Bold from "./Bold"; import { marked } from ".."; import InlineCode from "./InlineCode"; import BoldEmphasis from "./BoldEmphasis"; +import { renderWithHighlightWord } from "./utils"; export const LINK_REG = /\[(.*?)\]\((.+?)\)+/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(LINK_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], [InlineCode, BoldEmphasis, Emphasis, Bold]); - return `${parsedContent}`; + const parsedContent = marked(matchResult[1], highlightWord, [], [InlineCode, BoldEmphasis, Emphasis, Bold]); + return `${renderWithHighlightWord( + parsedContent, + highlightWord + )}`; }; export default { diff --git a/web/src/labs/marked/parser/OrderedList.ts b/web/src/labs/marked/parser/OrderedList.ts index fdc658cec..fdfa1a70f 100644 --- a/web/src/labs/marked/parser/OrderedList.ts +++ b/web/src/labs/marked/parser/OrderedList.ts @@ -3,13 +3,13 @@ import { marked } from ".."; export const ORDERED_LIST_REG = /^(\d+)\. (.+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(ORDERED_LIST_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[2], [], inlineElementParserList); + const parsedContent = marked(matchResult[2], highlightWord, [], inlineElementParserList); return `

${matchResult[1]}.${parsedContent}

${matchResult[3]}`; }; diff --git a/web/src/labs/marked/parser/Paragraph.ts b/web/src/labs/marked/parser/Paragraph.ts index a4e7b0f76..150b6f5e3 100644 --- a/web/src/labs/marked/parser/Paragraph.ts +++ b/web/src/labs/marked/parser/Paragraph.ts @@ -3,13 +3,12 @@ import { marked } from ".."; export const PARAGRAPH_REG = /^(.*)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(PARAGRAPH_REG); if (!matchResult) { return rawStr; } - - const parsedContent = marked(matchResult[1], [], inlineElementParserList); + const parsedContent = marked(matchResult[1], highlightWord, [], inlineElementParserList); return `

${parsedContent}

${matchResult[2]}`; }; diff --git a/web/src/labs/marked/parser/PlainLink.ts b/web/src/labs/marked/parser/PlainLink.ts index 73d8265ec..ee47093dd 100644 --- a/web/src/labs/marked/parser/PlainLink.ts +++ b/web/src/labs/marked/parser/PlainLink.ts @@ -1,14 +1,18 @@ import { escape } from "lodash-es"; +import { renderWithHighlightWord } from "./utils"; export const PLAIN_LINK_REG = /(https?:\/\/[^ ]+)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(PLAIN_LINK_REG); if (!matchResult) { return rawStr; } - return `${escape(matchResult[1])}`; + return `${renderWithHighlightWord( + escape(matchResult[1]), + highlightWord + )}`; }; export default { diff --git a/web/src/labs/marked/parser/PlainText.ts b/web/src/labs/marked/parser/PlainText.ts index bb3fba3e8..076620a24 100644 --- a/web/src/labs/marked/parser/PlainText.ts +++ b/web/src/labs/marked/parser/PlainText.ts @@ -1,14 +1,15 @@ import { escape } from "lodash-es"; +import { renderWithHighlightWord } from "./utils"; export const PLAIN_TEXT_REG = /(.+)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(PLAIN_TEXT_REG); if (!matchResult) { return rawStr; } - return `${escape(matchResult[1])}`; + return `${renderWithHighlightWord(escape(matchResult[1]), highlightWord)}`; }; export default { diff --git a/web/src/labs/marked/parser/Table.ts b/web/src/labs/marked/parser/Table.ts index e267a3cd1..ccbbe38ad 100644 --- a/web/src/labs/marked/parser/Table.ts +++ b/web/src/labs/marked/parser/Table.ts @@ -6,9 +6,11 @@ * | 1 | 2 | 3 | * | 4 | 5 | 6 | */ +import { renderWithHighlightWord } from "./utils"; + export const TABLE_REG = /^(\|.*\|)(?:(?:\n(?:\|-*)+\|))((?:\n\|.*\|)+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(TABLE_REG); if (!matchResult) { return rawStr; @@ -29,11 +31,11 @@ const renderer = (rawStr: string): string => { return ` - ${tableHeader.map((str) => ``).join("")} + ${tableHeader.map((str) => ``).join("")} - ${tableBody.map((row) => `${row.map((str) => ``).join("")}`).join("")} + ${tableBody.map((row) => `${row.map((str) => ``).join("")}`).join("")}
${str}${renderWithHighlightWord(str, highlightWord)}
${str}
${renderWithHighlightWord(str, highlightWord)}
${matchResult[3]}`; }; diff --git a/web/src/labs/marked/parser/Tag.ts b/web/src/labs/marked/parser/Tag.ts index 93ce49c63..1410043b0 100644 --- a/web/src/labs/marked/parser/Tag.ts +++ b/web/src/labs/marked/parser/Tag.ts @@ -1,14 +1,15 @@ import { escape } from "lodash-es"; +import { renderWithHighlightWord } from "./utils"; export const TAG_REG = /#([^\s#]+?) /; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(TAG_REG); if (!matchResult) { return rawStr; } - return `#${escape(matchResult[1])} `; + return `#${renderWithHighlightWord(escape(matchResult[1]), highlightWord)} `; }; export default { diff --git a/web/src/labs/marked/parser/TodoList.ts b/web/src/labs/marked/parser/TodoList.ts index 06302576f..252c3a7dd 100644 --- a/web/src/labs/marked/parser/TodoList.ts +++ b/web/src/labs/marked/parser/TodoList.ts @@ -4,13 +4,13 @@ import { marked } from ".."; export const TODO_LIST_REG = /^- \[ \] (.+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(TODO_LIST_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], inlineElementParserList); + const parsedContent = marked(matchResult[1], highlightWord, [], inlineElementParserList); return `

${parsedContent}

${escape(matchResult[2])}`; }; diff --git a/web/src/labs/marked/parser/UnorderedList.ts b/web/src/labs/marked/parser/UnorderedList.ts index 185979d91..984de76df 100644 --- a/web/src/labs/marked/parser/UnorderedList.ts +++ b/web/src/labs/marked/parser/UnorderedList.ts @@ -4,13 +4,13 @@ import { marked } from ".."; export const UNORDERED_LIST_REG = /^[*-] (.+)(\n?)/; -const renderer = (rawStr: string): string => { +const renderer = (rawStr: string, highlightWord: string | undefined): string => { const matchResult = rawStr.match(UNORDERED_LIST_REG); if (!matchResult) { return rawStr; } - const parsedContent = marked(matchResult[1], [], inlineElementParserList); + const parsedContent = marked(matchResult[1], highlightWord, [], inlineElementParserList); return `

${parsedContent}

${escape(matchResult[2])}`; }; diff --git a/web/src/labs/marked/parser/index.ts b/web/src/labs/marked/parser/index.ts index 80ff1e2d3..4a0b0d031 100644 --- a/web/src/labs/marked/parser/index.ts +++ b/web/src/labs/marked/parser/index.ts @@ -38,5 +38,6 @@ export const blockElementParserList = [ UnorderedList, Paragraph, ]; +// TODO 感觉会递归 export const inlineElementParserList = [Image, BoldEmphasis, Bold, Emphasis, Link, InlineCode, PlainLink, Tag, PlainText]; export const parserList = [...blockElementParserList, ...inlineElementParserList]; diff --git a/web/src/labs/marked/parser/utils.ts b/web/src/labs/marked/parser/utils.ts new file mode 100644 index 000000000..30dc93a71 --- /dev/null +++ b/web/src/labs/marked/parser/utils.ts @@ -0,0 +1,7 @@ +export const renderWithHighlightWord = (result: string, highlightWord: string | undefined) => { + if (highlightWord) { + const highlightReg = RegExp(highlightWord, "g"); + result = result.replace(highlightReg, `${highlightWord}`); + } + return result; +}; diff --git a/web/src/less/memo.less b/web/src/less/memo.less index dc78c38b8..51d81c032 100644 --- a/web/src/less/memo.less +++ b/web/src/less/memo.less @@ -116,6 +116,10 @@ .img { @apply max-w-xs; } + + .highlight-word{ + @apply bg-yellow-200; + } } }