import { Fragment, useMemo, useState, type ReactNode } from 'react'; import { highlightCodeLine, parseMarkdown, type MarkdownInline, } from './markdown.js'; export interface MarkdownContentProps { readonly text: string; readonly className?: string; } function InlineContent({ content }: { readonly content: readonly MarkdownInline[] }) { const nodes: ReactNode[] = []; content.forEach((token, index) => { const key = `${token.type}-${index}`; const value = token.value.split('\n').map((line, lineIndex, lines) => ( {line} {lineIndex < lines.length - 1 ?
: null}
)); if (token.type === 'strong') nodes.push({value}); else if (token.type === 'emphasis') nodes.push({value}); else if (token.type === 'strike') nodes.push({value}); else if (token.type === 'code') nodes.push({token.value}); else if (token.type === 'link') nodes.push( {value}, ); else nodes.push({value}); }); return <>{nodes}; } export function CodeBlock({ code, language = '', closed = true }: { readonly code: string; readonly language?: string; readonly closed?: boolean }) { const [copied, setCopied] = useState(false); const [wrapped, setWrapped] = useState(false); const [expanded, setExpanded] = useState(false); const lines = useMemo(() => code.split('\n'), [code]); const isLong = lines.length > 18 || code.length > 1800; const visibleLines = isLong && !expanded ? lines.slice(0, 18) : lines; const copy = async () => { try { await navigator.clipboard.writeText(code); setCopied(true); window.setTimeout(() => setCopied(false), 1600); } catch { setCopied(false); } }; return (
{language || 'plain text'} {!closed ? 生成中 : null}
        
          {visibleLines.map((line, lineIndex) => (
            
              
              
                {highlightCodeLine(line, language).map((token, tokenIndex) => (
                  {token.value}
                ))}
                {'\n'}
              
            
          ))}
        
      
{isLong ? ( ) : null}
); } export function MarkdownContent({ text, className }: MarkdownContentProps) { const blocks = useMemo(() => parseMarkdown(text), [text]); return (
{blocks.map((block, index) => { if (block.type === 'heading') { const Heading = `h${block.level}` as keyof React.JSX.IntrinsicElements; return ; } if (block.type === 'paragraph') return

; if (block.type === 'quote') return
; if (block.type === 'rule') return
; if (block.type === 'code') return ; if (block.type === 'list') { const List = block.ordered ? 'ol' : 'ul'; return ( {block.items.map((item, itemIndex) => (
  • {item.checked === undefined ? null : }
  • ))}
    ); } if (block.type === 'table') { return (
    {block.header.map((cell, cellIndex) => )}{block.rows.map((row, rowIndex) => {row.map((cell, cellIndex) => )})}
    ); } return null; })}
    ); }