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