File size: 2,963 Bytes
4e0867d
 
 
 
 
 
 
 
 
 
b6ecafa
 
 
 
4e0867d
b6ecafa
 
4e0867d
 
 
 
 
 
 
b6ecafa
 
4e0867d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
'use client'

import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'

interface MarkdownRendererProps {
  content: string
  preview?: boolean
}

function stripHtml(content: string): string {
  return content.replace(/<[^>]*>/g, '')
}

function getPreviewContent(content: string): string {
  const cleaned = stripHtml(content)
  const firstParagraph = cleaned.trim().split(/\n\s*\n/)[0] || ''
  if (firstParagraph.length <= 240) return firstParagraph
  return `${firstParagraph.slice(0, 240)}...`
}

export function MarkdownRenderer({ content, preview = false }: MarkdownRendererProps) {
  if (!content?.trim()) return null

  const cleaned = stripHtml(content)
  const markdownContent = preview ? getPreviewContent(content) : cleaned

  return (
    <div className={`prose prose-invert max-w-none ${preview ? 'text-xs' : 'text-sm'}`}>
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        components={{
          h1: ({ children }) => <h1 className={`${preview ? 'text-sm' : 'text-xl'} font-semibold mb-2`}>{children}</h1>,
          h2: ({ children }) => <h2 className={`${preview ? 'text-xs' : 'text-lg'} font-semibold mb-2`}>{children}</h2>,
          h3: ({ children }) => <h3 className={`${preview ? 'text-xs' : 'text-base'} font-semibold mb-1`}>{children}</h3>,
          p: ({ children }) => <p className={`text-foreground/85 ${preview ? 'text-xs mb-1' : 'text-sm mb-2'} leading-relaxed`}>{children}</p>,
          ul: ({ children }) => <ul className={`list-disc ml-4 ${preview ? 'text-xs mb-1' : 'text-sm mb-2'}`}>{children}</ul>,
          ol: ({ children }) => <ol className={`list-decimal ml-4 ${preview ? 'text-xs mb-1' : 'text-sm mb-2'}`}>{children}</ol>,
          li: ({ children }) => <li className="mb-0.5 text-foreground/85">{children}</li>,
          code: ({ children, className }) => {
            const isInline = !className
            if (isInline) {
              return <code className="bg-surface-2 text-primary px-1 py-0.5 rounded text-[0.85em]">{children}</code>
            }
            return (
              <code className="block bg-surface-2 border border-border rounded p-2 overflow-x-auto text-[0.85em]">
                {children}
              </code>
            )
          },
          blockquote: ({ children }) => (
            <blockquote className="border-l-2 border-border pl-3 italic text-muted-foreground mb-2">
              {children}
            </blockquote>
          ),
          a: ({ href, children }) => (
            <a href={href} target="_blank" rel="noopener noreferrer" className="text-blue-400 hover:text-blue-300 underline">
              {children}
            </a>
          ),
          strong: ({ children }) => <strong className="font-semibold text-foreground">{children}</strong>,
          em: ({ children }) => <em className="italic text-foreground/90">{children}</em>,
        }}
      >
        {markdownContent}
      </ReactMarkdown>
    </div>
  )
}