From a17c5dfba54cad08e9ae012d2017e3dda35e4830 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Tue, 21 Mar 2023 09:24:40 +0700 Subject: [PATCH] added note content parser --- package.json | 1 + pnpm-lock.yaml | 14 +++++-- src/components/note/content/index.tsx | 56 +++++++++++++-------------- src/components/note/index.tsx | 18 ++++++--- src/components/note/root.tsx | 4 +- src/components/user/mention.tsx | 50 ++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 src/components/user/mention.tsx diff --git a/package.json b/package.json index a28b9d4c..e24a9bd2 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-dom": "^18.2.0", "react-hook-form": "^7.43.7", "react-player": "^2.12.0", + "react-string-replace": "^1.1.0", "react-virtuoso": "^4.1.0", "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql", "unique-names-generator": "^4.7.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac5393a9..44f19c7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,7 @@ specifiers: react-dom: ^18.2.0 react-hook-form: ^7.43.7 react-player: ^2.12.0 + react-string-replace: ^1.1.0 react-virtuoso: ^4.1.0 tailwindcss: ^3.2.7 tauri-plugin-sql-api: github:tauri-apps/tauri-plugin-sql @@ -82,6 +83,7 @@ dependencies: react-dom: 18.2.0_react@18.2.0 react-hook-form: 7.43.7_react@18.2.0 react-player: 2.12.0_react@18.2.0 + react-string-replace: 1.1.0 react-virtuoso: 4.1.0_biqbaboplfbrettd7655fr4n2y tauri-plugin-sql-api: github.com/tauri-apps/tauri-plugin-sql/3a8b9a6b244df7512bc5ef8692cebdedbab3ccce unique-names-generator: 4.7.1 @@ -1682,7 +1684,7 @@ packages: '@uiw/copy-to-clipboard': 1.0.12 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-markdown: 8.0.5_pmekkgnqduwlme35zpnqhenc34 + react-markdown: 8.0.6_pmekkgnqduwlme35zpnqhenc34 rehype-attr: 2.1.4 rehype-autolink-headings: 6.1.1 rehype-ignore: 1.0.4 @@ -5240,9 +5242,9 @@ packages: { integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== } dev: false - /react-markdown/8.0.5_pmekkgnqduwlme35zpnqhenc34: + /react-markdown/8.0.6_pmekkgnqduwlme35zpnqhenc34: resolution: - { integrity: sha512-jGJolWWmOWAvzf+xMdB9zwStViODyyFQhNB/bwCerbBKmrTmgmA599CGiOlP58OId1IMoIRsA8UdI1Lod4zb5A== } + { integrity: sha512-KgPWsYgHuftdx510wwIzpwf+5js/iHqBR+fzxefv8Khk3mFbnioF1bmL2idHN3ler0LMQmICKeDrWnZrX9mtbQ== } peerDependencies: '@types/react': '>=16' react: '>=16' @@ -5319,6 +5321,12 @@ packages: use-sidecar: 1.1.2_pmekkgnqduwlme35zpnqhenc34 dev: false + /react-string-replace/1.1.0: + resolution: + { integrity: sha512-N6RalSDFGbOHs0IJi1H611WbZsvk3ZT47Jl2JEXFbiS3kTwsdCYij70Keo/tWtLy7sfhDsYm7CwNM/WmjXIaMw== } + engines: { node: '>=0.12.0' } + dev: false + /react-style-singleton/2.2.1_pmekkgnqduwlme35zpnqhenc34: resolution: { integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== } diff --git a/src/components/note/content/index.tsx b/src/components/note/content/index.tsx index 742a3227..3b63599b 100644 --- a/src/components/note/content/index.tsx +++ b/src/components/note/content/index.tsx @@ -1,22 +1,35 @@ import NoteMetadata from '@components/note/content/metadata'; import NotePreview from '@components/note/content/preview'; import { UserExtend } from '@components/user/extend'; +import { UserMention } from '@components/user/mention'; -import dynamic from 'next/dynamic'; import { memo, useMemo } from 'react'; - -const MarkdownPreview = dynamic(() => import('@uiw/react-markdown-preview'), { - ssr: false, - loading: () =>
, -}); +import reactStringReplace from 'react-string-replace'; export const Content = memo(function Content({ data }: { data: any }) { - const content = useMemo( - () => - // remove all image urls - data.content.replace(/(https?:\/\/.*\.(jpg|jpeg|gif|png|webp)((\?.*)$|$))/i, ''), - [data.content] - ); + const content = useMemo(() => { + let parsedContent; + // get data tags + const tags = JSON.parse(data.tags); + // remove all image urls + parsedContent = data.content.replace(/(https?:\/\/.*\.(jpg|jpeg|gif|png|webp)((\?.*)$|$))/gim, ''); + // handle urls + parsedContent = reactStringReplace(parsedContent, /(https?:\/\/\S+)/g, (match, i) => ( + + {match} + + )); + // handle hashtags + parsedContent = reactStringReplace(parsedContent, /#(\w+)/g, (match, i) => ( + #{match} + )); + // handle mentions + parsedContent = reactStringReplace(parsedContent, /\#\[(\d+)\]/gm, (match, i) => ( +