feat: add lightbox to profile avatar and banner (#661)

This commit is contained in:
Alex Gleason 2025-11-14 08:02:21 -06:00 committed by GitHub
parent 82c13006ff
commit 19eaf1a4e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 160 additions and 6 deletions

View file

@ -1,6 +1,11 @@
import { generateImageByPubkey } from '@/lib/pubkey'
import { randomString } from '@/lib/random'
import { cn } from '@/lib/utils'
import modalManager from '@/services/modal-manager.service'
import { useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom'
import Lightbox from 'yet-another-react-lightbox'
import Zoom from 'yet-another-react-lightbox/plugins/zoom'
import Image from '../Image'
export default function ProfileBanner({
@ -32,3 +37,78 @@ export default function ProfileBanner({
/>
)
}
export function BannerWithLightbox({
pubkey,
banner,
className
}: {
pubkey: string
banner?: string
className?: string
}) {
const id = useMemo(() => `profile-banner-lightbox-${randomString()}`, [])
const defaultBanner = useMemo(() => generateImageByPubkey(pubkey), [pubkey])
const [bannerUrl, setBannerUrl] = useState(banner ?? defaultBanner)
const [index, setIndex] = useState(-1)
useEffect(() => {
if (banner) {
setBannerUrl(banner)
} else {
setBannerUrl(defaultBanner)
}
}, [defaultBanner, banner])
useEffect(() => {
if (index >= 0) {
modalManager.register(id, () => {
setIndex(-1)
})
} else {
modalManager.unregister(id)
}
}, [index, id])
const handleBannerClick = (event: React.MouseEvent) => {
event.stopPropagation()
event.preventDefault()
setIndex(0)
}
return (
<>
<Image
image={{ url: bannerUrl, pubkey }}
alt={`${pubkey} banner`}
className={cn('rounded-none', className)}
classNames={{
wrapper: 'cursor-zoom-in'
}}
errorPlaceholder={defaultBanner}
onClick={handleBannerClick}
/>
{index >= 0 &&
createPortal(
<div onClick={(e) => e.stopPropagation()}>
<Lightbox
index={index}
slides={[{ src: bannerUrl }]}
plugins={[Zoom]}
open={index >= 0}
close={() => setIndex(-1)}
controller={{
closeOnBackdropClick: true,
closeOnPullUp: true,
closeOnPullDown: true
}}
styles={{
toolbar: { paddingTop: '2.25rem' }
}}
/>
</div>,
document.body
)}
</>
)
}