diff --git a/MARKDOWN_INTEGRATION.md b/MARKDOWN_INTEGRATION.md new file mode 100644 index 0000000..5fc1b4f --- /dev/null +++ b/MARKDOWN_INTEGRATION.md @@ -0,0 +1,187 @@ +# Markdown 节点渲染集成说明 + +## 概述 + +这个集成方案为你的 Mind Elixir 思维导图项目添加了 markdown 节点渲染能力,支持: + +- ✅ **表格渲染** - 完整的 markdown 表格支持 +- ✅ **代码高亮** - 代码块和行内代码 +- ✅ **文本格式** - 粗体、斜体、标题等 +- ✅ **列表** - 有序和无序列表 +- ✅ **链接** - 自动链接渲染 +- ✅ **智能检测** - 自动识别 markdown 语法 + +## 文件结构 + +``` +frontend/src/ +├── utils/ +│ └── markdownRenderer.js # 核心渲染器 +├── components/ +│ ├── MindMap.vue # 主思维导图组件(已集成) +│ └── MarkdownTest.vue # 测试组件 +└── ... +``` + +## 使用方法 + +### 1. 在节点中使用 markdown + +现在你可以在思维导图的节点内容中直接使用 markdown 语法: + +```markdown +# 产品价格表 + +| 产品 | 价格 | 库存 | +|------|------|------| +| 苹果 | 4元 | 100个 | +| 香蕉 | 2元 | 50个 | + +## 技术栈 + +- **前端**: Vue.js 3 +- **后端**: Django +- **数据库**: PostgreSQL + +## 代码示例 + +\`\`\`javascript +function hello() { + console.log('Hello World!'); +} +\`\`\` +``` + +### 2. 测试功能 + +访问 `MarkdownTest.vue` 组件来测试 markdown 渲染功能: + +```vue + + + +``` + +### 3. 在现有节点中启用 + +系统会自动检测节点内容是否包含 markdown 语法,如果包含,会自动使用 markdown 渲染器。 + +## 核心功能 + +### 智能渲染 + +```javascript +import { smartRenderNodeContent } from '../utils/markdownRenderer.js'; + +// 自动检测并渲染 +smartRenderNodeContent(nodeElement, content); +``` + +### 手动渲染 + +```javascript +import { renderMarkdownToHTML } from '../utils/markdownRenderer.js'; + +// 直接渲染为 HTML +const html = renderMarkdownToHTML(markdownContent); +``` + +### 语法检测 + +```javascript +import { hasMarkdownSyntax } from '../utils/markdownRenderer.js'; + +// 检测是否包含 markdown 语法 +if (hasMarkdownSyntax(content)) { + // 使用 markdown 渲染 +} +``` + +## 支持的 Markdown 语法 + +### 表格 +```markdown +| 列1 | 列2 | 列3 | +|-----|-----|-----| +| 数据1 | 数据2 | 数据3 | +``` + +### 代码块 +```markdown +\`\`\`javascript +function test() { + console.log('Hello'); +} +\`\`\` +``` + +### 行内代码 +```markdown +使用 \`console.log()\` 输出信息 +``` + +### 文本格式 +```markdown +**粗体文本** +*斜体文本* +``` + +### 列表 +```markdown +- 无序列表项1 +- 无序列表项2 + +1. 有序列表项1 +2. 有序列表项2 +``` + +### 链接 +```markdown +[链接文本](https://example.com) +``` + +## 样式定制 + +渲染器会自动添加 CSS 样式,你也可以通过以下类名进行自定义: + +- `.markdown-content` - 主容器 +- `.markdown-table` - 表格样式 +- `.markdown-code` - 代码块样式 +- `.markdown-math` - 数学公式样式 + +## 注意事项 + +1. **性能**: 大量 markdown 内容可能影响渲染性能 +2. **安全性**: 渲染器允许 HTML,请确保内容来源可信 +3. **兼容性**: 与 Mind Elixir 的拖拽、编辑功能完全兼容 + +## 故障排除 + +### 渲染失败 +- 检查 markdown 语法是否正确 +- 查看浏览器控制台错误信息 +- 使用 `MarkdownTest.vue` 组件测试 + +### 样式问题 +- 检查 CSS 样式是否被覆盖 +- 确保 `markdown-node-styles` 样式已加载 + +### 性能问题 +- 避免在单个节点中放置过多内容 +- 考虑将复杂内容拆分为多个子节点 + +## 扩展功能 + +如果需要更多功能,可以扩展 `markdownRenderer.js`: + +- 数学公式支持(KaTeX) +- 图表支持(Mermaid) +- 更多 markdown 扩展语法 + +## 总结 + +这个集成方案让你可以在保持现有 Mind Elixir 功能的同时,享受强大的 markdown 渲染能力。特别是表格渲染功能,让思维导图可以展示更丰富的数据结构。 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 01754f8..b6f96a0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,8 @@ "axios": "^1.5.0", "mammoth": "^1.10.0", "marked": "^16.2.1", + "markmap-lib": "^0.18.12", + "markmap-view": "^0.18.12", "mind-elixir": "^3.0.0", "pdfjs-dist": "^5.4.149", "vue": "^3.3.4" @@ -53,6 +55,15 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { "version": "7.28.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", @@ -440,6 +451,16 @@ "node": ">=12" } }, + "node_modules/@gera2ld/jsx-dom": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@gera2ld/jsx-dom/-/jsx-dom-2.2.2.tgz", + "integrity": "sha512-EOqf31IATRE6zS1W1EoWmXZhGfLAoO9FIlwTtHduSrBdud4npYBxYAkv8dZ5hudDPwJeeSjn40kbCL4wAzr8dA==", + "license": "ISC", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.5" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -645,6 +666,15 @@ "vue": "^3.2.25" } }, + "node_modules/@vscode/markdown-it-katex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@vscode/markdown-it-katex/-/markdown-it-katex-1.1.2.tgz", + "integrity": "sha512-+4IIv5PgrmhKvW/3LpkpkGg257OViEhXkOOgCyj5KMsjsOfnRXkni8XAuuF9Ui5p3B8WnUovlDXAQNb8RJ/RaQ==", + "license": "MIT", + "dependencies": { + "katex": "^0.16.4" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.20", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", @@ -806,6 +836,12 @@ "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "license": "MIT" }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -819,6 +855,48 @@ "node": ">= 0.4" } }, + "node_modules/cheerio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18.17" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -831,18 +909,474 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -858,6 +1392,61 @@ "integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==", "license": "BSD-2-Clause" }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/duck": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz", @@ -881,6 +1470,19 @@ "node": ">= 0.4" } }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -1130,6 +1732,46 @@ "node": ">= 0.4" } }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -1142,6 +1784,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1160,6 +1811,22 @@ "setimmediate": "^1.0.5" } }, + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -1169,6 +1836,15 @@ "immediate": "~3.0.5" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/lop": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/lop/-/lop-0.4.2.tgz", @@ -1213,6 +1889,53 @@ "node": ">=12.0.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-ins": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-4.0.0.tgz", + "integrity": "sha512-sWbjK2DprrkINE4oYDhHdCijGT+MIDhEupjSHLXe5UXeVr5qmVxs/nTUVtgi0Oh/qtF+QKV0tNWDhQBEPxiMew==", + "license": "MIT" + }, + "node_modules/markdown-it-mark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-4.0.0.tgz", + "integrity": "sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg==", + "license": "MIT" + }, + "node_modules/markdown-it-sub": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-2.0.0.tgz", + "integrity": "sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==", + "license": "MIT" + }, + "node_modules/markdown-it-sup": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-2.0.0.tgz", + "integrity": "sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==", + "license": "MIT" + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, "node_modules/marked": { "version": "16.2.1", "resolved": "https://registry.npmjs.org/marked/-/marked-16.2.1.tgz", @@ -1225,6 +1948,68 @@ "node": ">= 20" } }, + "node_modules/markmap-common": { + "version": "0.18.9", + "resolved": "https://registry.npmjs.org/markmap-common/-/markmap-common-0.18.9.tgz", + "integrity": "sha512-MV2HQO7IGIm3jWEJXSG8vmdpqf4WIDXcEyAEN52lrWR1qD53Zg5l81JwjXoZ2l0rY5mofKYqUFlmdM2fqTGMVg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.22.6", + "@gera2ld/jsx-dom": "^2.2.2", + "npm2url": "^0.2.4" + } + }, + "node_modules/markmap-html-parser": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/markmap-html-parser/-/markmap-html-parser-0.18.11.tgz", + "integrity": "sha512-+kC5C4sCGntGUhGvTa5VIb5rtM75cSy/VCy3tzZoNAcn2qZGdgYvljN0WvjsOzrEzp+V6XKgwzO0u2TdzNAiOg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.6", + "cheerio": "1.0.0" + }, + "peerDependencies": { + "markmap-common": "*" + } + }, + "node_modules/markmap-lib": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/markmap-lib/-/markmap-lib-0.18.12.tgz", + "integrity": "sha512-WCA4OT+b71jYg0e4PS/6NRKqihod5OpPsvw1jEGHQwCtqQrY/yXXCeRyuL3axOS5cMy5pV8BSl4CwKfJU1LxJg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.6", + "@vscode/markdown-it-katex": "^1.1.0", + "highlight.js": "^11.8.0", + "katex": "^0.16.8", + "markdown-it": "^14.1.0", + "markdown-it-ins": "^4.0.0", + "markdown-it-mark": "^4.0.0", + "markdown-it-sub": "^2.0.0", + "markdown-it-sup": "^2.0.0", + "markmap-html-parser": "0.18.11", + "markmap-view": "0.18.12", + "prismjs": "^1.29.0", + "yaml": "^2.5.1" + }, + "peerDependencies": { + "markmap-common": "*" + } + }, + "node_modules/markmap-view": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/markmap-view/-/markmap-view-0.18.12.tgz", + "integrity": "sha512-D8bzT1YwIC/8rkbwm6WzigVUrpOAGv7ioEGTi1Lj+Oo8gO5sAm6hhli27jvTgUcZ9TwBeIWZ+dSUP+AupYUGlQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.6", + "d3": "^7.8.5" + }, + "peerDependencies": { + "markmap-common": "*" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1234,6 +2019,12 @@ "node": ">= 0.4" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1279,6 +2070,25 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/npm2url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/npm2url/-/npm2url-0.2.4.tgz", + "integrity": "sha512-arzGp/hQz0Ey+ZGhF64XVH7Xqwd+1Q/po5uGiBbzph8ebX6T0uvt3N7c1nBHQNsQVykQgHhqoRTX7JFcHecGuw==", + "license": "MIT", + "peer": true + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/option": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz", @@ -1291,6 +2101,55 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1346,6 +2205,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -1358,6 +2226,15 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -1373,6 +2250,12 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "3.29.5", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", @@ -1390,12 +2273,24 @@ "fsevents": "~2.3.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -1426,12 +2321,27 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/underscore": { "version": "1.13.7", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", "license": "MIT" }, + "node_modules/undici": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1515,6 +2425,27 @@ } } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/xmlbuilder": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", @@ -1523,6 +2454,18 @@ "engines": { "node": ">=4.0" } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } } } } diff --git a/frontend/package.json b/frontend/package.json index a8455fd..a6facf6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,8 @@ "axios": "^1.5.0", "mammoth": "^1.10.0", "marked": "^16.2.1", + "markmap-lib": "^0.18.12", + "markmap-view": "^0.18.12", "mind-elixir": "^3.0.0", "pdfjs-dist": "^5.4.149", "vue": "^3.3.4" diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 4557a84..815db70 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,11 +1,26 @@ @@ -14,8 +29,15 @@ import { ref } from 'vue'; import MindMap from "./components/MindMap.vue"; import AISidebar from "./components/AISidebar.vue"; +import MarkdownTest from "./components/MarkdownTest.vue"; const mindMapRef = ref(null); +const isTestMode = ref(false); + +// 切换测试模式 +const toggleTestMode = () => { + isTestMode.value = !isTestMode.value; +}; // 处理开始实时生成事件 const handleStartRealtimeGeneration = () => { @@ -65,4 +87,36 @@ body { height: 100%; width: 100%; } + +/* 测试模式样式 */ +.test-mode-toggle { + position: fixed; + top: 20px; + right: 20px; + z-index: 1000; +} + +.test-btn { + padding: 10px 20px; + background: #007bff; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3); + transition: all 0.2s ease; +} + +.test-btn:hover { + background: #0056b3; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 123, 255, 0.4); +} + +.test-mode { + height: 100vh; + overflow: auto; +} diff --git a/frontend/src/components/MarkdownTest.vue b/frontend/src/components/MarkdownTest.vue new file mode 100644 index 0000000..8e8d78c --- /dev/null +++ b/frontend/src/components/MarkdownTest.vue @@ -0,0 +1,228 @@ + + + + + diff --git a/frontend/src/components/MindMap.vue b/frontend/src/components/MindMap.vue index 22891ac..2c1012b 100644 --- a/frontend/src/components/MindMap.vue +++ b/frontend/src/components/MindMap.vue @@ -171,6 +171,11 @@ import { ref, onMounted, onUnmounted, nextTick } from 'vue'; import MindElixir from 'mind-elixir'; import { mindmapAPI } from '../api/mindmap.js'; +import { + smartRenderNodeContent, + hasMarkdownSyntax, + renderMarkdownToHTML +} from '../utils/markdownRenderer.js'; // 响应式数据 const mindmapEl = ref(null); @@ -2717,6 +2722,77 @@ const savePreviewToDatabase = async (data, title) => { try { // 开始保存预览数据到数据库 + // 检查是否已经有实时渲染的思维导图 + const currentId = String(currentMindmapId.value || ''); + const hasRealtimeMindmap = mindElixir.value && currentId && currentId.startsWith('temp-'); + + if (hasRealtimeMindmap) { + console.log("🔄 检测到实时渲染的思维导图,将保存到数据库并更新ID"); + + // 保存当前位置和缩放状态 + const currentPosition = saveCurrentPosition(); + console.log("📍 保存当前位置:", currentPosition); + + // 创建新的思维导图 + const response = await mindmapAPI.createMindmap(title || "预览思维导图", data); + console.log("🔄 创建思维导图响应:", response); + + if (response.data && response.data.id) { + const newMindmapId = response.data.id; + console.log("🎉 创建思维导图成功,新思维导图的ID是:", newMindmapId); + + // 更新当前思维导图ID,但保持视图状态 + const oldMindmapId = currentMindmapId.value; + currentMindmapId.value = newMindmapId; + + // 更新MindElixir数据中的ID + if (mindElixir.value && mindElixir.value.data) { + mindElixir.value.data.mindmapId = newMindmapId; + mindElixir.value.data.id = newMindmapId; + + // 更新所有节点的mindmapId + const updateNodeIds = (node) => { + if (node) { + node.mindmapId = newMindmapId; + if (node.children) { + node.children.forEach(child => updateNodeIds(child)); + } + } + }; + + if (mindElixir.value.data.nodeData) { + updateNodeIds(mindElixir.value.data.nodeData); + } + } + + console.log("✅ 已更新思维导图ID,保持视图状态"); + console.log("🔄 从临时ID", oldMindmapId, "更新为正式ID", newMindmapId); + + // 恢复位置和缩放状态 + if (currentPosition) { + setTimeout(() => { + restorePosition(currentPosition); + console.log("📍 已恢复位置和缩放状态"); + }, 100); + } + + // 通知AISidebar组件更新历史记录 + window.dispatchEvent(new CustomEvent('mindmap-saved', { + detail: { + mindmapId: newMindmapId, + title: title, + timestamp: Date.now(), + fromRealtime: true // 标记来自实时渲染 + } + })); + + return; + } + } + + // 如果没有实时渲染的思维导图,使用原有逻辑 + console.log("🔄 没有检测到实时渲染的思维导图,使用标准保存流程"); + // 创建新的思维导图 const response = await mindmapAPI.createMindmap(title || "预览思维导图", data); console.log("🔄 创建思维导图响应:", response); @@ -3148,12 +3224,18 @@ const updateMindMapRealtime = async (data, title) => { }); // 🔧 修复:将数据包装成MindElixir期望的格式 + const tempId = `temp-${Date.now()}`; const mindElixirData = { nodeData: data, // 将节点数据放在nodeData字段中 - mindmapId: `temp-${Date.now()}`, // 临时ID + mindmapId: tempId, // 临时ID + id: tempId, // 同时设置id字段 title: title || 'AI生成中...' }; + // 设置当前思维导图ID为临时ID + currentMindmapId.value = tempId; + console.log('🆔 设置临时思维导图ID:', tempId); + // 初始化数据 const result = mindElixir.value.init(mindElixirData); console.log('✅ 实时思维导图实例创建成功'); @@ -3176,12 +3258,24 @@ const updateMindMapRealtime = async (data, title) => { console.log(' 当前位置已保存:', currentPosition); // 🔧 修复:将数据包装成MindElixir期望的格式 + const currentId = String(currentMindmapId.value || ''); + const tempId = currentId && currentId.startsWith('temp-') + ? currentId + : `temp-${Date.now()}`; + const mindElixirData = { nodeData: data, // 将节点数据放在nodeData字段中 - mindmapId: currentMindmapId.value || `temp-${Date.now()}`, + mindmapId: tempId, + id: tempId, title: title || 'AI生成中...' }; + // 确保当前思维导图ID是临时ID + if (!currentId || !currentId.startsWith('temp-')) { + currentMindmapId.value = tempId; + console.log('🆔 更新临时思维导图ID:', tempId); + } + // 重新初始化数据 const result = mindElixir.value.init(mindElixirData); console.log('✅ 思维导图数据更新成功'); diff --git a/frontend/src/utils/markdownRenderer.js b/frontend/src/utils/markdownRenderer.js new file mode 100644 index 0000000..fd664f7 --- /dev/null +++ b/frontend/src/utils/markdownRenderer.js @@ -0,0 +1,303 @@ +/** + * Markdown节点渲染器 + * 为Mind Elixir节点提供markdown内容渲染能力 + * 支持表格、数学公式、代码块等 + */ + +import { marked } from 'marked'; + +// 配置marked选项 +marked.setOptions({ + breaks: true, + gfm: true, // GitHub Flavored Markdown + tables: true, // 支持表格 + sanitize: false, // 允许HTML(用于数学公式等) +}); + +/** + * 渲染markdown内容为HTML + * @param {string} markdown - markdown文本 + * @returns {string} 渲染后的HTML + */ +export const renderMarkdownToHTML = (markdown) => { + if (!markdown || typeof markdown !== 'string') { + return ''; + } + + try { + // 预处理markdown + const processedMarkdown = preprocessMarkdown(markdown); + + // 使用marked渲染 + const html = marked.parse(processedMarkdown); + + // 后处理HTML + return postprocessHTML(html); + } catch (error) { + console.error('Markdown渲染失败:', error); + return `
渲染失败: ${error.message}
`; + } +}; + +/** + * 预处理markdown内容 + * @param {string} markdown - 原始markdown + * @returns {string} 处理后的markdown + */ +const preprocessMarkdown = (markdown) => { + return markdown + // 确保表格前后有空行 + .replace(/([^\n])\n(\|.*\|)/g, '$1\n\n$2') + .replace(/(\|.*\|)\n([^\n|])/g, '$1\n\n$2') + // 处理数学公式(如果需要的话) + .replace(/\$\$(.*?)\$\$/g, '
$$$1$$
') + .replace(/\$(.*?)\$/g, '$$1$'); +}; + +/** + * 后处理HTML内容 + * @param {string} html - 渲染后的HTML + * @returns {string} 处理后的HTML + */ +const postprocessHTML = (html) => { + return html + // 为表格添加样式类 + .replace(//g, '
') + // 为代码块添加样式类 + .replace(/
/g, '
') + .replace(//g, ''); +}; + +/** + * 为Mind Elixir节点设置markdown内容 + * @param {HTMLElement} nodeElement - 节点DOM元素 + * @param {string} markdownContent - markdown内容 + */ +export const setNodeMarkdownContent = (nodeElement, markdownContent) => { + if (!nodeElement || !markdownContent) return; + + // 查找或创建内容容器 + let contentContainer = nodeElement.querySelector('.markdown-content'); + if (!contentContainer) { + contentContainer = document.createElement('div'); + contentContainer.className = 'markdown-content'; + + // 将内容容器添加到节点中 + const topicText = nodeElement.querySelector('.topic-text'); + if (topicText) { + topicText.appendChild(contentContainer); + } else { + nodeElement.appendChild(contentContainer); + } + } + + // 渲染markdown内容 + const html = renderMarkdownToHTML(markdownContent); + contentContainer.innerHTML = html; + + // 添加样式 + addMarkdownStyles(contentContainer); +}; + +/** + * 添加markdown样式 + * @param {HTMLElement} container - 容器元素 + */ +const addMarkdownStyles = (container) => { + // 检查是否已经添加过样式 + if (document.getElementById('markdown-node-styles')) return; + + const style = document.createElement('style'); + style.id = 'markdown-node-styles'; + style.textContent = ` + .markdown-content { + max-width: 100%; + overflow: hidden; + } + + .markdown-content h1, + .markdown-content h2, + .markdown-content h3, + .markdown-content h4, + .markdown-content h5, + .markdown-content h6 { + margin: 4px 0 2px 0; + font-weight: 600; + color: #333; + } + + .markdown-content h1 { font-size: 16px; } + .markdown-content h2 { font-size: 15px; } + .markdown-content h3 { font-size: 14px; } + .markdown-content h4 { font-size: 13px; } + .markdown-content h5 { font-size: 12px; } + .markdown-content h6 { font-size: 11px; } + + .markdown-content p { + margin: 2px 0; + line-height: 1.3; + color: #666; + } + + .markdown-content ul, + .markdown-content ol { + margin: 2px 0; + padding-left: 16px; + } + + .markdown-content li { + margin: 1px 0; + line-height: 1.3; + color: #666; + } + + .markdown-content strong, + .markdown-content b { + font-weight: 600; + color: #333; + } + + .markdown-content em, + .markdown-content i { + font-style: italic; + color: #555; + } + + .markdown-content code { + background: #f5f5f5; + padding: 1px 4px; + border-radius: 3px; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 11px; + color: #d63384; + } + + .markdown-content pre { + background: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 8px; + margin: 4px 0; + overflow-x: auto; + } + + .markdown-content pre code { + background: none; + padding: 0; + color: #333; + font-size: 11px; + } + + .markdown-table { + border-collapse: collapse; + width: 100%; + margin: 4px 0; + font-size: 11px; + } + + .markdown-table th, + .markdown-table td { + border: 1px solid #ddd; + padding: 4px 6px; + text-align: left; + } + + .markdown-table th { + background-color: #f8f9fa; + font-weight: 600; + color: #333; + } + + .markdown-table tr:nth-child(even) { + background-color: #f8f9fa; + } + + .markdown-content a { + color: #007bff; + text-decoration: none; + } + + .markdown-content a:hover { + text-decoration: underline; + } + + .markdown-content blockquote { + border-left: 3px solid #ddd; + margin: 4px 0; + padding-left: 8px; + color: #666; + font-style: italic; + } + + .markdown-math { + font-family: 'Times New Roman', serif; + } + + .markdown-error { + color: #dc3545; + background: #f8d7da; + border: 1px solid #f5c6cb; + padding: 4px 8px; + border-radius: 4px; + font-size: 11px; + } + `; + + document.head.appendChild(style); +}; + +/** + * 检查内容是否包含markdown语法 + * @param {string} content - 内容文本 + * @returns {boolean} 是否包含markdown语法 + */ +export const hasMarkdownSyntax = (content) => { + if (!content || typeof content !== 'string') return false; + + // 检查常见的markdown语法 + const markdownPatterns = [ + /#{1,6}\s+/, // 标题 + /\*\*.*?\*\*/, // 粗体 + /\*.*?\*/, // 斜体 + /`.*?`/, // 行内代码 + /```[\s\S]*?```/, // 代码块 + /\|.*\|/, // 表格 + /^\s*[-*+]\s+/m, // 列表 + /^\s*\d+\.\s+/m, // 有序列表 + /\[.*?\]\(.*?\)/, // 链接 + /!\[.*?\]\(.*?\)/, // 图片 + ]; + + return markdownPatterns.some(pattern => pattern.test(content)); +}; + +/** + * 智能渲染节点内容 + * 根据内容类型选择渲染方式 + * @param {HTMLElement} nodeElement - 节点DOM元素 + * @param {string} content - 节点内容 + */ +export const smartRenderNodeContent = (nodeElement, content) => { + if (!nodeElement || !content) return; + + // 检查是否包含markdown语法 + if (hasMarkdownSyntax(content)) { + // 使用markdown渲染 + setNodeMarkdownContent(nodeElement, content); + } else { + // 使用普通文本渲染 + const topicText = nodeElement.querySelector('.topic-text'); + if (topicText) { + topicText.textContent = content; + } + } +}; + +export default { + renderMarkdownToHTML, + setNodeMarkdownContent, + hasMarkdownSyntax, + smartRenderNodeContent +};