diff --git a/src/components/Notes/NoteRender.tsx b/src/components/Notes/NoteRender.tsx
index 94833f2..4d97a0f 100644
--- a/src/components/Notes/NoteRender.tsx
+++ b/src/components/Notes/NoteRender.tsx
@@ -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 (
-
+
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(
+ ,
+ document.body
+ )}
+ >
+ )
}
function handleNaddr(data: nip19.AddressPointer, original: string) {
diff --git a/src/styles/comments.css b/src/styles/comments.css
index c0ab065..abb964b 100644
--- a/src/styles/comments.css
+++ b/src/styles/comments.css
@@ -639,3 +639,8 @@ hover {
.IBMSMSMBSSCL_CBText > *:last-child {
margin-bottom: 0;
}
+
+/* Lightbox exception */
+.IBMSMSMBSSCL_CBText > .fslightbox-container {
+ margin: 0
+}
diff --git a/src/styles/feed.css b/src/styles/feed.css
index bac72cd..287af3e 100644
--- a/src/styles/feed.css
+++ b/src/styles/feed.css
@@ -170,6 +170,7 @@
width: 100%;
border-radius: 10px;
box-shadow: 0 0 8px 0 rgb(0,0,0,0.25);
+ cursor: pointer;
}
.videoFeedRender {