diff --git a/src/components/ContentPreview/index.tsx b/src/components/ContentPreview/index.tsx new file mode 100644 index 00000000..a1d38201 --- /dev/null +++ b/src/components/ContentPreview/index.tsx @@ -0,0 +1,34 @@ +import { extractEmbeddedNotesFromContent, extractImagesFromContent } from '@/lib/event' +import { cn } from '@/lib/utils' +import { Event } from 'nostr-tools' +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import { embedded, embeddedNostrNpubRenderer, embeddedNostrProfileRenderer } from '../Embedded' + +export default function ContentPreview({ + event, + className +}: { + event?: Event + className?: string +}) { + const { t } = useTranslation() + const content = useMemo(() => { + if (!event) return t('Not found') + const { contentWithoutEmbeddedNotes, embeddedNotes } = extractEmbeddedNotesFromContent( + event.content + ) + const { contentWithoutImages, images } = extractImagesFromContent(contentWithoutEmbeddedNotes) + const contents = [contentWithoutImages] + if (images?.length) { + contents.push(`[${t('image')}]`) + } + if (embeddedNotes.length) { + contents.push(`[${t('note')}]`) + } + return embedded(contents.join(' '), [embeddedNostrProfileRenderer, embeddedNostrNpubRenderer]) + }, [event]) + if (!event) return null + + return
{content}
+} diff --git a/src/components/Embedded/EmbeddedNote.tsx b/src/components/Embedded/EmbeddedNote.tsx index 45e5394d..8604c6fc 100644 --- a/src/components/Embedded/EmbeddedNote.tsx +++ b/src/components/Embedded/EmbeddedNote.tsx @@ -35,8 +35,8 @@ function EmbeddedNoteSkeleton({ className }: { className?: string }) { onClick={(e) => e.stopPropagation()} >
- - + +
diff --git a/src/components/Note/index.tsx b/src/components/Note/index.tsx index 309a88bf..0ec0c34a 100644 --- a/src/components/Note/index.tsx +++ b/src/components/Note/index.tsx @@ -1,5 +1,6 @@ import { useSecondaryPage } from '@/PageManager' -import { getUsingClient } from '@/lib/event' +import { useFetchEvent } from '@/hooks' +import { getParentEventId, getUsingClient } from '@/lib/event' import { toNote } from '@/lib/link' import { Event } from 'nostr-tools' import { useMemo } from 'react' @@ -12,21 +13,27 @@ import Username from '../Username' export default function Note({ event, - parentEvent, size = 'normal', className, + hideParentNotePreview = false, hideStats = false, fetchNoteStats = false }: { event: Event - parentEvent?: Event size?: 'normal' | 'small' className?: string + hideParentNotePreview?: boolean hideStats?: boolean fetchNoteStats?: boolean }) { const { push } = useSecondaryPage() + const parentEventId = useMemo( + () => (hideParentNotePreview ? undefined : getParentEventId(event)), + [event, hideParentNotePreview] + ) + const { event: parentEvent, isFetching } = useFetchEvent(parentEventId) const usingClient = useMemo(() => getUsingClient(event), [event]) + return (
@@ -49,13 +56,14 @@ export default function Note({
- {parentEvent && ( + {parentEventId && ( { e.stopPropagation() - push(toNote(parentEvent)) + push(toNote(parentEventId)) }} /> )} diff --git a/src/components/NoteCard/MainNoteCard.tsx b/src/components/NoteCard/MainNoteCard.tsx index dcc24197..abdd58ee 100644 --- a/src/components/NoteCard/MainNoteCard.tsx +++ b/src/components/NoteCard/MainNoteCard.tsx @@ -1,6 +1,4 @@ import { Separator } from '@/components/ui/separator' -import { useFetchEvent } from '@/hooks' -import { getParentEventId, getRootEventId } from '@/lib/event' import { toNote } from '@/lib/link' import { useSecondaryPage } from '@/PageManager' import { Event } from 'nostr-tools' @@ -19,8 +17,6 @@ export default function MainNoteCard({ embedded?: boolean }) { const { push } = useSecondaryPage() - const { event: rootEvent } = useFetchEvent(getRootEventId(event)) - const { event: parentEvent } = useFetchEvent(getParentEventId(event)) return (
- +
{!embedded && } diff --git a/src/components/NoteList/index.tsx b/src/components/NoteList/index.tsx index f0f041b7..c4ce3312 100644 --- a/src/components/NoteList/index.tsx +++ b/src/components/NoteList/index.tsx @@ -335,13 +335,23 @@ function LoadingSkeleton({ isPictures }: { isPictures: boolean }) {
-
- - +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
- -
) } diff --git a/src/components/NotificationList/index.tsx b/src/components/NotificationList/index.tsx index 1130264e..ef8ffc1d 100644 --- a/src/components/NotificationList/index.tsx +++ b/src/components/NotificationList/index.tsx @@ -1,7 +1,6 @@ import { Skeleton } from '@/components/ui/skeleton' import { BIG_RELAY_URLS, COMMENT_EVENT_KIND, PICTURE_EVENT_KIND } from '@/constants' import { useFetchEvent } from '@/hooks' -import { extractEmbeddedNotesFromContent, extractImagesFromContent } from '@/lib/event' import { toNote } from '@/lib/link' import { tagNameEquals } from '@/lib/tag' import { useSecondaryPage } from '@/PageManager' @@ -22,7 +21,7 @@ import { } from 'react' import { useTranslation } from 'react-i18next' import PullToRefresh from 'react-simple-pull-to-refresh' -import { embedded, embeddedNostrNpubRenderer, embeddedNostrProfileRenderer } from '../Embedded' +import ContentPreview from '../ContentPreview' import { FormattedTimestamp } from '../FormattedTimestamp' import UserAvatar from '../UserAvatar' @@ -230,7 +229,7 @@ function ReactionNotification({ notification }: { notification: Event }) {
{notification.content === '+' ? : notification.content}
- +
@@ -248,7 +247,7 @@ function ReplyNotification({ notification }: { notification: Event }) { > - +
@@ -278,7 +277,7 @@ function RepostNotification({ notification }: { notification: Event }) { > - +
@@ -307,26 +306,10 @@ function CommentNotification({ notification }: { notification: Event }) { > - +
) } - -function ContentPreview({ event }: { event?: Event }) { - const { t } = useTranslation() - const content = useMemo(() => { - if (!event) return null - const { contentWithoutEmbeddedNotes } = extractEmbeddedNotesFromContent(event.content) - const { contentWithoutImages, images } = extractImagesFromContent(contentWithoutEmbeddedNotes) - return embedded(contentWithoutImages + (images?.length ? `[${t('image')}]` : ''), [ - embeddedNostrProfileRenderer, - embeddedNostrNpubRenderer - ]) - }, [event]) - if (!event) return null - - return
{content}
-} diff --git a/src/components/ParentNotePreview/index.tsx b/src/components/ParentNotePreview/index.tsx index 4e59673e..56f20c92 100644 --- a/src/components/ParentNotePreview/index.tsx +++ b/src/components/ParentNotePreview/index.tsx @@ -1,37 +1,62 @@ +import { Skeleton } from '@/components/ui/skeleton' import { cn } from '@/lib/utils' import { useMuteList } from '@/providers/MuteListProvider' import { Event } from 'nostr-tools' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' +import ContentPreview from '../ContentPreview' import UserAvatar from '../UserAvatar' export default function ParentNotePreview({ event, + isFetching = false, className, onClick }: { - event: Event + event?: Event + isFetching?: boolean className?: string onClick?: React.MouseEventHandler | undefined }) { const { t } = useTranslation() const { mutePubkeys } = useMuteList() - const isMuted = useMemo(() => mutePubkeys.includes(event.pubkey), [mutePubkeys, event]) + const isMuted = useMemo( + () => (event ? mutePubkeys.includes(event.pubkey) : false), + [mutePubkeys, event] + ) + + if (isFetching) { + return ( +
+
{t('reply to')}
+ +
+ +
+
+ ) + } return (
{t('reply to')}
- + {event && } {isMuted ? (
{t('[muted]')}
) : ( -
{event.content}
+ )}
) diff --git a/src/components/Username/index.tsx b/src/components/Username/index.tsx index 3d993ebe..88c3ddc3 100644 --- a/src/components/Username/index.tsx +++ b/src/components/Username/index.tsx @@ -64,7 +64,13 @@ export function SimpleUsername({ skeletonClassName?: string }) { const { profile } = useFetchProfile(userId) - if (!profile) return + if (!profile) { + return ( +
+ +
+ ) + } const { username } = profile diff --git a/src/i18n/en.ts b/src/i18n/en.ts index f62390bf..690cecdc 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -49,6 +49,7 @@ export default { 'switch to dark theme': 'switch to dark theme', 'switch to system theme': 'switch to system theme', Note: 'Note', + note: 'note', "username's following": "{{username}}'s following", "username's used relays": "{{username}}'s used relays", "username's muted": "{{username}}'s muted", diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index 8fe62d5d..4c76eb1c 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -49,6 +49,7 @@ export default { 'switch to dark theme': '切换到深色主题', 'switch to system theme': '切换到系统主题', Note: '笔记', + note: '笔记', "username's following": '{{username}} 的关注', "username's used relays": '{{username}} 使用的服务器', "username's muted": '{{username}} 屏蔽的用户', diff --git a/src/pages/secondary/NotePage/index.tsx b/src/pages/secondary/NotePage/index.tsx index bd553950..9d884838 100644 --- a/src/pages/secondary/NotePage/index.tsx +++ b/src/pages/secondary/NotePage/index.tsx @@ -1,10 +1,11 @@ import { useSecondaryPage } from '@/PageManager' +import ContentPreview from '@/components/ContentPreview' import Nip22ReplyNoteList from '@/components/Nip22ReplyNoteList' import Note from '@/components/Note' import PictureNote from '@/components/PictureNote' import ReplyNoteList from '@/components/ReplyNoteList' import UserAvatar from '@/components/UserAvatar' -import Username from '@/components/Username' +import { SimpleUsername } from '@/components/Username' import { Card } from '@/components/ui/card' import { Separator } from '@/components/ui/separator' import { Skeleton } from '@/components/ui/skeleton' @@ -27,7 +28,25 @@ const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref return (
- +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
) @@ -55,7 +74,7 @@ const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref )} - + {event.kind === kinds.ShortTextNote ? ( @@ -74,23 +93,52 @@ NotePage.displayName = 'NotePage' export default NotePage function ParentNote({ eventId }: { eventId?: string }) { + const { t } = useTranslation() const { push } = useSecondaryPage() - const { event } = useFetchEvent(eventId) - if (!event) return null + const { event, isFetching } = useFetchEvent(eventId) + if (!eventId) return null + + if (isFetching) { + return ( +
+ push(toNote(eventId))} + > + +
+ +
+
+
+
+ ) + } + + if (!event) { + return ( +
+ + {t('Not found')} + +
+
+ ) + } return (
push(toNote(event))} + onClick={() => push(toNote(eventId))} > - -
{event.content}
+