Browse Source

fixed discussion video display and scroll bar

imwald
Silberengel 5 months ago
parent
commit
f97313074a
  1. 107
      src/components/UniversalContent/SimpleContent.tsx
  2. 14
      src/layouts/SecondaryPageLayout/index.tsx
  3. 4
      src/pages/secondary/NotePage/index.tsx

107
src/components/UniversalContent/SimpleContent.tsx

@ -8,6 +8,7 @@ import { remarkNostr } from '../Note/LongFormArticle/remarkNostr'
import NostrNode from '../Note/LongFormArticle/NostrNode' import NostrNode from '../Note/LongFormArticle/NostrNode'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import ImageWithLightbox from '../ImageWithLightbox' import ImageWithLightbox from '../ImageWithLightbox'
import MediaPlayer from '../MediaPlayer'
interface SimpleContentProps { interface SimpleContentProps {
event?: Event event?: Event
@ -22,6 +23,33 @@ export default function SimpleContent({
}: SimpleContentProps) { }: SimpleContentProps) {
const imetaInfos = useMemo(() => event ? getImetaInfosFromEvent(event) : [], [event]) const imetaInfos = useMemo(() => event ? getImetaInfosFromEvent(event) : [], [event])
// Extract video URLs from imeta tags to avoid duplicate rendering
const imetaVideoUrls = useMemo(() => {
return imetaInfos
.filter(info => {
// Check if the imeta info is a video by looking at the URL extension
const url = info.url
const extension = url.split('.').pop()?.toLowerCase()
return extension && ['mp4', 'webm', 'ogg', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'm4v'].includes(extension)
})
.map(info => {
// Clean the URL first, then normalize
const cleanedUrl = (() => {
try {
return cleanUrl(info.url)
} catch {
return info.url
}
})()
try {
return new URL(cleanedUrl).href
} catch {
return cleanedUrl
}
})
}, [imetaInfos])
const processedContent = useMemo(() => { const processedContent = useMemo(() => {
const rawContent = content || event?.content || '' const rawContent = content || event?.content || ''
@ -40,7 +68,7 @@ export default function SimpleContent({
return cleaned return cleaned
}, [content, event?.content]) }, [content, event?.content])
// Process content to handle images and markdown // Process content to handle images, videos and markdown
const { markdownContent, mediaElements } = useMemo(() => { const { markdownContent, mediaElements } = useMemo(() => {
const lines = processedContent.split('\n') const lines = processedContent.split('\n')
const elements: JSX.Element[] = [] const elements: JSX.Element[] = []
@ -73,16 +101,87 @@ export default function SimpleContent({
markdownLines.push(beforeImage + afterImage) markdownLines.push(beforeImage + afterImage)
} }
} else { } else {
// Regular text line - add to markdown processing // Check if line contains a video URL
markdownLines.push(line) const videoMatch = line.match(/(https?:\/\/[^\s]+\.(mp4|webm|ogg|avi|mov|wmv|flv|mkv|m4v))/i)
if (videoMatch) {
const originalVideoUrl = videoMatch[1]
// Clean the video URL to remove tracking parameters
const cleanedVideoUrl = (() => {
try {
return cleanUrl(originalVideoUrl)
} catch {
return originalVideoUrl
}
})()
// Check if this video URL is already handled by imeta tags
const normalizedVideoUrl = (() => {
try {
return new URL(cleanedVideoUrl).href
} catch {
return cleanedVideoUrl
}
})()
if (!imetaVideoUrls.includes(normalizedVideoUrl)) {
elements.push(
<div key={key++} className="my-4">
<MediaPlayer
src={cleanedVideoUrl}
className="max-w-full h-auto rounded-lg"
/>
</div>
)
}
// Add the rest of the line as text if there's anything else
const beforeVideo = line.substring(0, videoMatch.index).trim()
const afterVideo = line.substring(videoMatch.index! + originalVideoUrl.length).trim()
if (beforeVideo || afterVideo) {
markdownLines.push(beforeVideo + afterVideo)
}
} else {
// Regular text line - add to markdown processing
markdownLines.push(line)
}
} }
}) })
// Add imeta videos to the elements
imetaInfos
.filter(info => {
// Check if the imeta info is a video by looking at the URL extension
const url = info.url
const extension = url.split('.').pop()?.toLowerCase()
return extension && ['mp4', 'webm', 'ogg', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'm4v'].includes(extension)
})
.forEach(videoInfo => {
// Clean the imeta video URL to remove tracking parameters
const cleanedVideoUrl = (() => {
try {
return cleanUrl(videoInfo.url)
} catch {
return videoInfo.url
}
})()
elements.push(
<div key={key++} className="my-4">
<MediaPlayer
src={cleanedVideoUrl}
className="max-w-full h-auto rounded-lg"
/>
</div>
)
})
return { return {
markdownContent: markdownLines.join('\n'), markdownContent: markdownLines.join('\n'),
mediaElements: elements mediaElements: elements
} }
}, [processedContent, imetaInfos, event?.pubkey]) }, [processedContent, imetaInfos, event?.pubkey, imetaVideoUrls])
const components = useMemo(() => ({ const components = useMemo(() => ({
nostr: ({ rawText, bech32Id }: { rawText: string; bech32Id: string }) => ( nostr: ({ rawText, bech32Id }: { rawText: string; bech32Id: string }) => (

14
src/layouts/SecondaryPageLayout/index.tsx

@ -84,11 +84,7 @@ const SecondaryPageLayout = forwardRef(
return ( return (
<DeepBrowsingProvider active={currentIndex === index} scrollAreaRef={scrollAreaRef}> <DeepBrowsingProvider active={currentIndex === index} scrollAreaRef={scrollAreaRef}>
<ScrollArea <div className="h-full flex flex-col">
className="h-[calc(100vh-2rem)] overflow-auto"
scrollBarClassName={title ? "z-50 pt-12" : "z-50"}
ref={scrollAreaRef}
>
{title && ( {title && (
<SecondaryPageTitlebar <SecondaryPageTitlebar
title={title} title={title}
@ -98,9 +94,11 @@ const SecondaryPageLayout = forwardRef(
titlebar={titlebar} titlebar={titlebar}
/> />
)} )}
{children} <div className="flex-1" ref={scrollAreaRef}>
<div className="h-4" /> {children}
</ScrollArea> <div className="h-4" />
</div>
</div>
{displayScrollToTopButton && <ScrollToTopButton scrollAreaRef={scrollAreaRef} />} {displayScrollToTopButton && <ScrollToTopButton scrollAreaRef={scrollAreaRef} />}
</DeepBrowsingProvider> </DeepBrowsingProvider>
) )

4
src/pages/secondary/NotePage/index.tsx

@ -102,7 +102,9 @@ const NotePage = forwardRef(({ id, index, hideTitlebar = false }: { id?: string;
<NoteStats className="mt-3" event={finalEvent} fetchIfNotExisting displayTopZapsAndLikes /> <NoteStats className="mt-3" event={finalEvent} fetchIfNotExisting displayTopZapsAndLikes />
</div> </div>
<Separator className="mt-4" /> <Separator className="mt-4" />
<NoteInteractions key={`note-interactions-${finalEvent.id}`} pageIndex={index} event={finalEvent} /> <div className="px-4 pb-4">
<NoteInteractions key={`note-interactions-${finalEvent.id}`} pageIndex={index} event={finalEvent} />
</div>
</SecondaryPageLayout> </SecondaryPageLayout>
) )
}) })

Loading…
Cancel
Save