index.tsx raw

   1  import { randomString } from '@/lib/random'
   2  import { cn } from '@/lib/utils'
   3  import { useContentPolicy } from '@/providers/ContentPolicyProvider'
   4  import modalManager from '@/services/modal-manager.service'
   5  import { TImetaInfo } from '@/types'
   6  import { useEffect, useMemo, useState } from 'react'
   7  import { createPortal } from 'react-dom'
   8  import { useTranslation } from 'react-i18next'
   9  import Lightbox from 'yet-another-react-lightbox'
  10  import Zoom from 'yet-another-react-lightbox/plugins/zoom'
  11  import Image from '../Image'
  12  
  13  export default function ImageWithLightbox({
  14    image,
  15    className,
  16    classNames = {},
  17    errorPlaceholder,
  18    ignoreAutoLoadPolicy = false
  19  }: {
  20    image: TImetaInfo
  21    className?: string
  22    classNames?: {
  23      wrapper?: string
  24      skeleton?: string
  25    }
  26    errorPlaceholder?: string
  27    ignoreAutoLoadPolicy?: boolean
  28  }) {
  29    const id = useMemo(() => `image-with-lightbox-${randomString()}`, [])
  30    const { t } = useTranslation()
  31    const { autoLoadMedia } = useContentPolicy()
  32    const [display, setDisplay] = useState(ignoreAutoLoadPolicy ? true : autoLoadMedia)
  33    const [index, setIndex] = useState(-1)
  34    useEffect(() => {
  35      if (index >= 0) {
  36        modalManager.register(id, () => {
  37          setIndex(-1)
  38        })
  39      } else {
  40        modalManager.unregister(id)
  41      }
  42    }, [index])
  43  
  44    if (!display) {
  45      return (
  46        <div
  47          className="text-primary hover:underline truncate w-fit cursor-pointer"
  48          onClick={(e) => {
  49            e.stopPropagation()
  50            setDisplay(true)
  51          }}
  52        >
  53          [{t('Click to load image')}]
  54        </div>
  55      )
  56    }
  57  
  58    const handlePhotoClick = (event: React.MouseEvent) => {
  59      event.stopPropagation()
  60      event.preventDefault()
  61      setIndex(0)
  62    }
  63  
  64    return (
  65      <div>
  66        <Image
  67          key={0}
  68          className={className}
  69          classNames={{
  70            wrapper: cn('border cursor-zoom-in', classNames.wrapper),
  71            errorPlaceholder: 'aspect-square h-[30vh]',
  72            skeleton: classNames.skeleton
  73          }}
  74          image={image}
  75          onClick={(e) => handlePhotoClick(e)}
  76          errorPlaceholder={errorPlaceholder}
  77        />
  78        {index >= 0 &&
  79          createPortal(
  80            <div onClick={(e) => e.stopPropagation()}>
  81              <Lightbox
  82                index={index}
  83                slides={[{ src: image.url }]}
  84                plugins={[Zoom]}
  85                open={index >= 0}
  86                close={() => setIndex(-1)}
  87                controller={{
  88                  closeOnBackdropClick: true,
  89                  closeOnPullUp: true,
  90                  closeOnPullDown: true
  91                }}
  92                styles={{
  93                  toolbar: { paddingTop: '2.25rem' }
  94                }}
  95              />
  96            </div>,
  97            document.body
  98          )}
  99      </div>
 100    )
 101  }
 102