✨ feat(vscode): 代码阅读预览把注释、说明、问 AI 回答里的 mermaid 代码块画成图

- markdown.ts:mermaid 代码块出占位(源码转义后记在 data-source,里面先放原样的代码块);带增删的说明、逐字生成中的回答仍是普通代码块
- useMermaidDiagrams:页面上有占位才按需加载 mermaid(strict、跟 VS Code 字体),按源码 + 配色缓存 SVG,一次只画一张,换主题重画;画不出来留代码块、下面一行原因
- 打包:Vite 的按需加载辅助函数单独成块,加构建检查禁止别的块 import 入口(入口带 ?v= 加载,被 import 会整页再跑一遍、第二次拿 VS Code API 报错)
- 主题明暗判断抽到 lib/vscodeTheme,看板的改动面板共用
This commit is contained in:
cruldra committed 2026-10-13 18:51:05 +11:00
1 parent bc84e74f29
commit 6dac457ed1
11 files changed
+1289 -24

No files matched your search

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { renderMarkdown, renderMarkdownDiff } from './markdown'
import { renderMarkdown, renderMarkdownDiff, renderMarkdownOnce } from './markdown'
import { repoImageInner } from './repoImage'
describe('renderMarkdown', () => {
@@ -124,3 +124,27 @@ describe('renderMarkdownDiff', () => {
expect(renderMarkdownDiff([{ text: '共 ' }, { text: '# 3', change: 'add' }])).toBe('<p>共 <ins class="cr-diff-word"># 3</ins></p>\n')
})
})
describe('mermaid 代码块', () => {
const source = 'flowchart TD\n A["读 <配置> & 写"] --> B{"成功?"}\n'
const escaped = 'flowchart TD\n A[&quot;读 &lt;配置&gt; &amp; 写&quot;] --&gt; B{&quot;成功?&quot;}\n'
const codeBlock = `<pre><code class="language-mermaid">${escaped}</code></pre>\n`
const placeholder = `<div class="cr-mermaid" data-source="${escaped}">${codeBlock}</div>\n`
it('出占位:转义后的源码记在 data-source,里面先放原样的代码块', () => {
expect(renderMarkdown(`说明\n\n\`\`\`mermaid\n${source}\`\`\``)).toBe(`<p>说明</p>\n${placeholder}`)
expect(renderMarkdown(`\`\`\`mermaid\n${source}\`\`\``, 'peek')).toBe(placeholder)
expect(renderMarkdown(`\`\`\`mermaid\n${source}\`\`\``, 'answer')).toBe(placeholder)
})
it('别的代码块照旧', () => {
expect(renderMarkdown('```ts\nload(\'a\')\n```')).toBe('<pre><code class="language-ts">load(\'a\')\n</code></pre>\n')
expect(renderMarkdown('```\nflowchart TD\n```')).toBe('<pre><code>flowchart TD\n</code></pre>\n')
expect(renderMarkdown('```mermaidx\nA\n```')).not.toContain('cr-mermaid')
})
it('带增删的说明、还在逐字长的回答里仍是普通代码块', () => {
expect(renderMarkdownDiff([{ text: `\`\`\`mermaid\n${source}\`\`\`` }])).toBe(codeBlock)
expect(renderMarkdownOnce(`\`\`\`mermaid\n${source}\`\`\``)).toBe(codeBlock)
})
})