diff --git a/src/app/newsfeed/components/contentParser.tsx b/src/app/newsfeed/components/contentParser.tsx deleted file mode 100644 index 093dc6a0..00000000 --- a/src/app/newsfeed/components/contentParser.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { NoteQuote } from '@lume/app/newsfeed/components/note/quote'; -import { NoteMentionUser } from '@lume/app/newsfeed/components/user/mention'; -import ImagePreview from '@lume/shared/preview/image'; -import VideoPreview from '@lume/shared/preview/video'; -import YoutubePreview from '@lume/shared/preview/youtube'; - -import destr from 'destr'; -import reactStringReplace from 'react-string-replace'; - -export const contentParser = (noteContent: any, noteTags: any) => { - let parsedContent = noteContent.trim(); - - // get data tags - const tags = destr(noteTags); - // handle urls - parsedContent = reactStringReplace(parsedContent, /(https?:\/\/\S+)/g, (match, i) => { - if (match.match(/\.(jpg|jpeg|gif|png|webp)$/i)) { - // image url - return ; - } else if (match.match(/(http:|https:)?(\/\/)?(www\.)?(youtube.com|youtu.be)\/(watch|embed)?(\?v=|\/)?(\S+)?/)) { - // youtube - return ; - } else if (match.match(/\.(mp4|webm)$/i)) { - // video - return ; - } else { - return ( - - {match} - - ); - } - }); - // handle #-hashtags - parsedContent = reactStringReplace(parsedContent, /#(\w+)/g, (match, i) => ( - - #{match} - - )); - // handle mentions - if (tags && tags.length > 0) { - parsedContent = reactStringReplace(parsedContent, /\#\[(\d+)\]/gm, (match, i) => { - if (tags[match][0] === 'p') { - // @-mentions - return ; - } else if (tags[match][0] === 'e') { - // note-quotes - return ; - } else { - return; - } - }); - } - - return parsedContent; -}; diff --git a/src/app/newsfeed/pages/following/index.page.tsx b/src/app/newsfeed/pages/following/index.page.tsx index 2c82f4e5..562678cd 100644 --- a/src/app/newsfeed/pages/following/index.page.tsx +++ b/src/app/newsfeed/pages/following/index.page.tsx @@ -1,7 +1,7 @@ import NoteForm from '@lume/app/newsfeed/components/form'; -import NoteBase from '@lume/app/newsfeed/components/note/base'; -import { Placeholder } from '@lume/app/newsfeed/components/note/placeholder'; -import { NoteQuoteRepost } from '@lume/app/newsfeed/components/note/quoteRepost'; +import NoteBase from '@lume/app/note/components/base'; +import { Placeholder } from '@lume/app/note/components/placeholder'; +import { NoteQuoteRepost } from '@lume/app/note/components/quoteRepost'; import { hasNewerNoteAtom } from '@lume/stores/note'; import { getNotes } from '@lume/utils/storage'; diff --git a/src/app/newsfeed/components/note/base.tsx b/src/app/note/components/base.tsx similarity index 80% rename from src/app/newsfeed/components/note/base.tsx rename to src/app/note/components/base.tsx index 338c7b25..6e7a802c 100644 --- a/src/app/newsfeed/components/note/base.tsx +++ b/src/app/note/components/base.tsx @@ -1,9 +1,9 @@ -import NoteMetadata from '@lume/app/newsfeed/components/note/metadata'; -import { NoteParent } from '@lume/app/newsfeed/components/note/parent'; -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; +import NoteMetadata from '@lume/app/note/components/metadata'; +import { NoteParent } from '@lume/app/note/components/parent'; import { noteParser } from '@lume/app/note/components/parser'; import ImagePreview from '@lume/app/note/components/preview/image'; import VideoPreview from '@lume/app/note/components/preview/video'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { navigate } from 'vite-plugin-ssr/client/router'; @@ -24,7 +24,11 @@ export default function NoteBase({ event }: { event: any }) { onClick={(e) => openNote(e)} className="relative z-10 flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 px-3 py-5 hover:bg-black/20" > - {event.parent_id ? : <>} + {event.parent_id && event.parent_id !== event.event_id ? ( + + ) : ( + <> + )}
diff --git a/src/app/newsfeed/components/note/comment.tsx b/src/app/note/components/comment.tsx similarity index 79% rename from src/app/newsfeed/components/note/comment.tsx rename to src/app/note/components/comment.tsx index 3f1fa1a3..6a62e5d5 100644 --- a/src/app/newsfeed/components/note/comment.tsx +++ b/src/app/note/components/comment.tsx @@ -1,11 +1,8 @@ -import { contentParser } from '@lume/app/newsfeed/components/contentParser'; -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { memo } from 'react'; export const NoteComment = memo(function NoteComment({ event }: { event: any }) { - const content = contentParser(event.content, event.tags); - return (
@@ -13,7 +10,7 @@ export const NoteComment = memo(function NoteComment({ event }: { event: any })
- {content} + {event.content}
diff --git a/src/app/note/components/form.tsx b/src/app/note/components/formReply.tsx similarity index 100% rename from src/app/note/components/form.tsx rename to src/app/note/components/formReply.tsx diff --git a/src/app/newsfeed/components/note/metadata.tsx b/src/app/note/components/metadata.tsx similarity index 89% rename from src/app/newsfeed/components/note/metadata.tsx rename to src/app/note/components/metadata.tsx index 4d84a9cf..ea44b8a7 100644 --- a/src/app/newsfeed/components/note/metadata.tsx +++ b/src/app/note/components/metadata.tsx @@ -1,6 +1,6 @@ -import NoteLike from '@lume/app/newsfeed/components/metadata/like'; -import NoteReply from '@lume/app/newsfeed/components/metadata/reply'; -import NoteRepost from '@lume/app/newsfeed/components/metadata/repost'; +import NoteLike from '@lume/app/note/components/metadata/like'; +import NoteReply from '@lume/app/note/components/metadata/reply'; +import NoteRepost from '@lume/app/note/components/metadata/repost'; import ZapIcon from '@lume/shared/icons/zap'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; diff --git a/src/app/newsfeed/components/metadata/like.tsx b/src/app/note/components/metadata/like.tsx similarity index 100% rename from src/app/newsfeed/components/metadata/like.tsx rename to src/app/note/components/metadata/like.tsx diff --git a/src/app/newsfeed/components/metadata/reply.tsx b/src/app/note/components/metadata/reply.tsx similarity index 100% rename from src/app/newsfeed/components/metadata/reply.tsx rename to src/app/note/components/metadata/reply.tsx diff --git a/src/app/newsfeed/components/metadata/repost.tsx b/src/app/note/components/metadata/repost.tsx similarity index 100% rename from src/app/newsfeed/components/metadata/repost.tsx rename to src/app/note/components/metadata/repost.tsx diff --git a/src/app/newsfeed/components/note/parent.tsx b/src/app/note/components/parent.tsx similarity index 95% rename from src/app/newsfeed/components/note/parent.tsx rename to src/app/note/components/parent.tsx index c37d46fe..e8718c0a 100644 --- a/src/app/newsfeed/components/note/parent.tsx +++ b/src/app/note/components/parent.tsx @@ -1,8 +1,8 @@ -import NoteMetadata from '@lume/app/newsfeed/components/note/metadata'; -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; +import NoteMetadata from '@lume/app/note/components/metadata'; import { noteParser } from '@lume/app/note/components/parser'; import ImagePreview from '@lume/app/note/components/preview/image'; import VideoPreview from '@lume/app/note/components/preview/video'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; diff --git a/src/app/note/components/parser.tsx b/src/app/note/components/parser.tsx index 09df7ed0..cae72011 100644 --- a/src/app/note/components/parser.tsx +++ b/src/app/note/components/parser.tsx @@ -1,55 +1,66 @@ +import { NoteQuote } from '@lume/app/note/components/quote'; +import { NoteMentionUser } from '@lume/app/note/components/user/mention'; + import { Event, parseReferences } from 'nostr-tools'; +import reactStringReplace from 'react-string-replace'; const getURLs = new RegExp( - '(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))', - 'g' + '(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal|wss|ws):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))', + 'gmi' ); export const noteParser = (event: Event) => { const references = parseReferences(event); - const content = { original: event.content, parsed: event.content, images: [], videos: [], others: [] }; - - // remove extra whitespace - content.parsed = content.parsed.replace(/\s+/g, ' ').trim(); + const content: { original: string; parsed: any; images: string[]; videos: string[] } = { + original: event.content, + parsed: event.content, + images: [], + videos: [], + }; // handle media - content.original.match(getURLs)?.forEach((url) => { - if (url.match(/\.(jpg|jpeg|gif|png|webp|avif)$/im)) { + content.original.match(getURLs)?.forEach((item) => { + // make sure url is trimmed + const url = item.trim(); + + if (url.match(/\.(jpg|jpeg|gif|png|webp|avif)$/gim)) { // image url - content.images.push(url.trim()); + content.images.push(url); // remove url from original content content.parsed = content.parsed.replace(url, ''); - } else if (url.match(/(http:|https:)?(\/\/)?(www\.)?(youtube.com|youtu.be)\/(watch|embed)?(\?v=|\/)?(\S+)?/)) { - // youtube - content.videos.push(url.trim()); - // remove url from original content - content.parsed = content.parsed.replace(url, ''); - } else if (url.match(/\.(mp4|webm|mov)$/im)) { + } else if (url.match(/\.(mp4|webm|mov)$/i)) { // video - content.videos.push(url.trim()); + content.videos.push(url); // remove url from original content content.parsed = content.parsed.replace(url, ''); - } else { - content.others.push(url.trim()); } }); + // handle hashtag + content.parsed = reactStringReplace(content.parsed, /#(\w+)/g, (match, i) => ( + + #{match} + + )); + // handle note references references?.forEach((reference) => { if (reference?.profile) { - content.parsed = content.parsed.replace( - reference.text, - `` - ); + content.parsed = reactStringReplace(content.parsed, reference.text, () => { + return ; + }); } if (reference?.event) { - content.parsed = content.parsed.replace(reference.text, `;`); + content.parsed = reactStringReplace(content.parsed, reference.text, () => { + return ; + }); } - if (reference?.address) { - content.parsed = content.parsed.replace( - reference.text, - `${reference.address}` - ); + }); + + // make sure no unnessary spaces are left + content.parsed.forEach((item: string, index: string) => { + if (typeof item === 'string') { + content.parsed[index] = item.replace(/^\x20+|\x20+$/gm, ''); } }); diff --git a/src/app/newsfeed/components/note/placeholder.tsx b/src/app/note/components/placeholder.tsx similarity index 100% rename from src/app/newsfeed/components/note/placeholder.tsx rename to src/app/note/components/placeholder.tsx diff --git a/src/app/newsfeed/components/note/quote.tsx b/src/app/note/components/quote.tsx similarity index 96% rename from src/app/newsfeed/components/note/quote.tsx rename to src/app/note/components/quote.tsx index 8b728ffb..ebf5ea39 100644 --- a/src/app/newsfeed/components/note/quote.tsx +++ b/src/app/note/components/quote.tsx @@ -1,7 +1,7 @@ -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; import { noteParser } from '@lume/app/note/components/parser'; import ImagePreview from '@lume/app/note/components/preview/image'; import VideoPreview from '@lume/app/note/components/preview/video'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; diff --git a/src/app/newsfeed/components/note/quoteRepost.tsx b/src/app/note/components/quoteRepost.tsx similarity index 82% rename from src/app/newsfeed/components/note/quoteRepost.tsx rename to src/app/note/components/quoteRepost.tsx index 80b5eb6e..9250f059 100644 --- a/src/app/newsfeed/components/note/quoteRepost.tsx +++ b/src/app/note/components/quoteRepost.tsx @@ -1,5 +1,5 @@ -import { RootNote } from '@lume/app/newsfeed/components/note/rootNote'; -import { NoteRepostUser } from '@lume/app/newsfeed/components/user/repost'; +import { RootNote } from '@lume/app/note/components/rootNote'; +import { NoteRepostUser } from '@lume/app/note/components/user/repost'; import { getQuoteID } from '@lume/utils/transform'; import { memo } from 'react'; diff --git a/src/app/note/components/replies.tsx b/src/app/note/components/replies.tsx index 3d4cb94c..60375ed7 100644 --- a/src/app/note/components/replies.tsx +++ b/src/app/note/components/replies.tsx @@ -1,4 +1,4 @@ -import NoteReplyForm from '@lume/app/note/components/form'; +import NoteReplyForm from '@lume/app/note/components/formReply'; import NoteReply from '@lume/app/note/components/reply'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; diff --git a/src/app/note/components/reply.tsx b/src/app/note/components/reply.tsx index f0809a95..b8e6be08 100644 --- a/src/app/note/components/reply.tsx +++ b/src/app/note/components/reply.tsx @@ -1,16 +1,19 @@ -import { contentParser } from '@lume/app/newsfeed/components/contentParser'; - -import NoteReplyUser from './user'; +import { noteParser } from '@lume/app/note/components//parser'; +import ImagePreview from '@lume/app/note/components/preview/image'; +import VideoPreview from '@lume/app/note/components/preview/video'; +import NoteReplyUser from '@lume/app/note/components/user/reply'; export default function NoteReply({ data }: { data: any }) { - const content = contentParser(data.content, data.tags); + const content = noteParser(data); return (
-
{content}
+
{content.parsed}
+ {Array.isArray(content.images) && content.images.length ? : <>} + {Array.isArray(content.videos) && content.videos.length ? : <>}
diff --git a/src/app/newsfeed/components/note/rootNote.tsx b/src/app/note/components/rootNote.tsx similarity index 95% rename from src/app/newsfeed/components/note/rootNote.tsx rename to src/app/note/components/rootNote.tsx index 09cc6bd0..05dd642d 100644 --- a/src/app/newsfeed/components/note/rootNote.tsx +++ b/src/app/note/components/rootNote.tsx @@ -1,8 +1,8 @@ -import NoteMetadata from '@lume/app/newsfeed/components/note/metadata'; -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; +import NoteMetadata from '@lume/app/note/components/metadata'; import { noteParser } from '@lume/app/note/components/parser'; import ImagePreview from '@lume/app/note/components/preview/image'; import VideoPreview from '@lume/app/note/components/preview/video'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; @@ -46,7 +46,7 @@ export const RootNote = memo(function RootNote({ id, fallback }: { id: string; f } }; - const content = !error && data ? noteParser(parseFallback) : null; + const content = !error && data ? noteParser(data) : null; if (parseFallback) { const contentFallback = noteParser(parseFallback); diff --git a/src/app/newsfeed/components/user/default.tsx b/src/app/note/components/user/default.tsx similarity index 97% rename from src/app/newsfeed/components/user/default.tsx rename to src/app/note/components/user/default.tsx index 96a177fc..520e39ae 100644 --- a/src/app/newsfeed/components/user/default.tsx +++ b/src/app/note/components/user/default.tsx @@ -14,7 +14,7 @@ export const NoteDefaultUser = ({ pubkey, time }: { pubkey: string; time: number
{isError || isLoading ? ( <> -
+
diff --git a/src/app/newsfeed/components/user/mention.tsx b/src/app/note/components/user/mention.tsx similarity index 100% rename from src/app/newsfeed/components/user/mention.tsx rename to src/app/note/components/user/mention.tsx diff --git a/src/app/note/components/user.tsx b/src/app/note/components/user/reply.tsx similarity index 100% rename from src/app/note/components/user.tsx rename to src/app/note/components/user/reply.tsx diff --git a/src/app/newsfeed/components/user/repost.tsx b/src/app/note/components/user/repost.tsx similarity index 97% rename from src/app/newsfeed/components/user/repost.tsx rename to src/app/note/components/user/repost.tsx index af72675b..8549af48 100644 --- a/src/app/newsfeed/components/user/repost.tsx +++ b/src/app/note/components/user/repost.tsx @@ -14,7 +14,7 @@ export const NoteRepostUser = ({ pubkey, time }: { pubkey: string; time: number
{isError || isLoading ? ( <> -
+
diff --git a/src/app/note/pages/index.page.tsx b/src/app/note/pages/index.page.tsx index 5be6ae95..93092189 100644 --- a/src/app/note/pages/index.page.tsx +++ b/src/app/note/pages/index.page.tsx @@ -1,7 +1,9 @@ -import { contentParser } from '@lume/app/newsfeed/components/contentParser'; -import NoteMetadata from '@lume/app/newsfeed/components/note/metadata'; -import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default'; +import NoteMetadata from '@lume/app/note/components/metadata'; +import { noteParser } from '@lume/app/note/components/parser'; +import ImagePreview from '@lume/app/note/components/preview/image'; +import VideoPreview from '@lume/app/note/components/preview/video'; import NoteReplies from '@lume/app/note/components/replies'; +import { NoteDefaultUser } from '@lume/app/note/components/user/default'; import { RelayContext } from '@lume/shared/relayProvider'; import { READONLY_RELAYS } from '@lume/stores/constants'; import { usePageContext } from '@lume/utils/hooks/usePageContext'; @@ -35,6 +37,8 @@ export function Page() { }; }); + const content = !error && data ? noteParser(data) : null; + return (
@@ -69,8 +73,18 @@ export function Page() {
- {contentParser(data.content, data.tags)} + {content ? content.parsed : ''}
+ {Array.isArray(content.images) && content.images.length ? ( + + ) : ( + <> + )} + {Array.isArray(content.videos) && content.videos.length ? ( + + ) : ( + <> + )}
e.stopPropagation()} className="mt-5 border-t border-zinc-800 px-5 py-5">