feat(notes): image gallery
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m8s

This commit is contained in:
en 2025-02-27 14:54:36 +01:00
parent 6dcf139989
commit 0167f90326
3 changed files with 69 additions and 4 deletions

View File

@ -1,7 +1,7 @@
import { NDKKind } from '@nostr-dev-kit/ndk'
import { ProfileLink } from 'components/ProfileSection'
import { nip19 } from 'nostr-tools'
import { useMemo } from 'react'
import { useCallback, useMemo, useState } from 'react'
import { Fragment } from 'react/jsx-runtime'
import { BlogPreview } from './internal/BlogPreview'
import { ModPreview } from './internal/ModPreview'
@ -14,6 +14,8 @@ import {
isValidVideoUrl,
isYoutubeLink
} from 'utils'
import FsLightbox from 'fslightbox-react'
import { createPortal } from 'react-dom'
interface NoteRenderProps {
content: string
@ -28,6 +30,44 @@ const nostrNip05Mention = /(?:nostr:|@)[^\s]{1,64}@[^\s]+\.[^\s]{2,}/i
const nip05Entity = /(?:nostr:|@)([^\s]{1,64}@[^\s]+\.[^\s]{2,})/i
export const NoteRender = ({ content }: NoteRenderProps) => {
const [lightBoxController, setLightBoxController] = useState({
toggler: false,
slide: 1
})
const slides = useMemo(() => {
const urls: string[] = []
const parts = content.matchAll(new RegExp(`${link.source}`, 'gui'))
;[...parts]
.filter((p) => typeof p !== 'undefined')
.forEach((part) => {
const [href] = part
if (href && isValidUrl(href)) {
if (isValidImageUrl(href) || isValidVideoUrl(href)) {
urls.push(href)
} else if (isYoutubeLink(href)) {
const id = getIdFromYoutubeLink(href)
if (id) {
urls.push(`https://www.youtube.com/embed/${id}`)
}
}
}
})
return urls
}, [content])
const openLightBoxOnSlide = useCallback(
(url: string) => {
slides.length &&
setLightBoxController((prev) => ({
toggler: !prev.toggler,
slide: slides.findIndex((s) => s === url) + 1
}))
},
[slides]
)
const _content = useMemo(() => {
if (!content) return
@ -49,7 +89,13 @@ export const NoteRender = ({ content }: NoteRenderProps) => {
if (isValidImageUrl(href)) {
// Image
return (
<img key={key} className='imgFeedRender' src={href} alt='' />
<img
key={key}
className='imgFeedRender'
src={href}
alt=''
onClick={() => openLightBoxOnSlide(href)}
/>
)
} else if (isValidVideoUrl(href)) {
// Video
@ -129,9 +175,22 @@ export const NoteRender = ({ content }: NoteRenderProps) => {
}
})
return _parts
}, [content])
}, [content, openLightBoxOnSlide])
return _content
return (
<>
{_content}
{slides.length > 0 &&
createPortal(
<FsLightbox
toggler={lightBoxController.toggler}
sources={slides}
slide={lightBoxController.slide}
/>,
document.body
)}
</>
)
}
function handleNaddr(data: nip19.AddressPointer, original: string) {

View File

@ -639,3 +639,8 @@ hover {
.IBMSMSMBSSCL_CBText > *:last-child {
margin-bottom: 0;
}
/* Lightbox exception */
.IBMSMSMBSSCL_CBText > .fslightbox-container {
margin: 0
}

View File

@ -170,6 +170,7 @@
width: 100%;
border-radius: 10px;
box-shadow: 0 0 8px 0 rgb(0,0,0,0.25);
cursor: pointer;
}
.videoFeedRender {