'use client'; import ReactMarkdown, { type Components } from 'react-markdown'; import { isHTMLContent } from '@/lib/content'; interface ContentViewProps { content: string | null | undefined; className?: string; /** * 显式指定内容格式,优先于内容探测。 * - 'html':富文本,dangerouslySetInnerHTML 渲染 * - 'markdown':用 react-markdown 解析 * 不传时回退到 isHTMLContent 自动判断(旧调用方兼容)。 */ format?: 'html' | 'markdown'; } const mdComponents: Components = { pre: ({ children }) => (
      {children}
    
), code: ({ className: cls, children }) => { // 行内 code(无 language- 前缀)→ 灰底圆角;块级 code 由
 包裹
    const isBlock = typeof cls === 'string' && cls.includes('language-');
    if (isBlock) {
      return {children};
    }
    return (
      
        {children}
      
    );
  },
  table: ({ children }) => (
    
      {children}
    
), th: ({ children }) => ( {children} ), td: ({ children }) => ( {children} ), hr: () =>
, }; /** * 智能内容渲染器: * - HTML 内容(来自 RichEditor) → 用 dangerouslySetInnerHTML 直接渲染 * - Markdown 内容(来自 .md 上传)→ 用 react-markdown 解析为 React 元素后渲染 * 两者都套 `.prose-rich` 类以复用全局排版样式。 * * 注:MD 内容用 suppressHydrationWarning 包裹,避免 react-markdown * SSR/客户端解析在边界字符(HTML 标签、空白)上产生 hydration 不一致。 */ export function ContentView({ content, className, format }: ContentViewProps) { if (!content?.trim()) return null; const wrapperClass = className ? `prose-rich ${className}` : 'prose-rich'; const isHtml = format === 'html' ? true : format === 'markdown' ? false : isHTMLContent(content); if (isHtml) { return (
); } return (
{content}
); }