index.tsx raw

   1  import { useFetchWebMetadata } from '@/hooks/useFetchWebMetadata'
   2  import { cn } from '@/lib/utils'
   3  import { useContentPolicy } from '@/providers/ContentPolicyProvider'
   4  import { useScreenSize } from '@/providers/ScreenSizeProvider'
   5  import { useMemo } from 'react'
   6  import Image from '../Image'
   7  import ExternalLink from '../ExternalLink'
   8  
   9  export default function WebPreview({
  10    url,
  11    className,
  12    mustLoad
  13  }: {
  14    url: string
  15    className?: string
  16    mustLoad?: boolean
  17  }) {
  18    const { autoLoadMedia } = useContentPolicy()
  19    const { isSmallScreen } = useScreenSize()
  20    const { title, description, image } = useFetchWebMetadata(url)
  21  
  22    const hostname = useMemo(() => {
  23      try {
  24        return new URL(url).hostname
  25      } catch {
  26        return ''
  27      }
  28    }, [url])
  29  
  30    if (!autoLoadMedia && !mustLoad) {
  31      return null
  32    }
  33  
  34    if (!title) {
  35      if (mustLoad) {
  36        return <ExternalLink url={url} justOpenLink />
  37      } else {
  38        return null
  39      }
  40    }
  41  
  42    if (isSmallScreen && image) {
  43      return (
  44        <div
  45          className="rounded-xl border mt-2 overflow-hidden"
  46          onClick={(e) => {
  47            e.stopPropagation()
  48            window.open(url, '_blank')
  49          }}
  50        >
  51          <Image image={{ url: image }} className="w-full h-44 rounded-none" hideIfError />
  52          <div className="bg-muted p-2 w-full">
  53            <div className="text-xs text-muted-foreground">{hostname}</div>
  54            <div className="font-semibold line-clamp-1">{title}</div>
  55          </div>
  56        </div>
  57      )
  58    }
  59  
  60    return (
  61      <div
  62        className={cn('p-0 clickable flex w-full border rounded-xl overflow-hidden', className)}
  63        onClick={(e) => {
  64          e.stopPropagation()
  65          window.open(url, '_blank')
  66        }}
  67      >
  68        {image && (
  69          <Image
  70            image={{ url: image }}
  71            className="aspect-[4/3] xl:aspect-video bg-foreground h-44"
  72            classNames={{
  73              wrapper: 'rounded-none border-r'
  74            }}
  75            hideIfError
  76          />
  77        )}
  78        <div className="flex-1 w-0 p-2">
  79          <div className="text-xs text-muted-foreground">{hostname}</div>
  80          <div className="font-semibold line-clamp-2">{title}</div>
  81          <div className="text-xs text-muted-foreground line-clamp-5">{description}</div>
  82        </div>
  83      </div>
  84    )
  85  }
  86