// 共享 Markdown 渲染:marked 解析 + DOMPurify 净化 + highlight.js 代码高亮。 // 挂 window.MaestroRichDoc,供 GateSection / TaskTree 等在 vite app 与 standalone demo 两环境共用。 // 依赖 window.marked / window.DOMPurify(必需,CDN 全局)+ window.hljs(可选,缺则代码块不着色)。 function ensureRichDocCss() { if (document.getElementById('maestro-richdoc-css')) return; const s = document.createElement('style'); s.id = 'maestro-richdoc-css'; s.textContent = ` .m-richdoc { font-size: 12.8px; line-height: 1.7; color: var(--ink); word-break: break-word; } .m-richdoc > :first-child { margin-top: 0; } .m-richdoc > :last-child { margin-bottom: 0; } .m-richdoc h1, .m-richdoc h2, .m-richdoc h3, .m-richdoc h4 { font-weight: 700; line-height: 1.3; margin: 16px 0 8px; letter-spacing: .01em; } .m-richdoc h1 { font-size: 1.32em; color: var(--ink); border-bottom: 1px solid var(--line-soft); padding-bottom: 5px; } .m-richdoc h2 { font-size: 1.16em; color: var(--green); } .m-richdoc h3 { font-size: 1.05em; color: var(--cyan); } .m-richdoc h4 { font-size: 1em; color: var(--muted); } .m-richdoc p { margin: 7px 0; } .m-richdoc ul, .m-richdoc ol { margin: 7px 0; padding-left: 22px; } .m-richdoc li { margin: 3px 0; } .m-richdoc li::marker { color: var(--green); } .m-richdoc a { color: var(--cyan); text-decoration: none; border-bottom: 1px solid var(--cyan-dim); } .m-richdoc a:hover { border-bottom-color: var(--cyan); } .m-richdoc strong { color: var(--ink); font-weight: 700; } .m-richdoc em { color: var(--muted); } .m-richdoc code { font-family: var(--mono); font-size: .9em; color: var(--cyan); background: var(--panel-2); border-radius: 3px; padding: 1.5px 5px; } .m-richdoc pre { background: var(--bg-deep); border: 1px solid var(--line-soft); border-radius: 5px; padding: 11px 13px; overflow-x: auto; margin: 9px 0; } .m-richdoc pre code { display: block; font-family: var(--mono); font-size: 11.8px; line-height: 1.55; color: var(--ink); background: none; border: 0; padding: 0; } .m-richdoc blockquote { margin: 9px 0; padding: 2px 13px; border-left: 3px solid var(--line); color: var(--muted); } .m-richdoc table { border-collapse: collapse; margin: 9px 0; font-size: .95em; display: block; overflow-x: auto; } .m-richdoc th, .m-richdoc td { border: 1px solid var(--line); padding: 5px 10px; text-align: left; } .m-richdoc th { background: var(--panel-2); color: var(--ink); font-weight: 700; } .m-richdoc hr { border: 0; border-top: 1px solid var(--line-soft); margin: 14px 0; } .m-richdoc img { max-width: 100%; } `; document.head.appendChild(s); } function MaestroRichDoc({ md }) { const ref = React.useRef(null); ensureRichDocCss(); const ready = typeof window !== 'undefined' && !!window.marked && !!window.DOMPurify; const html = React.useMemo(() => { if (!ready || !md) return null; try { const raw = window.marked.parse(String(md), { gfm: true, breaks: false }); return window.DOMPurify.sanitize(raw); } catch (e) { return null; } }, [md, ready]); React.useEffect(() => { if (html && ref.current && window.hljs) { ref.current.querySelectorAll('pre code').forEach((el) => { try { window.hljs.highlightElement(el); } catch (e) { /* noop */ } }); } }, [html]); // 兜底:库未就绪或解析失败 → 原文 pre-wrap,永不崩 if (html == null) { return
{md || ''}
; } return
; } window.MaestroRichDoc = MaestroRichDoc;