/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import ReactMarkdown from 'react-markdown'; import 'katex/dist/katex.min.css'; import 'highlight.js/styles/github.css'; import './markdown.css'; import RemarkMath from 'remark-math'; import RemarkBreaks from 'remark-breaks'; import RehypeKatex from 'rehype-katex'; import RemarkGfm from 'remark-gfm'; import RehypeHighlight from 'rehype-highlight'; import { useRef, useState, useEffect, useMemo } from 'react'; import mermaid from 'mermaid'; import React from 'react'; import { useDebouncedCallback } from 'use-debounce'; import clsx from 'clsx'; import { Button, Tooltip, Toast } from '@douyinfe/semi-ui'; import { copy, rehypeSplitWordsIntoSpans } from '../../../helpers'; import { IconCopy } from '@douyinfe/semi-icons'; import { useTranslation } from 'react-i18next'; mermaid.initialize({ startOnLoad: false, theme: 'default', securityLevel: 'loose', }); export function Mermaid(props) { const ref = useRef(null); const [hasError, setHasError] = useState(false); useEffect(() => { if (props.code && ref.current) { mermaid .run({ nodes: [ref.current], suppressErrors: true, }) .catch((e) => { setHasError(true); console.error('[Mermaid] ', e.message); }); } }, [props.code]); function viewSvgInNewWindow() { const svg = ref.current?.querySelector('svg'); if (!svg) return; const text = new XMLSerializer().serializeToString(svg); const blob = new Blob([text], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); window.open(url, '_blank'); } if (hasError) { return null; } return (
viewSvgInNewWindow()} > {props.code}
); } function SandboxedHtmlPreview({ code }) { const iframeRef = useRef(null); const [iframeHeight, setIframeHeight] = useState(150); useEffect(() => { const iframe = iframeRef.current; if (!iframe) return; const handleLoad = () => { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (doc) { const height = doc.documentElement.scrollHeight || doc.body.scrollHeight; setIframeHeight(Math.min(Math.max(height + 16, 60), 600)); } } catch { // sandbox restrictions may prevent access, that's fine } }; iframe.addEventListener('load', handleLoad); return () => iframe.removeEventListener('load', handleLoad); }, [code]); return (