index.tsx raw

   1  import {
   2    EmbeddedHashtagParser,
   3    EmbeddedUrlParser,
   4    EmbeddedWebsocketUrlParser,
   5    parseContent
   6  } from '@/lib/content-parser'
   7  import { cn } from '@/lib/utils'
   8  import { useMemo } from 'react'
   9  import { EmbeddedHashtag, EmbeddedLNInvoice, EmbeddedWebsocketUrl } from '../Embedded'
  10  import ImageGallery from '../ImageGallery'
  11  import MediaPlayer from '../MediaPlayer'
  12  import WebPreview from '../WebPreview'
  13  import XEmbeddedPost from '../XEmbeddedPost'
  14  import YoutubeEmbeddedPlayer from '../YoutubeEmbeddedPlayer'
  15  
  16  export default function ExternalContent({
  17    content,
  18    className,
  19    mustLoadMedia
  20  }: {
  21    content?: string
  22    className?: string
  23    mustLoadMedia?: boolean
  24  }) {
  25    const nodes = useMemo(() => {
  26      if (!content) return []
  27  
  28      return parseContent(content, [
  29        EmbeddedUrlParser,
  30        EmbeddedWebsocketUrlParser,
  31        EmbeddedHashtagParser
  32      ])
  33    }, [content])
  34  
  35    if (!nodes || nodes.length === 0) {
  36      return null
  37    }
  38  
  39    const node = nodes[0]
  40  
  41    if (node.type === 'text') {
  42      return (
  43        <div className={cn('text-wrap break-words whitespace-pre-wrap', className)}>{content}</div>
  44      )
  45    }
  46  
  47    if (node.type === 'url') {
  48      return <WebPreview url={node.data} className={className} mustLoad={mustLoadMedia} />
  49    }
  50  
  51    if (node.type === 'x-post') {
  52      return (
  53        <XEmbeddedPost
  54          url={node.data}
  55          className={className}
  56          mustLoad={mustLoadMedia}
  57          embedded={false}
  58        />
  59      )
  60    }
  61  
  62    if (node.type === 'youtube') {
  63      return <YoutubeEmbeddedPlayer url={node.data} className={className} mustLoad={mustLoadMedia} />
  64    }
  65  
  66    if (node.type === 'image' || node.type === 'images') {
  67      const data = Array.isArray(node.data) ? node.data : [node.data]
  68      return (
  69        <ImageGallery
  70          className={className}
  71          images={data.map((url) => ({ url }))}
  72          mustLoad={mustLoadMedia}
  73        />
  74      )
  75    }
  76  
  77    if (node.type === 'media') {
  78      return <MediaPlayer className={className} src={node.data} mustLoad={mustLoadMedia} />
  79    }
  80  
  81    if (node.type === 'invoice') {
  82      return <EmbeddedLNInvoice invoice={node.data} className={className} />
  83    }
  84  
  85    if (node.type === 'websocket-url') {
  86      return <EmbeddedWebsocketUrl url={node.data} />
  87    }
  88  
  89    if (node.type === 'hashtag') {
  90      return <EmbeddedHashtag hashtag={node.data} />
  91    }
  92  
  93    return null
  94  }
  95