From 06adcdb2a8a0a3cd3c097909af4d5cf4f4fe5ffe Mon Sep 17 00:00:00 2001 From: codytseng Date: Sat, 16 Aug 2025 17:49:18 +0800 Subject: [PATCH] feat: improve support for long-form articles --- src/components/ImageWithLightbox/index.tsx | 4 +- src/components/Note/LongFormArticle/index.tsx | 82 +++++++++++++++---- .../Note/LongFormArticlePreview.tsx | 19 +++-- src/components/NoteList/index.tsx | 2 +- src/lib/link.ts | 7 +- src/pages/secondary/NoteListPage/index.tsx | 12 ++- src/types/index.d.ts | 2 +- 7 files changed, 101 insertions(+), 27 deletions(-) diff --git a/src/components/ImageWithLightbox/index.tsx b/src/components/ImageWithLightbox/index.tsx index 368aefb8..491693de 100644 --- a/src/components/ImageWithLightbox/index.tsx +++ b/src/components/ImageWithLightbox/index.tsx @@ -34,10 +34,10 @@ export default function ImageWithLightbox({ } return ( -
+
getLongFormArticleMetadataFromEvent(event), [event]) return ( @@ -28,15 +31,6 @@ export default function LongFormArticle({

{metadata.summary}

)} - {metadata.tags.length > 0 && ( -
- {metadata.tags.map((tag) => ( - - {tag} - - ))} -
- )} {metadata.image && ( { + if (url.startsWith('nostr:')) { + return url.slice(6) // Remove 'nostr:' prefix for rendering + } + return url + }} components={ { nostr: (props) => , - a: (props) => ( - - ), + a: ({ href, children, ...props }) => { + if (!href) { + return + } + if ( + href.startsWith('note1') || + href.startsWith('nevent1') || + href.startsWith('naddr1') + ) { + return ( + + {children} + + ) + } + if (href.startsWith('npub1') || href.startsWith('nprofile1')) { + return ( + + {children} + + ) + } + return ( + + {children} + + ) + }, p: (props) =>

, div: (props) =>

, code: (props) => @@ -59,6 +96,23 @@ export default function LongFormArticle({ > {event.content} + {metadata.tags.length > 0 && ( +
+ {metadata.tags.map((tag) => ( +
{ + e.stopPropagation() + push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] })) + }} + > + #{tag} +
+ ))} +
+ )}
) } diff --git a/src/components/Note/LongFormArticlePreview.tsx b/src/components/Note/LongFormArticlePreview.tsx index 6e7fbba1..df864700 100644 --- a/src/components/Note/LongFormArticlePreview.tsx +++ b/src/components/Note/LongFormArticlePreview.tsx @@ -1,7 +1,8 @@ -import { Badge } from '@/components/ui/badge' import { getLongFormArticleMetadataFromEvent } from '@/lib/event-metadata' +import { toNoteList } from '@/lib/link' +import { useSecondaryPage } from '@/PageManager' import { useScreenSize } from '@/providers/ScreenSizeProvider' -import { Event } from 'nostr-tools' +import { Event, kinds } from 'nostr-tools' import { useMemo } from 'react' import Image from '../Image' @@ -13,6 +14,7 @@ export default function LongFormArticlePreview({ className?: string }) { const { isSmallScreen } = useScreenSize() + const { push } = useSecondaryPage() const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event]) const titleComponent =
{metadata.title}
@@ -20,9 +22,16 @@ export default function LongFormArticlePreview({ const tagsComponent = metadata.tags.length > 0 && (
{metadata.tags.map((tag) => ( - - {tag} - +
{ + e.stopPropagation() + push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] })) + }} + > + #{tag} +
))}
) diff --git a/src/components/NoteList/index.tsx b/src/components/NoteList/index.tsx index db6d89ff..58a16d26 100644 --- a/src/components/NoteList/index.tsx +++ b/src/components/NoteList/index.tsx @@ -119,8 +119,8 @@ const NoteList = forwardRef( subRequests.map(({ urls, filter }) => ({ urls, filter: { - ...filter, kinds: KINDS, + ...filter, limit: areAlgoRelays ? ALGO_LIMIT : LIMIT } })), diff --git a/src/lib/link.ts b/src/lib/link.ts index 847aca63..97575f66 100644 --- a/src/lib/link.ts +++ b/src/lib/link.ts @@ -11,16 +11,21 @@ export const toNoteList = ({ hashtag, search, externalContentId, - domain + domain, + kinds }: { hashtag?: string search?: string externalContentId?: string domain?: string + kinds?: number[] }) => { const path = '/notes' const query = new URLSearchParams() if (hashtag) query.set('t', hashtag.toLowerCase()) + if (kinds?.length) { + kinds.forEach((k) => query.append('k', k.toString())) + } if (search) query.set('s', search) if (externalContentId) query.set('i', externalContentId) if (domain) query.set('d', domain) diff --git a/src/pages/secondary/NoteListPage/index.tsx b/src/pages/secondary/NoteListPage/index.tsx index 67e7ce26..2f5b1fea 100644 --- a/src/pages/secondary/NoteListPage/index.tsx +++ b/src/pages/secondary/NoteListPage/index.tsx @@ -22,10 +22,12 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => { const [data, setData] = useState< | { type: 'hashtag' | 'search' | 'externalContent' + kinds?: number[] } | { type: 'domain' domain: string + kinds?: number[] } | null >(null) @@ -34,13 +36,17 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => { useEffect(() => { const init = async () => { const searchParams = new URLSearchParams(window.location.search) + const kinds = searchParams + .getAll('k') + .map((k) => parseInt(k)) + .filter((k) => !isNaN(k)) const hashtag = searchParams.get('t') if (hashtag) { setData({ type: 'hashtag' }) setTitle(`# ${hashtag}`) setSubRequests([ { - filter: { '#t': [hashtag] }, + filter: { '#t': [hashtag], ...(kinds.length > 0 ? { kinds } : {}) }, urls: BIG_RELAY_URLS } ]) @@ -52,7 +58,7 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => { setTitle(`${t('Search')}: ${search}`) setSubRequests([ { - filter: { search }, + filter: { search, ...(kinds.length > 0 ? { kinds } : {}) }, urls: SEARCHABLE_RELAY_URLS } ]) @@ -64,7 +70,7 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => { setTitle(externalContentId) setSubRequests([ { - filter: { '#I': [externalContentId] }, + filter: { '#I': [externalContentId], ...(kinds.length > 0 ? { kinds } : {}) }, urls: BIG_RELAY_URLS.concat(relayList?.write || []) } ]) diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 6eee69be..5749826e 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -5,7 +5,7 @@ export type TSubRequestFilter = Omit & { limit: numbe export type TFeedSubRequest = { urls: string[] - filter: Omit + filter: Omit } export type TProfile = {