Bpistle/src/components/ContentPreview/ReactionPreview.tsx
codytseng 234010c385 feat: add support for displaying kind 7 and kind 17 reaction events
Reactions now render with a large emoji (matching emoji-only note sizing)
and a "reacted to" preview pill linking to the target event, following
the same pattern as comment parent previews.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:56:04 +08:00

50 lines
1.4 KiB
TypeScript

import Image from '@/components/Image'
import { cn } from '@/lib/utils'
import { Heart } from 'lucide-react'
import { Event } from 'nostr-tools'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
export default function ReactionPreview({
event,
className
}: {
event: Event
className?: string
}) {
const { t } = useTranslation()
const reaction = useMemo(() => {
if (!event.content || event.content === '+') {
return <Heart size={14} className="inline text-red-400" />
}
const emojiName = /^:([^:]+):$/.exec(event.content)?.[1]
if (emojiName) {
const emojiTag = event.tags.find((tag) => tag[0] === 'emoji' && tag[1] === emojiName)
const emojiUrl = emojiTag?.[2]
if (emojiUrl) {
return (
<Image
image={{ url: emojiUrl, pubkey: event.pubkey }}
alt={emojiName}
className="inline-block h-4 w-4"
classNames={{ errorPlaceholder: 'bg-transparent', wrapper: 'inline-block rounded-md' }}
errorPlaceholder={<Heart size={14} className="inline text-red-400" />}
/>
)
}
}
if (event.content.length > 4) {
return <Heart size={14} className="inline text-red-400" />
}
return <span>{event.content}</span>
}, [event])
return (
<div className={cn('flex items-center gap-1 truncate', className)}>
<span className="truncate">[{t('Reaction')}]</span>
{reaction}
</div>
)
}