Browse Source

bug-fixed rendering

imwald
Silberengel 5 months ago
parent
commit
61bcdf72ad
  1. 129
      src/components/UniversalContent/SimpleContent.tsx

129
src/components/UniversalContent/SimpleContent.tsx

@ -1,9 +1,11 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { cn } from '@/lib/utils'
import { cleanUrl } from '@/lib/url' import { cleanUrl } from '@/lib/url'
import { getImetaInfosFromEvent } from '@/lib/event'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import ImageWithLightbox from '../ImageWithLightbox' import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import { remarkNostr } from '../Note/LongFormArticle/remarkNostr'
import NostrNode from '../Note/LongFormArticle/NostrNode'
import { cn } from '@/lib/utils'
interface SimpleContentProps { interface SimpleContentProps {
event?: Event event?: Event
@ -16,8 +18,6 @@ export default function SimpleContent({
content, content,
className className
}: SimpleContentProps) { }: SimpleContentProps) {
const imetaInfos = useMemo(() => event ? getImetaInfosFromEvent(event) : [], [event])
const processedContent = useMemo(() => { const processedContent = useMemo(() => {
const rawContent = content || event?.content || '' const rawContent = content || event?.content || ''
@ -36,83 +36,54 @@ export default function SimpleContent({
return cleaned return cleaned
}, [content, event?.content]) }, [content, event?.content])
const renderContent = () => { const components = useMemo(() => ({
if (!processedContent) return null nostr: ({ rawText, bech32Id }: { rawText: string; bech32Id: string }) => (
<NostrNode rawText={rawText} bech32Id={bech32Id} />
// Split content by lines and process each line ),
const lines = processedContent.split('\n') a: ({ href, children, ...props }: any) => {
const elements: JSX.Element[] = [] if (!href) {
let key = 0 return <span {...props} className="break-words" />
lines.forEach((line) => {
// Check if line contains an image URL
const imageMatch = line.match(/(https?:\/\/[^\s]+\.(jpg|jpeg|png|gif|webp|heic|svg))/i)
if (imageMatch) {
const imageUrl = imageMatch[1]
const imageInfo = imetaInfos.find((info) => info.url === imageUrl)
const imageData = imageInfo || { url: imageUrl, pubkey: event?.pubkey }
elements.push(
<div key={key++} className="my-4">
<ImageWithLightbox
image={imageData}
className="max-w-full h-auto rounded-lg cursor-zoom-in"
/>
</div>
)
// Add the rest of the line as text if there's anything else
const beforeImage = line.substring(0, imageMatch.index).trim()
const afterImage = line.substring(imageMatch.index! + imageUrl.length).trim()
if (beforeImage || afterImage) {
elements.push(
<div key={key++} className="mb-2">
{beforeImage && <span>{beforeImage}</span>}
{afterImage && <span>{afterImage}</span>}
</div>
)
}
} else {
// Regular text line
elements.push(
<div key={key++} className="mb-1">
{renderTextWithLinks(line)}
</div>
)
} }
}) return (
<a
return elements {...props}
} href={href}
target="_blank"
const renderTextWithLinks = (text: string) => { rel="noreferrer noopener"
// Simple link detection and rendering className="text-primary hover:underline break-words"
const linkRegex = /(https?:\/\/[^\s]+)/g >
const parts = text.split(linkRegex) {children}
</a>
return parts.map((part, index) => { )
if (linkRegex.test(part)) { },
return ( p: (props: any) => <p {...props} className="mb-2 last:mb-0" />,
<a code: (props: any) => <code {...props} className="bg-muted px-1 py-0.5 rounded text-sm break-words" />,
key={index} pre: (props: any) => <pre {...props} className="bg-muted p-3 rounded overflow-x-auto" />,
href={part} blockquote: (props: any) => <blockquote {...props} className="border-l-4 border-muted pl-4 italic" />,
target="_blank" ul: (props: any) => <ul {...props} className="list-disc list-inside mb-2" />,
rel="noreferrer noopener" ol: (props: any) => <ol {...props} className="list-decimal list-inside mb-2" />,
className="text-primary hover:underline break-words" li: (props: any) => <li {...props} className="mb-1" />,
> h1: (props: any) => <h1 {...props} className="text-xl font-bold mb-2 break-words" />,
{part} h2: (props: any) => <h2 {...props} className="text-lg font-bold mb-2 break-words" />,
</a> h3: (props: any) => <h3 {...props} className="text-base font-bold mb-2 break-words" />,
) strong: (props: any) => <strong {...props} className="font-bold" />,
} em: (props: any) => <em {...props} className="italic" />
return <span key={index}>{part}</span> }), [])
})
}
return ( return (
<div className={cn('text-wrap break-words whitespace-pre-wrap', className)}> <div className={cn('prose prose-sm prose-zinc max-w-none break-words dark:prose-invert', className)}>
{renderContent()} <Markdown
remarkPlugins={[remarkGfm, remarkNostr]}
urlTransform={(url) => {
if (url.startsWith('nostr:')) {
return url.slice(6) // Remove 'nostr:' prefix for rendering
}
return url
}}
components={components}
>
{processedContent}
</Markdown>
</div> </div>
) )
} }

Loading…
Cancel
Save