Browse Source

fix: 🐛

imwald
codytseng 5 months ago committed by Silberengel
parent
commit
90efcdc6ff
  1. 174
      src/components/Content/index.tsx
  2. 13
      src/components/YoutubeEmbeddedPlayer/index.tsx
  3. 2
      src/lib/content-parser.ts

174
src/components/Content/index.tsx

@ -16,7 +16,7 @@ import { cleanUrl } from '@/lib/url'
import mediaUpload from '@/services/media-upload.service' import mediaUpload from '@/services/media-upload.service'
import { TImetaInfo } from '@/types' import { TImetaInfo } from '@/types'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { memo } from 'react' import { useMemo } from 'react'
import { import {
EmbeddedHashtag, EmbeddedHashtag,
EmbeddedLNInvoice, EmbeddedLNInvoice,
@ -31,21 +31,21 @@ import MediaPlayer from '../MediaPlayer'
import WebPreview from '../WebPreview' import WebPreview from '../WebPreview'
import YoutubeEmbeddedPlayer from '../YoutubeEmbeddedPlayer' import YoutubeEmbeddedPlayer from '../YoutubeEmbeddedPlayer'
const Content = memo( export default function Content({
({ event,
event, content,
content, className,
className, mustLoadMedia
mustLoadMedia }: {
}: { event?: Event
event?: Event content?: string
content?: string className?: string
className?: string mustLoadMedia?: boolean
mustLoadMedia?: boolean }) {
}) => { const translatedEvent = useTranslatedEvent(event?.id)
const translatedEvent = useTranslatedEvent(event?.id) const { nodes, allImages, lastNormalUrl, emojiInfos } = useMemo(() => {
const _content = translatedEvent?.content ?? event?.content ?? content const _content = translatedEvent?.content ?? event?.content ?? content
if (!_content) return null if (!_content) return {}
const nodes = parseContent(_content, [ const nodes = parseContent(_content, [
EmbeddedUrlParser, EmbeddedUrlParser,
@ -104,7 +104,6 @@ const Content = memo(
}) })
.filter(Boolean) .filter(Boolean)
.flat() as TImetaInfo[] .flat() as TImetaInfo[]
let imageIndex = 0
const emojiInfos = getEmojiInfosFromEmojiTags(event?.tags) const emojiInfos = getEmojiInfosFromEmojiTags(event?.tags)
@ -112,73 +111,78 @@ const Content = memo(
const lastNormalUrl = const lastNormalUrl =
typeof lastNormalUrlNode?.data === 'string' ? lastNormalUrlNode.data : undefined typeof lastNormalUrlNode?.data === 'string' ? lastNormalUrlNode.data : undefined
return ( return { nodes, allImages, emojiInfos, lastNormalUrl }
<div className={cn('text-wrap break-words whitespace-pre-wrap', className)}> }, [event])
{nodes.map((node, index) => {
if (node.type === 'text') { if (!nodes || nodes.length === 0) {
return node.data return null
}
if (node.type === 'image' || node.type === 'images') {
const start = imageIndex
const end = imageIndex + (Array.isArray(node.data) ? node.data.length : 1)
imageIndex = end
return (
<ImageGallery
className="mt-2"
key={index}
images={allImages}
start={start}
end={end}
mustLoad={mustLoadMedia}
/>
)
}
if (node.type === 'media') {
return (
<MediaPlayer className="mt-2" key={index} src={node.data} mustLoad={mustLoadMedia} />
)
}
if (node.type === 'url') {
return <EmbeddedNormalUrl url={node.data} key={index} />
}
if (node.type === 'invoice') {
return <EmbeddedLNInvoice invoice={node.data} key={index} className="mt-2" />
}
if (node.type === 'websocket-url') {
return <EmbeddedWebsocketUrl url={node.data} key={index} />
}
if (node.type === 'event') {
const id = node.data.split(':')[1]
return <EmbeddedNote key={index} noteId={id} className="mt-2" />
}
if (node.type === 'mention') {
return <EmbeddedMention key={index} userId={node.data.split(':')[1]} />
}
if (node.type === 'hashtag') {
return <EmbeddedHashtag hashtag={node.data} key={index} />
}
if (node.type === 'emoji') {
const shortcode = node.data.split(':')[1]
const emoji = emojiInfos.find((e) => e.shortcode === shortcode)
if (!emoji) return node.data
return <Emoji classNames={{ img: 'mb-1' }} emoji={emoji} key={index} />
}
if (node.type === 'youtube') {
return (
<YoutubeEmbeddedPlayer
key={index}
url={node.data}
className="mt-2"
mustLoad={mustLoadMedia}
/>
)
}
return null
})}
{lastNormalUrl && <WebPreview className="mt-2" url={lastNormalUrl} />}
</div>
)
} }
)
Content.displayName = 'Content' let imageIndex = 0
export default Content return (
<div className={cn('text-wrap break-words whitespace-pre-wrap', className)}>
{nodes.map((node, index) => {
if (node.type === 'text') {
return node.data
}
if (node.type === 'image' || node.type === 'images') {
const start = imageIndex
const end = imageIndex + (Array.isArray(node.data) ? node.data.length : 1)
imageIndex = end
return (
<ImageGallery
className="mt-2"
key={index}
images={allImages}
start={start}
end={end}
mustLoad={mustLoadMedia}
/>
)
}
if (node.type === 'media') {
return (
<MediaPlayer className="mt-2" key={index} src={node.data} mustLoad={mustLoadMedia} />
)
}
if (node.type === 'url') {
return <EmbeddedNormalUrl url={node.data} key={index} />
}
if (node.type === 'invoice') {
return <EmbeddedLNInvoice invoice={node.data} key={index} className="mt-2" />
}
if (node.type === 'websocket-url') {
return <EmbeddedWebsocketUrl url={node.data} key={index} />
}
if (node.type === 'event') {
const id = node.data.split(':')[1]
return <EmbeddedNote key={index} noteId={id} className="mt-2" />
}
if (node.type === 'mention') {
return <EmbeddedMention key={index} userId={node.data.split(':')[1]} />
}
if (node.type === 'hashtag') {
return <EmbeddedHashtag hashtag={node.data} key={index} />
}
if (node.type === 'emoji') {
const shortcode = node.data.split(':')[1]
const emoji = emojiInfos.find((e) => e.shortcode === shortcode)
if (!emoji) return node.data
return <Emoji classNames={{ img: 'mb-1' }} emoji={emoji} key={index} />
}
if (node.type === 'youtube') {
return (
<YoutubeEmbeddedPlayer
key={index}
url={node.data}
className="mt-2"
mustLoad={mustLoadMedia}
/>
)
}
return null
})}
{lastNormalUrl && <WebPreview className="mt-2" url={lastNormalUrl} />}
</div>
)
}

13
src/components/YoutubeEmbeddedPlayer/index.tsx

@ -71,6 +71,7 @@ export default function YoutubeEmbeddedPlayer({
}) })
} catch (error) { } catch (error) {
console.error('Failed to initialize YouTube player:', error) console.error('Failed to initialize YouTube player:', error)
setError(true)
return return
} }
} }
@ -101,18 +102,8 @@ export default function YoutubeEmbeddedPlayer({
} }
if (!videoId && !initSuccess) { if (!videoId && !initSuccess) {
return ( return <ExternalLink url={url} />
<a
href={url}
className="text-primary hover:underline"
target="_blank"
rel="noopener noreferrer"
>
{url}
</a>
)
} }
return ( return (
<div <div
className={cn( className={cn(

2
src/lib/content-parser.ts

@ -94,7 +94,7 @@ export const EmbeddedUrlParser: TContentParser = (content: string) => {
type = 'image' type = 'image'
} else if (isMedia(url)) { } else if (isMedia(url)) {
type = 'media' type = 'media'
} else if (YOUTUBE_URL_REGEX.test(url)) { } else if (url.match(YOUTUBE_URL_REGEX)) {
type = 'youtube' type = 'youtube'
} }

Loading…
Cancel
Save