feat: improve highlight source display and navigation

This commit is contained in:
codytseng
2025-08-16 22:33:19 +08:00
parent 06adcdb2a8
commit 6350ddc224
4 changed files with 41 additions and 22 deletions

View File

@@ -1,8 +1,8 @@
import { useFetchEvent, useTranslatedEvent } from '@/hooks' import { useFetchEvent, useTranslatedEvent } from '@/hooks'
import { createFakeEvent } from '@/lib/event' import { createFakeEvent } from '@/lib/event'
import { toNjump, toNote } from '@/lib/link' import { toNote } from '@/lib/link'
import { isValidPubkey } from '@/lib/pubkey' import { isValidPubkey } from '@/lib/pubkey'
import { generateBech32IdFromATag } from '@/lib/tag' import { generateBech32IdFromATag, generateBech32IdFromETag } from '@/lib/tag'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useSecondaryPage } from '@/PageManager' import { useSecondaryPage } from '@/PageManager'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
@@ -62,7 +62,13 @@ function HighlightSource({ event }: { event: Event }) {
return sourceTag return sourceTag
}, [event]) }, [event])
const { event: referenceEvent } = useFetchEvent( const { event: referenceEvent } = useFetchEvent(
sourceTag && sourceTag[0] === 'e' ? sourceTag[1] : undefined sourceTag
? sourceTag[0] === 'e'
? generateBech32IdFromETag(sourceTag)
: sourceTag[0] === 'a'
? generateBech32IdFromATag(sourceTag)
: undefined
: undefined
) )
const referenceEventId = useMemo(() => { const referenceEventId = useMemo(() => {
if (!sourceTag || sourceTag[0] === 'r') return if (!sourceTag || sourceTag[0] === 'r') return
@@ -110,29 +116,17 @@ function HighlightSource({ event }: { event: Event }) {
<div className="flex items-center gap-2 text-muted-foreground"> <div className="flex items-center gap-2 text-muted-foreground">
<div className="shrink-0">{t('From')}</div> <div className="shrink-0">{t('From')}</div>
{pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />} {pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />}
{referenceEvent ? ( {referenceEventId && (
<div <div
className="truncate underline pointer-events-auto cursor-pointer hover:text-foreground" className="truncate underline pointer-events-auto cursor-pointer hover:text-foreground"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toNote(referenceEvent)) push(toNote(referenceEvent ?? referenceEventId))
}} }}
> >
<ContentPreview event={referenceEvent} /> {referenceEvent ? <ContentPreview event={referenceEvent} /> : referenceEventId}
</div> </div>
) : referenceEventId ? ( )}
<div className="truncate text-muted-foreground">
<a
href={toNjump(referenceEventId)}
target="_blank"
rel="noopener noreferrer"
className="underline text-muted-foreground hover:text-foreground"
onClick={(e) => e.stopPropagation()}
>
{toNjump(referenceEventId)}
</a>
</div>
) : null}
</div> </div>
) )
} }

View File

@@ -18,7 +18,13 @@ export function tagNameEquals(tagName: string) {
export function generateBech32IdFromETag(tag: string[]) { export function generateBech32IdFromETag(tag: string[]) {
try { try {
const [, id, relay, , author] = tag const [, id, relay, markerOrPubkey, pubkey] = tag
let author: string | undefined
if (markerOrPubkey && isValidPubkey(markerOrPubkey)) {
author = markerOrPubkey
} else if (pubkey && isValidPubkey(pubkey)) {
author = pubkey
}
return nip19.neventEncode({ id, relays: relay ? [relay] : undefined, author }) return nip19.neventEncode({ id, relays: relay ? [relay] : undefined, author })
} catch { } catch {
return undefined return undefined

View File

@@ -0,0 +1,13 @@
import ClientSelect from '@/components/ClientSelect'
import { useTranslation } from 'react-i18next'
export default function NotFound({ bech32Id }: { bech32Id?: string }) {
const { t } = useTranslation()
return (
<div className="text-muted-foreground w-full h-full flex flex-col items-center justify-center gap-2">
<div>{t('Note not found')}</div>
<ClientSelect originalNoteId={bech32Id} />
</div>
)
}

View File

@@ -18,7 +18,7 @@ import { Ellipsis } from 'lucide-react'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { forwardRef, useMemo } from 'react' import { forwardRef, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import NotFoundPage from '../NotFoundPage' import NotFound from './NotFound'
const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref) => { const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref) => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -59,7 +59,13 @@ const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref
</SecondaryPageLayout> </SecondaryPageLayout>
) )
} }
if (!event) return <NotFoundPage /> if (!event) {
return (
<SecondaryPageLayout ref={ref} index={index} title={t('Note')} displayScrollToTopButton>
<NotFound bech32Id={id} />
</SecondaryPageLayout>
)
}
return ( return (
<SecondaryPageLayout ref={ref} index={index} title={t('Note')} displayScrollToTopButton> <SecondaryPageLayout ref={ref} index={index} title={t('Note')} displayScrollToTopButton>