Revert "feat: support displaying highlights in replies"

This reverts commit d2c5c923a3.
This commit is contained in:
codytseng
2025-11-17 22:08:20 +08:00
parent 61d09a9482
commit b4366325cd
6 changed files with 50 additions and 112 deletions

View File

@@ -1,6 +1,5 @@
import { useFetchEvent, useTranslatedEvent } from '@/hooks' import { useFetchEvent, useTranslatedEvent } from '@/hooks'
import { createFakeEvent } from '@/lib/event' import { createFakeEvent } from '@/lib/event'
import { getHighlightSourceTag } from '@/lib/event-metadata'
import { toNote } from '@/lib/link' import { toNote } from '@/lib/link'
import { isValidPubkey } from '@/lib/pubkey' import { isValidPubkey } from '@/lib/pubkey'
import { generateBech32IdFromATag, generateBech32IdFromETag } from '@/lib/tag' import { generateBech32IdFromATag, generateBech32IdFromETag } from '@/lib/tag'
@@ -38,7 +37,36 @@ export default function Highlight({ event, className }: { event: Event; classNam
function HighlightSource({ event }: { event: Event }) { function HighlightSource({ event }: { event: Event }) {
const { t } = useTranslation() const { t } = useTranslation()
const { push } = useSecondaryPage() const { push } = useSecondaryPage()
const sourceTag = useMemo(() => getHighlightSourceTag(event), [event]) const sourceTag = useMemo(() => {
let sourceTag: string[] | undefined
for (const tag of event.tags) {
// Highest priority: 'source' tag
if (tag[2] === 'source') {
sourceTag = tag
break
}
// Give 'e' tags highest priority
if (tag[0] === 'e') {
sourceTag = tag
continue
}
// Give 'a' tags second priority over 'e' tags
if (tag[0] === 'a' && (!sourceTag || sourceTag[0] !== 'e')) {
sourceTag = tag
continue
}
// Give 'r' tags lowest priority
if (tag[0] === 'r' && (!sourceTag || sourceTag[0] === 'r')) {
sourceTag = tag
continue
}
}
return sourceTag
}, [event])
const { event: referenceEvent } = useFetchEvent( const { event: referenceEvent } = useFetchEvent(
sourceTag sourceTag
? sourceTag[0] === 'e' ? sourceTag[0] === 'e'

View File

@@ -1,26 +0,0 @@
import { useTranslatedEvent } from '@/hooks'
import { createFakeEvent } from '@/lib/event'
import { cn } from '@/lib/utils'
import { Event } from 'nostr-tools'
import { useMemo } from 'react'
import Content from '../Content'
export default function Highlight({ event, className }: { event: Event; className?: string }) {
const translatedEvent = useTranslatedEvent(event.id)
const comment = useMemo(
() => (translatedEvent?.tags ?? event.tags).find((tag) => tag[0] === 'comment')?.[1],
[event, translatedEvent]
)
return (
<div className={cn('text-wrap break-words whitespace-pre-wrap space-y-4', className)}>
{comment && <Content event={createFakeEvent({ content: comment })} />}
<div className="flex gap-4">
<div className="w-1 flex-shrink-0 my-1 bg-primary/60 rounded-md" />
<div className="italic whitespace-pre-line">
{translatedEvent?.content ?? event.content}
</div>
</div>
</div>
)
}

View File

@@ -6,7 +6,7 @@ import { toNote } from '@/lib/link'
import { useContentPolicy } from '@/providers/ContentPolicyProvider' import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useMuteList } from '@/providers/MuteListProvider' import { useMuteList } from '@/providers/MuteListProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Event, kinds } from 'nostr-tools' import { Event } from 'nostr-tools'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import ClientTag from '../ClientTag' import ClientTag from '../ClientTag'
@@ -15,12 +15,11 @@ import Content from '../Content'
import { FormattedTimestamp } from '../FormattedTimestamp' import { FormattedTimestamp } from '../FormattedTimestamp'
import Nip05 from '../Nip05' import Nip05 from '../Nip05'
import NoteOptions from '../NoteOptions' import NoteOptions from '../NoteOptions'
import ParentNotePreview from '../ParentNotePreview'
import StuffStats from '../StuffStats' import StuffStats from '../StuffStats'
import ParentNotePreview from '../ParentNotePreview'
import TranslateButton from '../TranslateButton' import TranslateButton from '../TranslateButton'
import UserAvatar from '../UserAvatar' import UserAvatar from '../UserAvatar'
import Username from '../Username' import Username from '../Username'
import Highlight from './Highlight'
export default function ReplyNote({ export default function ReplyNote({
event, event,
@@ -52,13 +51,6 @@ export default function ReplyNote({
return true return true
}, [showMuted, mutePubkeySet, event, hideContentMentioningMutedUsers]) }, [showMuted, mutePubkeySet, event, hideContentMentioningMutedUsers])
let content: React.ReactNode
if (event.kind === kinds.Highlights) {
content = <Highlight className="mt-2" event={event} />
} else {
content = <Content className="mt-2" event={event} />
}
return ( return (
<div <div
className={`pb-3 border-b transition-colors duration-500 clickable ${highlight ? 'bg-primary/50' : ''}`} className={`pb-3 border-b transition-colors duration-500 clickable ${highlight ? 'bg-primary/50' : ''}`}
@@ -103,7 +95,7 @@ export default function ReplyNote({
/> />
)} )}
{show ? ( {show ? (
content <Content className="mt-2" event={event} />
) : ( ) : (
<Button <Button
variant="outline" variant="outline"

View File

@@ -1,5 +1,4 @@
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants' import { BIG_RELAY_URLS, ExtendedKind } from '@/constants'
import { useStuff } from '@/hooks/useStuff'
import { import {
getEventKey, getEventKey,
getKeyFromTag, getKeyFromTag,
@@ -24,6 +23,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { LoadingBar } from '../LoadingBar' import { LoadingBar } from '../LoadingBar'
import ReplyNote, { ReplyNoteSkeleton } from '../ReplyNote' import ReplyNote, { ReplyNoteSkeleton } from '../ReplyNote'
import { useStuff } from '@/hooks/useStuff'
type TRootInfo = type TRootInfo =
| { type: 'E'; id: string; pubkey: string } | { type: 'E'; id: string; pubkey: string }
@@ -144,7 +144,7 @@ export default function ReplyNoteList({
if (rootInfo.type === 'E') { if (rootInfo.type === 'E') {
filters.push({ filters.push({
'#e': [rootInfo.id], '#e': [rootInfo.id],
kinds: [kinds.ShortTextNote, kinds.Highlights], kinds: [kinds.ShortTextNote],
limit: LIMIT limit: LIMIT
}) })
if (event?.kind !== kinds.ShortTextNote) { if (event?.kind !== kinds.ShortTextNote) {
@@ -158,7 +158,7 @@ export default function ReplyNoteList({
filters.push( filters.push(
{ {
'#a': [rootInfo.id], '#a': [rootInfo.id],
kinds: [kinds.ShortTextNote, kinds.Highlights], kinds: [kinds.ShortTextNote],
limit: LIMIT limit: LIMIT
}, },
{ {
@@ -171,18 +171,11 @@ export default function ReplyNoteList({
relayUrls.push(rootInfo.relay) relayUrls.push(rootInfo.relay)
} }
} else { } else {
filters.push( filters.push({
{
'#I': [rootInfo.id], '#I': [rootInfo.id],
kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT], kinds: [ExtendedKind.COMMENT, ExtendedKind.VOICE_COMMENT],
limit: LIMIT limit: LIMIT
}, })
{
'#r': [rootInfo.id],
kinds: [kinds.Highlights],
limit: LIMIT
}
)
} }
const { closer, timelineKey } = await client.subscribeTimeline( const { closer, timelineKey } = await client.subscribeTimeline(
filters.map((filter) => ({ filters.map((filter) => ({
@@ -192,9 +185,7 @@ export default function ReplyNoteList({
{ {
onEvents: (evts, eosed) => { onEvents: (evts, eosed) => {
if (evts.length > 0) { if (evts.length > 0) {
addReplies( addReplies(evts.filter((evt) => isReplyNoteEvent(evt)))
evts.filter((evt) => isReplyNoteEvent(evt) || evt.kind === kinds.Highlights)
)
} }
if (eosed) { if (eosed) {
setUntil(evts.length >= LIMIT ? evts[evts.length - 1].created_at - 1 : undefined) setUntil(evts.length >= LIMIT ? evts[evts.length - 1].created_at - 1 : undefined)
@@ -202,7 +193,7 @@ export default function ReplyNoteList({
} }
}, },
onNew: (evt) => { onNew: (evt) => {
if (!isReplyNoteEvent(evt) || evt.kind === kinds.Highlights) return if (!isReplyNoteEvent(evt)) return
addReplies([evt]) addReplies([evt])
} }
} }
@@ -258,9 +249,7 @@ export default function ReplyNoteList({
setLoading(true) setLoading(true)
const events = await client.loadMoreTimeline(timelineKey, until, LIMIT) const events = await client.loadMoreTimeline(timelineKey, until, LIMIT)
const olderEvents = events.filter( const olderEvents = events.filter((evt) => isReplyNoteEvent(evt))
(evt) => isReplyNoteEvent(evt) || evt.kind === kinds.Highlights
)
if (olderEvents.length > 0) { if (olderEvents.length > 0) {
addReplies(olderEvents) addReplies(olderEvents)
} }

View File

@@ -403,34 +403,3 @@ export function getPinnedEventHexIdSetFromPinListEvent(event?: Event | null): Se
.slice(0, MAX_PINNED_NOTES) ?? [] .slice(0, MAX_PINNED_NOTES) ?? []
) )
} }
export function getHighlightSourceTag(event: Event) {
let sourceTag: string[] | undefined
for (const tag of event.tags) {
// Highest priority: 'source' tag
if (tag[2] === 'source') {
sourceTag = tag
break
}
// Give 'e' tags highest priority
if (tag[0] === 'e') {
sourceTag = tag
continue
}
// Give 'a' tags second priority over 'e' tags
if (tag[0] === 'a' && (!sourceTag || sourceTag[0] !== 'e')) {
sourceTag = tag
continue
}
// Give 'r' tags lowest priority
if (tag[0] === 'r' && (!sourceTag || sourceTag[0] === 'r')) {
sourceTag = tag
continue
}
}
return sourceTag
}

View File

@@ -1,6 +1,5 @@
import { getEventKey, getKeyFromTag, getParentTag } from '@/lib/event' import { getEventKey, getKeyFromTag, getParentTag } from '@/lib/event'
import { getHighlightSourceTag } from '@/lib/event-metadata' import { Event } from 'nostr-tools'
import { Event, kinds } from 'nostr-tools'
import { createContext, useCallback, useContext, useState } from 'react' import { createContext, useCallback, useContext, useState } from 'react'
type TReplyContext = { type TReplyContext = {
@@ -31,26 +30,13 @@ export function ReplyProvider({ children }: { children: React.ReactNode }) {
if (newReplyKeySet.has(key)) return if (newReplyKeySet.has(key)) return
newReplyKeySet.add(key) newReplyKeySet.add(key)
let parentKey: string | undefined
if (reply.kind === kinds.Highlights) {
console.log('reply', reply)
const sourceTag = getHighlightSourceTag(reply)
if (!sourceTag) return
parentKey = getKeyFromTag(sourceTag)
} else {
const parentTag = getParentTag(reply) const parentTag = getParentTag(reply)
if (!parentTag) return if (parentTag) {
const parentKey = getKeyFromTag(parentTag.tag)
parentKey = getKeyFromTag(parentTag.tag)
}
if (parentKey) { if (parentKey) {
if (reply.kind === kinds.Highlights) {
console.log('parentKey', parentKey)
}
newReplyEventMap.set(parentKey, [...(newReplyEventMap.get(parentKey) || []), reply]) newReplyEventMap.set(parentKey, [...(newReplyEventMap.get(parentKey) || []), reply])
} }
}
}) })
if (newReplyEventMap.size === 0) return if (newReplyEventMap.size === 0) return