From e218ebee8906a0e3ad89cbaa8bac689be6cf874b Mon Sep 17 00:00:00 2001 From: reya Date: Wed, 1 Nov 2023 10:05:08 +0700 Subject: [PATCH] refactor text parser --- package.json | 2 + pnpm-lock.yaml | 74 +++++++----- src/shared/notes/kinds/text.tsx | 37 +++++- src/shared/notes/mentions/note.tsx | 7 +- src/shared/widgets/newsfeed.tsx | 8 +- src/shared/widgets/notification.tsx | 11 +- src/utils/parser.ts | 132 +++++++++++++++++++++ src/utils/parser.tsx | 173 ---------------------------- src/utils/types.d.ts | 3 +- 9 files changed, 234 insertions(+), 213 deletions(-) create mode 100644 src/utils/parser.ts delete mode 100644 src/utils/parser.tsx diff --git a/package.json b/package.json index 0b7e1437..b2767e85 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,10 @@ "destr": "^2.0.2", "framer-motion": "^10.16.4", "html-to-text": "^9.0.5", + "immer": "^10.0.3", "light-bolt11-decoder": "^3.0.0", "lru-cache": "^10.0.1", + "markdown-to-jsx": "^7.3.2", "media-chrome": "^1.4.5", "million": "^2.6.4", "minidenticons": "^4.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3f5fdfd..5a0dd272 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -140,12 +140,18 @@ dependencies: html-to-text: specifier: ^9.0.5 version: 9.0.5 + immer: + specifier: ^10.0.3 + version: 10.0.3 light-bolt11-decoder: specifier: ^3.0.0 version: 3.0.0 lru-cache: specifier: ^10.0.1 version: 10.0.1 + markdown-to-jsx: + specifier: ^7.3.2 + version: 7.3.2(react@18.2.0) media-chrome: specifier: ^1.4.5 version: 1.4.5 @@ -193,7 +199,7 @@ dependencies: version: 1.1.1 reactflow: specifier: ^11.9.4 - version: 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + version: 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) rehype-external-links: specifier: ^3.0.0 version: 3.0.0 @@ -220,7 +226,7 @@ dependencies: version: 0.15.6(react-dom@18.2.0)(react@18.2.0) zustand: specifier: ^4.4.4 - version: 4.4.4(@types/react@18.2.33)(react@18.2.0) + version: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) devDependencies: '@tailwindcss/typography': @@ -1792,39 +1798,39 @@ packages: '@babel/runtime': 7.23.2 dev: false - /@reactflow/background@11.3.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/background@11.3.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-bgwvqWxF09chwmdkyClpYEMaewBspdwjgLbbFlLf4SpWPFMYyuvCBQrcISsvy/EDEWO9i3Uj9ktgGAhvtSQsmA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/controls@11.2.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/controls@11.2.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-x6e5p9iHjC6gd+4SoZ3DOOp0F1MefGKQ8hT6yPVdqxfo1+rV2WhrWvrX/MCoEu12Dp7457LdLfa0giy3aho8tQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/core@11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/core@11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Ko7nKPOYalwDTTbRHi2+QXDiidSAcpUzGN3G+0B+QysLZkcaPCkpkMjjHiDC4c/Z1BJBzs1FRJg/T6BXaBnYkg==} peerDependencies: react: '>=17' @@ -1840,19 +1846,19 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/minimap@11.7.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/minimap@11.7.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Jo1R+uDey9IV7O2s3m0gK2+cZpg9M8hq2EZJb3NGfOSzMAPhj3mby0fNJIgTzycreuht0TpA51c2YfjGI3YIOw==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) '@types/d3-selection': 3.0.8 '@types/d3-zoom': 3.0.6 classcat: 5.0.4 @@ -1860,41 +1866,41 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-resizer@2.2.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/node-resizer@2.2.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-+p271/hAsM5M1+RQTWW/02pbNkCHeGXwxGimIlL1tMIagyuko0NX2vOz2B8jxJnPKlF09Wj18BcXBNUm3nDcSg==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 d3-drag: 3.0.0 d3-selection: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-toolbar@1.3.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /@reactflow/node-toolbar@1.3.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-TfcmpXHRBb2mUfzKGjburiU6FWqRME9pPFs1OwIC1z5e9BjupQhNDEKEk8XHi7PKL/mAiDfwuGXaM1BVVFuPqw==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.4.4(@types/react@18.2.33)(react@18.2.0) + zustand: 4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer @@ -4445,6 +4451,10 @@ packages: engines: {node: '>= 4'} dev: true + /immer@10.0.3: + resolution: {integrity: sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==} + dev: false + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -4922,6 +4932,15 @@ packages: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} dev: false + /markdown-to-jsx@7.3.2(react@18.2.0): + resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==} + engines: {node: '>= 10'} + peerDependencies: + react: '>= 0.14.0' + dependencies: + react: 18.2.0 + dev: false + /mdast-util-find-and-replace@3.0.1: resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==} dependencies: @@ -6122,18 +6141,18 @@ packages: loose-envify: 1.4.0 dev: false - /reactflow@11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0): + /reactflow@11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-IHAKBkJngNvU9y1vZ5Nw9rvA3Z+zc9geTgQQIi9qq9Y9knGLlDDr9KfsjbFMew9AycAAgVg8TvBEakF4IT5lqg==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/background': 11.3.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/controls': 11.2.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/core': 11.9.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/minimap': 11.7.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/node-resizer': 2.2.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/node-toolbar': 1.3.4(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/background': 11.3.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/controls': 11.2.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.9.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/minimap': 11.7.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/node-resizer': 2.2.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/node-toolbar': 1.3.4(@types/react@18.2.33)(immer@10.0.3)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -7117,7 +7136,7 @@ packages: engines: {node: '>=10'} dev: true - /zustand@4.4.4(@types/react@18.2.33)(react@18.2.0): + /zustand@4.4.4(@types/react@18.2.33)(immer@10.0.3)(react@18.2.0): resolution: {integrity: sha512-5UTUIAiHMNf5+mFp7/AnzJXS7+XxktULFN0+D1sCiZWyX7ZG+AQpqs2qpYrynRij4QvoDdCD+U+bmg/cG3Ucxw==} engines: {node: '>=12.7.0'} peerDependencies: @@ -7133,6 +7152,7 @@ packages: optional: true dependencies: '@types/react': 18.2.33 + immer: 10.0.3 react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) dev: false diff --git a/src/shared/notes/kinds/text.tsx b/src/shared/notes/kinds/text.tsx index 47064ec0..857c5fc0 100644 --- a/src/shared/notes/kinds/text.tsx +++ b/src/shared/notes/kinds/text.tsx @@ -1,6 +1,16 @@ +import Markdown from 'markdown-to-jsx'; import { memo } from 'react'; -import { ImagePreview, LinkPreview, MentionNote, VideoPreview } from '@shared/notes'; +import { + Boost, + Hashtag, + ImagePreview, + Invoice, + LinkPreview, + MentionNote, + MentionUser, + VideoPreview, +} from '@shared/notes'; import { parser } from '@utils/parser'; @@ -17,9 +27,30 @@ export function TextNote(props: { content?: string; truncate?: boolean }) { return (
-
+ str, + forceBlock: true, + enforceAtxHeadings: true, + }} + className="break-p prose prose-neutral max-w-none select-text whitespace-pre-line leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-1 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-600 prose-a:hover:underline" + > {richContent.parsed} -
+ {richContent.images.length ? : null} {richContent.videos.length ? : null} {richContent.links.length ? : null} diff --git a/src/shared/notes/mentions/note.tsx b/src/shared/notes/mentions/note.tsx index e5de7205..059d5019 100644 --- a/src/shared/notes/mentions/note.tsx +++ b/src/shared/notes/mentions/note.tsx @@ -75,13 +75,14 @@ export const MentionNote = memo(function MentionNote({ id }: { id: string }) { } return ( - +
); }); diff --git a/src/shared/widgets/newsfeed.tsx b/src/shared/widgets/newsfeed.tsx index ab080eae..12a9c510 100644 --- a/src/shared/widgets/newsfeed.tsx +++ b/src/shared/widgets/newsfeed.tsx @@ -124,7 +124,13 @@ export function NewsfeedWidget() { sub( filter, async (event) => { - queryClient.setQueryData(['newsfeed'], (old: NDKEvent[]) => [event, ...old]); + queryClient.setQueryData( + ['newsfeed'], + (prev: { pageParams: number; pages: Array }) => ({ + ...prev, + pages: [[event], ...prev.pages], + }) + ); }, false, 'newsfeed' diff --git a/src/shared/widgets/notification.tsx b/src/shared/widgets/notification.tsx index 104226d5..2265803f 100644 --- a/src/shared/widgets/notification.tsx +++ b/src/shared/widgets/notification.tsx @@ -77,10 +77,13 @@ export function NotificationWidget() { sub( filter, async (event) => { - queryClient.setQueryData(['notification'], (old: NDKEvent[]) => [ - event, - ...old, - ]); + queryClient.setQueryData( + ['notification'], + (prev: { pageParams: number; pages: Array }) => ({ + ...prev, + pages: [[event], ...prev.pages], + }) + ); const user = ndk.getUser({ hexpubkey: event.pubkey }); await user.fetchProfile(); diff --git a/src/utils/parser.ts b/src/utils/parser.ts new file mode 100644 index 00000000..42d1fac4 --- /dev/null +++ b/src/utils/parser.ts @@ -0,0 +1,132 @@ +import { nip19 } from 'nostr-tools'; +import { + AddressPointer, + EventPointer, + ProfilePointer, +} from 'nostr-tools/lib/types/nip19'; + +import { RichContent } from '@utils/types'; + +function isURL(string: string) { + try { + const url = new URL(string); + if (url.protocol.length > 0) { + if (url.protocol === 'https:' || url.protocol === 'http:') { + return true; + } else { + return false; + } + } + return true; + } catch (e) { + return false; + } +} + +export function parser(content: string) { + const richContent: RichContent = { + parsed: null, + images: [], + videos: [], + links: [], + notes: [], + }; + + const parsed = content + .trim() + .split(/(\s+)/) + .map((word) => { + // url + if (isURL(word)) { + const url = new URL(word); + url.search = ''; + + if (url.pathname.match(/\.(jpg|jpeg|gif|png|webp|avif)$/)) { + // image url + richContent.images.push(word); + // remove url from original content + return word.replace(word, ''); + } + + if (url.pathname.match(/\.(mp4|mov|webm|wmv|flv|mts|avi|ogv|mkv|mp3|m3u8)$/)) { + // video url + richContent.videos.push(word); + // remove url from original content + return word.replace(word, ''); + } + + // normal url + if (richContent.links.length < 1) { + richContent.links.push(url.toString()); + } + } + + // hashtag + if (word.startsWith('#') && word.length > 1) { + return word.replace(word, ``); + } + + // boost + if (word.startsWith('$prism') && word.length > 1) { + return word.replace(word, ``); + } + + // nostr account references (depreciated) + if (word.startsWith('@npub1')) { + const npub = word.replace('@', '').replace(/[^a-zA-Z0-9 ]/g, ''); + return word.replace( + word, + `` + ); + } + + // nostr account references + if (word.startsWith('nostr:npub1') || word.startsWith('npub1')) { + const npub = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); + return word.replace( + word, + `` + ); + } + + // nostr profile references + if (word.startsWith('nostr:nprofile1') || word.startsWith('nprofile1')) { + const nprofile = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); + const decoded = nip19.decode(nprofile).data as ProfilePointer; + return word.replace(word, ``); + } + + // nostr address references + if (word.startsWith('nostr:naddr1') || word.startsWith('naddr1')) { + const naddr = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); + const decoded = nip19.decode(naddr).data as AddressPointer; + return word.replace(word, ``); + } + + // lightning invoice + if (word.startsWith('lnbc') && word.length > 60) { + return word.replace(word, ``); + } + + // nostr note references + if (word.startsWith('nostr:note1') || word.startsWith('note1')) { + const note = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); + richContent.notes.push(nip19.decode(note).data as string); + return word.replace(word, ''); + } + + // nostr event references + if (word.startsWith('nostr:nevent1') || word.startsWith('nevent1')) { + const nevent = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); + const decoded = nip19.decode(nevent).data as EventPointer; + richContent.notes.push(decoded.id); + return word.replace(word, ''); + } + + return word; + }); + + // update content with parsed version + richContent.parsed = parsed.join(' ').trim(); + return richContent; +} diff --git a/src/utils/parser.tsx b/src/utils/parser.tsx deleted file mode 100644 index 2441dcf7..00000000 --- a/src/utils/parser.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { nip19 } from 'nostr-tools'; -import { - AddressPointer, - EventPointer, - ProfilePointer, -} from 'nostr-tools/lib/types/nip19'; -import { Link } from 'react-router-dom'; -import reactStringReplace from 'react-string-replace'; - -import { Boost, Hashtag, Invoice, MentionUser } from '@shared/notes'; - -import { RichContent } from '@utils/types'; - -function isURL(string: string) { - try { - const url = new URL(string); - if (url.protocol.length > 0) { - if (url.protocol === 'https:' || url.protocol === 'http:') { - return true; - } else { - return false; - } - } - return true; - } catch (e) { - return false; - } -} - -export function parser(eventContent: string) { - const content: RichContent = { - parsed: null, - images: [], - videos: [], - links: [], - notes: [], - }; - - const parsed = eventContent.split(/\s/gm).map((word) => { - // nostr note references - if (word.startsWith('nostr:note1') || word.startsWith('note1')) { - const note = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); - content.notes.push(nip19.decode(note).data as string); - return word.replace(word, ' '); - } - - // nostr event references - if (word.startsWith('nostr:nevent1') || word.startsWith('nevent1')) { - const nevent = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); - const decoded = nip19.decode(nevent).data as EventPointer; - content.notes.push(decoded.id); - return word.replace(word, ' '); - } - - // url - if (isURL(word)) { - const url = new URL(word); - url.search = ''; - - if (url.pathname.match(/\.(jpg|jpeg|gif|png|webp|avif)$/)) { - // image url - content.images.push(word); - // remove url from original content - return word.replace(word, ' '); - } - - if (url.pathname.match(/\.(mp4|mov|webm|wmv|flv|mts|avi|ogv|mkv|mp3|m3u8)$/)) { - // video url - content.videos.push(word); - // remove url from original content - return word.replace(word, ' '); - } - - // normal url - if (content.links.length < 1) { - content.links.push(url.toString()); - return word.replace(word, ' '); - } else { - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - - {word} - {' '} - - )); - } - } - - // hashtag - if (word.startsWith('#') && word.length > 1) { - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // boost - if (word.startsWith('$prism') && word.length > 1) { - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // nostr account references (depreciated) - if (word.startsWith('@npub1')) { - const npub = word.replace('@', '').replace(/[^a-zA-Z0-9 ]/g, ''); - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // nostr account references - if (word.startsWith('nostr:npub1') || word.startsWith('npub1')) { - const npub = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // nostr profile references - if (word.startsWith('nostr:nprofile1') || word.startsWith('nprofile1')) { - const nprofile = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); - const decoded = nip19.decode(nprofile).data as ProfilePointer; - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // nostr address references - if (word.startsWith('nostr:naddr1') || word.startsWith('naddr1')) { - const naddr = word.replace('nostr:', '').replace(/[^a-zA-Z0-9 ]/g, ''); - const decoded = nip19.decode(naddr).data as AddressPointer; - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // lightning invoice - if (word.startsWith('lnbc') && word.length > 60) { - return reactStringReplace(word, word, (match, i) => ( - <> - {' '} - {' '} - - )); - } - - // normal word - return ' ' + word + ' '; - }); - - // update content with parsed version - content.parsed = parsed; - return content; -} diff --git a/src/utils/types.d.ts b/src/utils/types.d.ts index ba8794ae..0c427925 100644 --- a/src/utils/types.d.ts +++ b/src/utils/types.d.ts @@ -1,9 +1,8 @@ import { type NDKEvent, type NDKUserProfile } from '@nostr-dev-kit/ndk'; import { type Response } from '@tauri-apps/plugin-http'; -import { ReactNode } from 'react'; export interface RichContent { - parsed: string | ReactNode[]; + parsed: string; images: string[]; videos: string[]; links: string[];