Content.tsx raw
1 import {
2 EmbeddedEmojiParser,
3 EmbeddedEventParser,
4 EmbeddedMentionParser,
5 EmbeddedUrlParser,
6 parseContent
7 } from '@/lib/content-parser'
8 import { cn } from '@/lib/utils'
9 import { TEmoji } from '@/types'
10 import { useMemo } from 'react'
11 import { useTranslation } from 'react-i18next'
12 import { EmbeddedMentionText } from '../Embedded'
13 import Emoji from '../Emoji'
14
15 export default function Content({
16 content,
17 className,
18 emojiInfos
19 }: {
20 content: string
21 className?: string
22 emojiInfos?: TEmoji[]
23 }) {
24 const { t } = useTranslation()
25 const nodes = useMemo(() => {
26 return parseContent(content, [
27 EmbeddedEventParser,
28 EmbeddedMentionParser,
29 EmbeddedUrlParser,
30 EmbeddedEmojiParser
31 ])
32 }, [content])
33
34 return (
35 <span className={cn('pointer-events-none', className)}>
36 {nodes.map((node, index) => {
37 if (node.type === 'image' || node.type === 'images') {
38 return index > 0 ? ` [${t('Image')}]` : `[${t('Image')}]`
39 }
40 if (node.type === 'media') {
41 return index > 0 ? ` [${t('Media')}]` : `[${t('Media')}]`
42 }
43 if (node.type === 'event') {
44 return index > 0 ? ` [${t('Note')}]` : `[${t('Note')}]`
45 }
46 if (node.type === 'mention') {
47 return <EmbeddedMentionText key={index} userId={node.data.split(':')[1]} />
48 }
49 if (node.type === 'emoji') {
50 const shortcode = node.data.split(':')[1]
51 const emoji = emojiInfos?.find((e) => e.shortcode === shortcode)
52 if (!emoji) return node.data
53 return <Emoji key={index} emoji={emoji} classNames={{ img: 'size-4' }} />
54 }
55 return node.data
56 })}
57 </span>
58 )
59 }
60