再次优化公式渲染,优化mermaid图渲染 #818

Merged
Eeeros merged 2 commits from Eeeros/forgeplus-react:gitlink_ssr_head into gitlink_ssr_head 2026-01-23 10:57:11 +08:00
3 changed files with 124 additions and 116 deletions

View File

@ -1860,71 +1860,76 @@
}
var marked = editormd.$marked;
const kateX = {
name: 'kateX',
level: 'block', // Is this a block-level or inline-level tokenizer?
start(src) {
// 匹配以 $$ 开头和结尾的 KaTeX 表达式
const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/;
// 匹配以 $ 开头和结尾的 KaTeX 表达式
const inlineRegex = /^\$[^$]+?\$(?:\n|$)/;
// 检查是否有块级 KaTeX 表达式
const blockMatch = src.match(startRegex);
if (blockMatch) {
return blockMatch.index;
}
// 检查是否有行内 KaTeX 表达式
const inlineMatch = src.match(inlineRegex);
if (inlineMatch) {
return inlineMatch.index;
}
// 如果没有匹配的内容,则返回 null 或 undefined
return null;
},
tokenizer(src, tokens) {
const match = src.match(/^\$([^\$]+)\$/);
if (match) {
return {
type: 'kateX',
raw: match[0],
text: match[1].trim(),
displayMode: false
};
}
const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/);
if (matchDisplay) {
return {
type: 'kateX',
raw: matchDisplay[0],
text: matchDisplay[1].trim(),
displayMode: true
};
}
return false;
},
renderer(token) {
let renderString = ''
try {
renderString = katex.renderToString(token.text, {
displayMode: token.displayMode,
macros: {
"\\mbox": "\\text{#1}",
"\\textrm": "\\text{#1}",
"\\textnormal": "\\text{#1}",
},
trust: false
})
} catch (error) {
renderString = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
}
return `<p class='editormd-tex'>${renderString}</p>`
// 块级 KaTeX: $$ ... $$
const katexBlock = {
name: 'katexBlock',
level: 'block',
start(src) {
const match = src.match(/\$\$/);
return match ? match.index : null;
},
tokenizer(src) {
const match = src.match(/^\$\$([\s\S]*?)\$\$/);
if (match) {
return {
type: 'katexBlock',
raw: match[0],
text: match[1].trim(),
displayMode: true
};
}
return false;
},
renderer(token) {
return renderKatex(token.text, true);
}
};
// 行内 KaTeX: $ ... $
const katexInline = {
name: 'katexInline',
level: 'inline',
start(src) {
// 找到 $ 且后面不是 $
const match = src.match(/\$(?!\$)/);
return match ? match.index : null;
},
tokenizer(src) {
const match = src.match(/^\$([^$]*?)\$(?!\$)/);
if (match) {
return {
type: 'katexInline',
raw: match[0],
text: match[1].trim(),
displayMode: false
};
}
return false;
},
renderer(token) {
return renderKatex(token.text, false);
}
};
// 公共渲染函数
function renderKatex(text, displayMode) {
try {
const html = renderToString(text, {
displayMode,
throwOnError: false,
macros: {
"\\mbox": "\\text{#1}",
"\\textrm": "\\text{#1}",
"\\textnormal": "\\text{#1}",
},
trust: false
});
return displayMode ? `<p class='editormd-tex'>${html}</p>` : html;
} catch (error) {
return `<span style="color:#c00" title="${error.message}">${text}</span>`;
}
}
var markdownToC = this.markdownToC = [];
var rendererOptions = this.markedRendererOptions = {
toc: settings.toc,
@ -1953,7 +1958,7 @@
};
if (editormd.kaTeXLoaded) {
marked.use({ extensions: [kateX] });
marked.use({ extensions: [katexBlock, katexInline] });
}
marked.setOptions(markedOptions);

View File

@ -181,74 +181,77 @@ marked.setOptions({
pedantic: false
})
const kateX = {
name: 'kateX',
level: 'block', // Is this a block-level or inline-level tokenizer?
// 块级 KaTeX: $$ ... $$
const katexBlock = {
name: 'katexBlock',
level: 'block',
start(src) {
// 匹配以 $$ 开头和结尾的 KaTeX 表达式
const startRegex = /^\$\$[^$]+?\$\$(?:\n|$)/;
// 匹配以 $ 开头和结尾的 KaTeX 表达式
const inlineRegex = /^\$[^$]+?\$(?:\n|$)/;
// 检查是否有块级 KaTeX 表达式
const blockMatch = src.match(startRegex);
if (blockMatch) {
return blockMatch.index;
}
// 检查是否有行内 KaTeX 表达式
const inlineMatch = src.match(inlineRegex);
if (inlineMatch) {
return inlineMatch.index;
}
// 如果没有匹配的内容,则返回 null 或 undefined
return null;
const match = src.match(/\$\$/);
return match ? match.index : null;
},
tokenizer(src, tokens) {
const match = src.match(/^\$([^\$]+)\$/);
tokenizer(src) {
const match = src.match(/^\$\$([\s\S]*?)\$\$/);
if (match) {
return {
type: 'kateX',
type: 'katexBlock',
raw: match[0],
text: match[1].trim(),
displayMode: false
};
}
const matchDisplay = src.match(/^\$\$([^\$]+)\$\$/);
if (matchDisplay) {
return {
type: 'kateX',
raw: matchDisplay[0],
text: matchDisplay[1].trim(),
displayMode: true
};
}
return false;
},
renderer(token) {
let renderString = ''
try {
renderString = renderToString(token.text || '', {
displayMode: token.displayMode,
throwOnError: false,
macros: {
"\\mbox": "\\text{#1}",
"\\textrm": "\\text{#1}",
"\\textnormal": "\\text{#1}",
},
trust: false
})
} catch (error) {
renderString = `<p style="color:#cc0000" title="${ error.message }">${ token.raw }`
}
return `<p class='editormd-tex'>${renderString}</p>`
return renderKatex(token.text, true);
}
};
// 行内 KaTeX: $ ... $
const katexInline = {
name: 'katexInline',
level: 'inline',
start(src) {
// 找到 $ 且后面不是 $
const match = src.match(/\$(?!\$)/);
return match ? match.index : null;
},
tokenizer(src) {
const match = src.match(/^\$([^$]*?)\$(?!\$)/);
if (match) {
return {
type: 'katexInline',
raw: match[0],
text: match[1].trim(),
displayMode: false
};
}
return false;
},
renderer(token) {
return renderKatex(token.text, false);
}
};
marked.use({ extensions: [kateX] });
// 公共渲染函数
function renderKatex(text, displayMode) {
try {
const html = renderToString(text, {
displayMode,
throwOnError: false,
macros: {
"\\mbox": "\\text{#1}",
"\\textrm": "\\text{#1}",
"\\textnormal": "\\text{#1}",
},
trust: false
});
return displayMode ? `<p class='editormd-tex'>${html}</p>` : html;
} catch (error) {
return `<span style="color:#c00" title="${error.message}">${text}</span>`;
}
}
marked.use({ extensions: [katexBlock, katexInline] });
marked.use({ tokenizer, renderer });

View File

@ -65,7 +65,7 @@ useEffect(() => {
.catch(err => {
console.error('Failed to load Mermaid:', err);
});
}, [html]);
}, [html, value]);
function getIssueList(){
let matchQuote = str.match(quoteRegex);