feat(notes): image gallery
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m8s
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m8s
This commit is contained in:
parent
6dcf139989
commit
0167f90326
@ -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) {
|
||||
|
@ -639,3 +639,8 @@ hover {
|
||||
.IBMSMSMBSSCL_CBText > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Lightbox exception */
|
||||
.IBMSMSMBSSCL_CBText > .fslightbox-container {
|
||||
margin: 0
|
||||
}
|
||||
|
@ -170,6 +170,7 @@
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 8px 0 rgb(0,0,0,0.25);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.videoFeedRender {
|
||||
|
Loading…
x
Reference in New Issue
Block a user