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 { NDKKind } from '@nostr-dev-kit/ndk'
|
||||||
import { ProfileLink } from 'components/ProfileSection'
|
import { ProfileLink } from 'components/ProfileSection'
|
||||||
import { nip19 } from 'nostr-tools'
|
import { nip19 } from 'nostr-tools'
|
||||||
import { useMemo } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { Fragment } from 'react/jsx-runtime'
|
import { Fragment } from 'react/jsx-runtime'
|
||||||
import { BlogPreview } from './internal/BlogPreview'
|
import { BlogPreview } from './internal/BlogPreview'
|
||||||
import { ModPreview } from './internal/ModPreview'
|
import { ModPreview } from './internal/ModPreview'
|
||||||
@ -14,6 +14,8 @@ import {
|
|||||||
isValidVideoUrl,
|
isValidVideoUrl,
|
||||||
isYoutubeLink
|
isYoutubeLink
|
||||||
} from 'utils'
|
} from 'utils'
|
||||||
|
import FsLightbox from 'fslightbox-react'
|
||||||
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
interface NoteRenderProps {
|
interface NoteRenderProps {
|
||||||
content: string
|
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
|
const nip05Entity = /(?:nostr:|@)([^\s]{1,64}@[^\s]+\.[^\s]{2,})/i
|
||||||
|
|
||||||
export const NoteRender = ({ content }: NoteRenderProps) => {
|
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(() => {
|
const _content = useMemo(() => {
|
||||||
if (!content) return
|
if (!content) return
|
||||||
|
|
||||||
@ -49,7 +89,13 @@ export const NoteRender = ({ content }: NoteRenderProps) => {
|
|||||||
if (isValidImageUrl(href)) {
|
if (isValidImageUrl(href)) {
|
||||||
// Image
|
// Image
|
||||||
return (
|
return (
|
||||||
<img key={key} className='imgFeedRender' src={href} alt='' />
|
<img
|
||||||
|
key={key}
|
||||||
|
className='imgFeedRender'
|
||||||
|
src={href}
|
||||||
|
alt=''
|
||||||
|
onClick={() => openLightBoxOnSlide(href)}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
} else if (isValidVideoUrl(href)) {
|
} else if (isValidVideoUrl(href)) {
|
||||||
// Video
|
// Video
|
||||||
@ -129,9 +175,22 @@ export const NoteRender = ({ content }: NoteRenderProps) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return _parts
|
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) {
|
function handleNaddr(data: nip19.AddressPointer, original: string) {
|
||||||
|
@ -639,3 +639,8 @@ hover {
|
|||||||
.IBMSMSMBSSCL_CBText > *:last-child {
|
.IBMSMSMBSSCL_CBText > *:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lightbox exception */
|
||||||
|
.IBMSMSMBSSCL_CBText > .fslightbox-container {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
@ -170,6 +170,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 0 8px 0 rgb(0,0,0,0.25);
|
box-shadow: 0 0 8px 0 rgb(0,0,0,0.25);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.videoFeedRender {
|
.videoFeedRender {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user