@tnotesjs/core 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +0 -1
  2. package/config/defaultConfig.ts +33 -4
  3. package/config/index.ts +6 -0
  4. package/core/NoteIndexCache.ts +7 -1
  5. package/core/NoteManager.ts +18 -30
  6. package/dist/{chunk-5Y5IYS6C.js → chunk-UJG3UU5X.js} +21 -5
  7. package/dist/{chunk-5QN44ES5.js → chunk-XCWFZLER.js} +48 -368
  8. package/dist/cli/index.js +26 -78
  9. package/dist/index.js +1 -1
  10. package/dist/vitepress/config/index.js +159 -18
  11. package/package.json +3 -6
  12. package/services/index.ts +0 -1
  13. package/services/init-sub-repo/initSubRepoLogic.ts +0 -1
  14. package/services/note/service.ts +0 -1
  15. package/types/config.ts +0 -3
  16. package/types/note.ts +0 -2
  17. package/vitepress/assets/icons/icon__cursor.svg +4 -0
  18. package/vitepress/assets/icons/index.ts +1 -0
  19. package/vitepress/components/Layout/AboutPanel.vue +0 -24
  20. package/vitepress/components/Layout/DocBeforeControls.vue +6 -14
  21. package/vitepress/components/Layout/DocFooter.vue +3 -3
  22. package/vitepress/components/Layout/Layout.vue +0 -30
  23. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +20 -11
  24. package/vitepress/components/Layout/homeReadme.data.ts +0 -48
  25. package/vitepress/components/MindmapPreview/InlineRuns.ts +25 -0
  26. package/vitepress/components/MindmapPreview/MindmapOutlineNode.vue +62 -0
  27. package/vitepress/components/MindmapPreview/MindmapPreview.vue +287 -0
  28. package/vitepress/components/MindmapPreview/compat.test.ts +93 -0
  29. package/vitepress/components/MindmapPreview/compat.ts +128 -0
  30. package/vitepress/components/MindmapPreview/expandLevel.test.ts +40 -0
  31. package/vitepress/components/MindmapPreview/expandLevel.ts +28 -0
  32. package/vitepress/components/MindmapPreview/legacyCorpus.test.ts +57 -0
  33. package/vitepress/components/Settings/Settings.vue +76 -73
  34. package/vitepress/components/SidebarCard/FolderTreeItems.vue +16 -6
  35. package/vitepress/components/SidebarCard/SidebarCard.vue +21 -27
  36. package/vitepress/components/composables/useLocalIde.ts +83 -0
  37. package/vitepress/components/constants.ts +5 -6
  38. package/vitepress/components/utils/vscodePaths.test.ts +22 -0
  39. package/vitepress/components/utils/vscodePaths.ts +24 -2
  40. package/vitepress/configs/markdown.config.ts +77 -20
  41. package/vitepress/theme/index.ts +4 -2
  42. package/vitepress/theme/styles/doc-layout.scss +4 -4
  43. package/vitepress/theme/styles/index.scss +0 -1
  44. package/services/timestamp/index.ts +0 -7
  45. package/services/timestamp/service.ts +0 -465
  46. package/vitepress/components/MarkMap/MarkMap.vue +0 -625
  47. package/vitepress/theme/styles/components/markmap.scss +0 -122
@@ -9,13 +9,13 @@ import { ref, computed, watch } from 'vue'
9
9
  import {
10
10
  icon__fold,
11
11
  icon__github,
12
- icon__vscode,
13
12
  icon__folder,
14
13
  icon__search,
15
14
  icon__number_gray,
16
15
  icon__number_purple,
17
16
  } from '../../assets/icons'
18
17
  import { NOTES_DIR_KEY, REPO_NAME, AUTHOR, ROOT_ITEM } from '../constants.ts'
18
+ import { useLocalIde } from '../composables/useLocalIde'
19
19
  import FolderTreeItems from './FolderTreeItems.vue'
20
20
  import NotesTrendChart from './NotesTrendChart.vue'
21
21
  import { useSettingsDialog } from '../Settings/composables/useSettingsDialog'
@@ -29,9 +29,7 @@ import {
29
29
  import {
30
30
  getRepoRootPath,
31
31
  resolveNoteReadmePath,
32
- toVscodeFileUrl,
33
32
  } from '../utils/vscodePaths'
34
- import { formatDate } from '../utils.ts'
35
33
 
36
34
  // #region props
37
35
  const props = defineProps({
@@ -46,6 +44,14 @@ const props = defineProps({
46
44
  })
47
45
  // #endregion
48
46
 
47
+ const {
48
+ icon: localIdeIcon,
49
+ openNoteTitle,
50
+ openRepoTitle,
51
+ openReadmeTitle,
52
+ toFileUrl,
53
+ } = useLocalIde()
54
+
49
55
  // #region data
50
56
  const viewMode = ref('folder')
51
57
  const expandedTreeKeys = ref(new Set())
@@ -217,7 +223,7 @@ function openGithubRepo() {
217
223
  window.open(`https://github.com/${AUTHOR}/${REPO_NAME}`, '_blank')
218
224
  }
219
225
 
220
- // 打开 VS Code 知识库
226
+ // 打开本地 IDE 知识库
221
227
  function openVSCodeRepo() {
222
228
  const notesDir = localStorage.getItem(NOTES_DIR_KEY)
223
229
 
@@ -231,10 +237,10 @@ function openVSCodeRepo() {
231
237
  return
232
238
  }
233
239
 
234
- window.open('vscode://file/' + notesDir, '_blank')
240
+ window.open(toFileUrl(notesDir), '_blank')
235
241
  }
236
242
 
237
- // 打开 VS Code 中的笔记 README.md
243
+ // 在本地 IDE 中打开笔记 README.md
238
244
  function openVSCodeArticle(article) {
239
245
  const notesDir = localStorage.getItem(NOTES_DIR_KEY)
240
246
 
@@ -251,7 +257,7 @@ function openVSCodeArticle(article) {
251
257
  const notePath = resolveNoteReadmePath(notesDir, article.relativePath)
252
258
  if (!notePath) return
253
259
 
254
- window.open(toVscodeFileUrl(notePath), '_blank')
260
+ window.open(toFileUrl(notePath), '_blank')
255
261
  }
256
262
 
257
263
  function openVSCodeReadme() {
@@ -268,7 +274,7 @@ function openVSCodeReadme() {
268
274
  }
269
275
 
270
276
  const readmePath = `${getRepoRootPath(notesDir)}/README.md`
271
- window.open(toVscodeFileUrl(readmePath), '_blank')
277
+ window.open(toFileUrl(readmePath), '_blank')
272
278
  }
273
279
  </script>
274
280
 
@@ -318,9 +324,9 @@ function openVSCodeReadme() {
318
324
  <img :src="icon__github" alt="GitHub仓库" />
319
325
  </button>
320
326
 
321
- <!-- VS Code 按钮 -->
322
- <button class="vscode-open" @click="openVSCodeRepo">
323
- <img :src="icon__vscode" alt="使用 VS Code 打开本地知识库" />
327
+ <!-- 本地 IDE 按钮 -->
328
+ <button class="vscode-open" @click="openVSCodeRepo" :title="openRepoTitle">
329
+ <img :src="localIdeIcon" :alt="openRepoTitle" />
324
330
  </button>
325
331
 
326
332
  <!-- 关于按钮 -->
@@ -346,18 +352,6 @@ function openVSCodeReadme() {
346
352
  {{ AUTHOR }}/{{ REPO_NAME }}
347
353
  </a>
348
354
  </div>
349
- <div class="about-item">
350
- <span class="about-label">📅 创建时间</span>
351
- <span class="about-value">{{
352
- formatDate(ROOT_ITEM.created_at)
353
- }}</span>
354
- </div>
355
- <div class="about-item">
356
- <span class="about-label">♻️ 最近更新</span>
357
- <span class="about-value">{{
358
- formatDate(ROOT_ITEM.updated_at)
359
- }}</span>
360
- </div>
361
355
  </div>
362
356
  </div>
363
357
  </div>
@@ -395,9 +389,9 @@ function openVSCodeReadme() {
395
389
  <button
396
390
  class="vscode-article"
397
391
  @click.stop="openVSCodeArticle(article)"
398
- title="在 VS Code 中打开笔记目录"
392
+ :title="openNoteTitle"
399
393
  >
400
- <img :src="icon__vscode" alt="打开笔记目录" />
394
+ <img :src="localIdeIcon" :alt="openNoteTitle" />
401
395
  </button>
402
396
  </div>
403
397
  </div>
@@ -415,10 +409,10 @@ function openVSCodeReadme() {
415
409
  <button
416
410
  class="vscode-article"
417
411
  type="button"
418
- title="在 VS Code 中打开 README.md"
412
+ :title="openReadmeTitle"
419
413
  @click="openVSCodeReadme"
420
414
  >
421
- <img :src="icon__vscode" alt="打开 README.md" />
415
+ <img :src="localIdeIcon" :alt="openReadmeTitle" />
422
416
  </button>
423
417
  </div>
424
418
  <FolderTreeItems
@@ -0,0 +1,83 @@
1
+ /**
2
+ * vitepress/components/composables/useLocalIde.ts
3
+ *
4
+ * 本地 IDE(VS Code / Cursor)选择状态与展示信息
5
+ */
6
+
7
+ import { computed, ref } from 'vue'
8
+
9
+ import { icon__cursor, icon__vscode } from '../../assets/icons'
10
+ import { LOCAL_IDE_KEY } from '../constants'
11
+ import {
12
+ DEFAULT_LOCAL_IDE,
13
+ normalizeLocalIde,
14
+ toIdeFileUrl,
15
+ type LocalIdeId,
16
+ } from '../utils/vscodePaths'
17
+
18
+ const ide = ref<LocalIdeId>(DEFAULT_LOCAL_IDE)
19
+ let hydrated = false
20
+
21
+ function readIdeFromStorage(): LocalIdeId {
22
+ if (typeof window === 'undefined') return DEFAULT_LOCAL_IDE
23
+ return normalizeLocalIde(localStorage.getItem(LOCAL_IDE_KEY))
24
+ }
25
+
26
+ function hydrateFromStorage() {
27
+ if (typeof window === 'undefined' || hydrated) return
28
+ ide.value = readIdeFromStorage()
29
+ hydrated = true
30
+ }
31
+
32
+ export function useLocalIde() {
33
+ hydrateFromStorage()
34
+
35
+ const icon = computed(() =>
36
+ ide.value === 'cursor' ? icon__cursor : icon__vscode,
37
+ )
38
+
39
+ const shortLabel = computed(() =>
40
+ ide.value === 'cursor' ? 'Cursor' : 'VS Code',
41
+ )
42
+
43
+ const openNoteTitle = computed(
44
+ () => `用 ${shortLabel.value} 打开笔记目录`,
45
+ )
46
+ const openRepoTitle = computed(
47
+ () => `用 ${shortLabel.value} 打开本地知识库`,
48
+ )
49
+ const openReadmeTitle = computed(
50
+ () => `用 ${shortLabel.value} 打开 README.md`,
51
+ )
52
+ const openCurrentTitle = computed(
53
+ () => `用 ${shortLabel.value} 打开当前笔记`,
54
+ )
55
+
56
+ function setLocalIde(next: LocalIdeId) {
57
+ ide.value = normalizeLocalIde(next)
58
+ if (typeof window !== 'undefined') {
59
+ localStorage.setItem(LOCAL_IDE_KEY, ide.value)
60
+ }
61
+ }
62
+
63
+ function refreshLocalIde() {
64
+ ide.value = readIdeFromStorage()
65
+ }
66
+
67
+ function toFileUrl(filePath: string) {
68
+ return toIdeFileUrl(filePath, ide.value)
69
+ }
70
+
71
+ return {
72
+ ide,
73
+ icon,
74
+ shortLabel,
75
+ openNoteTitle,
76
+ openRepoTitle,
77
+ openReadmeTitle,
78
+ openCurrentTitle,
79
+ setLocalIde,
80
+ refreshLocalIde,
81
+ toFileUrl,
82
+ }
83
+ }
@@ -37,6 +37,11 @@ export const ROOT_ITEM = __TNOTES_ROOT_ITEM__
37
37
  */
38
38
  export const NOTES_DIR_KEY: string = 'NOTES_DIR_KEY__' + REPO_NAME
39
39
 
40
+ /**
41
+ * 本地打开所用 IDE(vscode | cursor)
42
+ */
43
+ export const LOCAL_IDE_KEY: string = 'LOCAL_IDE_KEY__' + REPO_NAME
44
+
40
45
  /**
41
46
  * 用户选择的视图
42
47
  */
@@ -53,12 +58,6 @@ export const EN_WORD_LIST_COMP_IS_AUTO_SHOW_CARD: string =
53
58
  */
54
59
  export const MARKMAP_THEME_KEY: string = 'MARKMAP_THEME_KEY__' + REPO_NAME
55
60
 
56
- /**
57
- * MarkMap 默认展开层级配置
58
- */
59
- export const MARKMAP_EXPAND_LEVEL_KEY: string =
60
- 'MARKMAP_EXPAND_LEVEL_KEY__' + REPO_NAME
61
-
62
61
  /**
63
62
  * 侧边栏是否显示笔记编号配置
64
63
  */
@@ -2,7 +2,9 @@ import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import {
4
4
  getRepoRootPath,
5
+ normalizeLocalIde,
5
6
  resolveNoteReadmePath,
7
+ toIdeFileUrl,
6
8
  toVscodeFileUrl,
7
9
  } from './vscodePaths'
8
10
 
@@ -33,6 +35,26 @@ describe('vscodePaths', () => {
33
35
  )
34
36
  })
35
37
 
38
+ it('normalizeLocalIde falls back to vscode', () => {
39
+ expect(normalizeLocalIde(null)).toBe('vscode')
40
+ expect(normalizeLocalIde('')).toBe('vscode')
41
+ expect(normalizeLocalIde('foo')).toBe('vscode')
42
+ expect(normalizeLocalIde('cursor')).toBe('cursor')
43
+ expect(normalizeLocalIde('vscode')).toBe('vscode')
44
+ })
45
+
46
+ it('toIdeFileUrl uses vscode scheme by default', () => {
47
+ expect(toIdeFileUrl('C:\\notes\\0001\\README.md')).toContain(
48
+ 'vscode://file/',
49
+ )
50
+ })
51
+
52
+ it('toIdeFileUrl uses cursor scheme when selected', () => {
53
+ expect(toIdeFileUrl('C:\\notes\\0001\\README.md', 'cursor')).toContain(
54
+ 'cursor://file/',
55
+ )
56
+ })
57
+
36
58
  it('toVscodeFileUrl encodes file path', () => {
37
59
  expect(toVscodeFileUrl('C:\\notes\\0001\\README.md')).toContain(
38
60
  'vscode://file/',
@@ -1,10 +1,19 @@
1
1
  /**
2
2
  * vitepress/components/utils/vscodePaths.ts
3
3
  *
4
- * 将站点内路径解析为本地 VS Code 可打开的文件路径。
4
+ * 将站点内路径解析为本地 IDE 可打开的文件路径与 URL。
5
5
  * NOTES_DIR 通常配置为仓库下的 notes 目录(如 .../TNotes.introduction/notes)。
6
6
  */
7
7
 
8
+ export type LocalIdeId = 'vscode' | 'cursor'
9
+
10
+ export const DEFAULT_LOCAL_IDE: LocalIdeId = 'vscode'
11
+
12
+ const IDE_SCHEMES: Record<LocalIdeId, string> = {
13
+ vscode: 'vscode',
14
+ cursor: 'cursor',
15
+ }
16
+
8
17
  export function getRepoRootPath(notesDir: string): string {
9
18
  const normalized = notesDir.replace(/[/\\]+$/, '')
10
19
  if (/[/\\]notes$/i.test(normalized)) {
@@ -47,6 +56,19 @@ export function resolveNoteReadmePath(
47
56
  return `${base}${sep}${folderPath}${sep}README.md`
48
57
  }
49
58
 
59
+ export function normalizeLocalIde(value: string | null | undefined): LocalIdeId {
60
+ return value === 'cursor' ? 'cursor' : DEFAULT_LOCAL_IDE
61
+ }
62
+
63
+ export function toIdeFileUrl(
64
+ filePath: string,
65
+ ide: LocalIdeId = DEFAULT_LOCAL_IDE,
66
+ ): string {
67
+ const scheme = IDE_SCHEMES[normalizeLocalIde(ide)]
68
+ return `${scheme}://file/${encodeURI(filePath)}`
69
+ }
70
+
71
+ /** @deprecated 使用 toIdeFileUrl(filePath, 'vscode') */
50
72
  export function toVscodeFileUrl(filePath: string): string {
51
- return `vscode://file/${encodeURI(filePath)}`
73
+ return toIdeFileUrl(filePath, 'vscode')
52
74
  }
@@ -11,6 +11,11 @@ import markdownItTaskLists from 'markdown-it-task-lists'
11
11
  import path from 'path'
12
12
 
13
13
  import { generateAnchor } from '../../utils'
14
+ import {
15
+ normalizeMindmapMarkdown,
16
+ parseMarkmapFence,
17
+ parseMindmapReference,
18
+ } from '../components/MindmapPreview/compat'
14
19
 
15
20
  import type MarkdownIt from 'markdown-it'
16
21
  import type { MarkdownOptions } from 'vitepress'
@@ -66,17 +71,13 @@ const simpleMermaidMarkdown = (md: MarkdownIt) => {
66
71
  }
67
72
 
68
73
  /**
69
- * MarkMap 容器配置
74
+ * Mindmap 容器配置(兼容旧的 markmap 围栏名)
70
75
  */
71
- function configureMarkMapContainer(md: MarkdownIt) {
72
- // 先保留 container 的解析(负责把 ```markmap ``` 识别成 container tokens)
73
- // 但让它本身不输出任何 HTML(render 返回空)
76
+ function configureMindmapContainer(md: MarkdownIt) {
74
77
  md.use(markdownItContainer, 'markmap', {
75
78
  marker: '`',
76
79
  validate(params: string) {
77
- // 接受 "markmap", "markmap{...}" 或 "markmap key=val ..." 等写法
78
- const p = (params || '').trim()
79
- return p.startsWith('markmap')
80
+ return (params || '').trim().startsWith('markmap')
80
81
  },
81
82
  render() {
82
83
  return ''
@@ -93,11 +94,13 @@ function configureMarkMapContainer(md: MarkdownIt) {
93
94
  for (let i = 0; i < tokens.length; i++) {
94
95
  const t = tokens[i]
95
96
  if (t.type === 'container_markmap_open') {
97
+ const containerName = 'markmap'
98
+ const closeType = 'container_markmap_close'
96
99
  // 找到对应的 close token
97
100
  let j = i + 1
98
101
  while (
99
102
  j < tokens.length &&
100
- tokens[j].type !== 'container_markmap_close'
103
+ tokens[j].type !== closeType
101
104
  )
102
105
  j++
103
106
  if (j >= tokens.length) continue // safety
@@ -109,9 +112,12 @@ function configureMarkMapContainer(md: MarkdownIt) {
109
112
 
110
113
  // 1) 从开头 fence 行解析参数(支持 `{a=1 b="x"}`、`a=1 b="x"`,并支持单个数字 shorthand)
111
114
  const params: { [key: string]: any; initialExpandLevel?: number } = {}
115
+ let explicitTitle: string | undefined
112
116
 
113
117
  if (open.map && typeof open.map[0] === 'number') {
114
118
  const openLine = (lines[open.map[0]] || '').trim()
119
+ const fenceOptions = parseMarkmapFence(openLine)
120
+ explicitTitle = fenceOptions.title
115
121
  let paramPart = ''
116
122
 
117
123
  // 优先匹配大括号形式 ```markmap{...}
@@ -121,10 +127,13 @@ function configureMarkMapContainer(md: MarkdownIt) {
121
127
  } else {
122
128
  // 否则尝试去掉前缀 ``` 和 markmap,剩下的作为参数部分
123
129
  const after = openLine.replace(/^`+\s*/, '')
124
- if (after.startsWith('markmap')) {
125
- paramPart = after.slice('markmap'.length).trim()
130
+ if (after.startsWith(containerName)) {
131
+ paramPart = after.slice(containerName.length).trim()
126
132
  }
127
133
  }
134
+ if (fenceOptions.initialExpandLevel !== undefined) {
135
+ params.initialExpandLevel = fenceOptions.initialExpandLevel
136
+ }
128
137
 
129
138
  if (paramPart) {
130
139
  // 使用正则按 token 切分:保持用引号包裹的片段为单个 token(支持包含空格)
@@ -179,10 +188,11 @@ function configureMarkMapContainer(md: MarkdownIt) {
179
188
  // --- 检查第一非空行是否为引用语法 ---
180
189
  const firstNonEmptyLine =
181
190
  (content || '').split('\n').find((ln) => ln.trim() !== '') || ''
182
- const refMatch = firstNonEmptyLine.trim().match(/^<<<\s*(.+)$/)
183
- if (refMatch) {
184
- // 提取引用路径,支持引号包裹
185
- const refRaw = refMatch[1].trim().replace(/^['"]|['"]$/g, '')
191
+ const reference = parseMindmapReference(firstNonEmptyLine)
192
+ let referencedTitle: string | undefined
193
+ if (reference) {
194
+ const refRaw = reference.path
195
+ referencedTitle = reference.title
186
196
 
187
197
  // 尝试同步读取文件内容(兼容常见 Node 环境)
188
198
  try {
@@ -213,12 +223,14 @@ function configureMarkMapContainer(md: MarkdownIt) {
213
223
  } catch (err) {
214
224
  // 读取失败:将错误写入 content 以便排查(不会让流程直接崩溃)
215
225
  const errorMsg = err instanceof Error ? err.message : String(err)
216
- content = `Failed to load referenced file: ${esc(
217
- String(refRaw)
218
- )}\n\nError: ${esc(errorMsg)}`
226
+ content = `- Failed to load referenced file: ${esc(String(refRaw))}\n - Error: ${esc(errorMsg)}`
219
227
  }
220
228
  }
221
229
 
230
+ content = normalizeMindmapMarkdown(content, {
231
+ title: explicitTitle || referencedTitle,
232
+ })
233
+
222
234
  // 3) 构造组件标签并把参数注入为 props
223
235
  const encodedContent = encodeURIComponent(content.trim())
224
236
  let propsStr = `content="${encodedContent}"`
@@ -232,7 +244,7 @@ function configureMarkMapContainer(md: MarkdownIt) {
232
244
  }
233
245
  }
234
246
 
235
- const html = `<MarkMap ${propsStr}></MarkMap>\n`
247
+ const html = `<MindmapPreview ${propsStr}></MindmapPreview>\n`
236
248
 
237
249
  // 创建 html_block token
238
250
  const htmlToken = new state.Token('html_block', '', 0)
@@ -247,6 +259,50 @@ function configureMarkMapContainer(md: MarkdownIt) {
247
259
  })
248
260
  }
249
261
 
262
+ /** Canonical `mindmap` fence. Legacy `markmap` stays on its historical container path. */
263
+ function configureMindmapFence(md: MarkdownIt) {
264
+ const fence = md.renderer.rules.fence
265
+ ? md.renderer.rules.fence.bind(md.renderer.rules)
266
+ : () => ''
267
+
268
+ md.renderer.rules.fence = (tokens, index, options, env, slf) => {
269
+ const token = tokens[index]
270
+ const info = token.info.trim()
271
+ if (!/^mindmap(?=\s|\{|\[|$)/.test(info)) {
272
+ return fence(tokens, index, options, env, slf)
273
+ }
274
+
275
+ const fenceOptions = parseMarkmapFence(info)
276
+ let content = token.content
277
+ const firstNonEmptyLine = content.split('\n').find((line) => line.trim()) ?? ''
278
+ const reference = parseMindmapReference(firstNonEmptyLine)
279
+
280
+ if (reference) {
281
+ const possibleRel = env?.relativePath || env?.path || env?.filePath || env?.file || ''
282
+ const refFullPath = path.isAbsolute(reference.path)
283
+ ? reference.path
284
+ : path.resolve(process.cwd(), possibleRel ? path.dirname(possibleRel) : '', reference.path)
285
+ try {
286
+ content = fs.readFileSync(refFullPath, 'utf8')
287
+ } catch (error) {
288
+ const message = error instanceof Error ? error.message : String(error)
289
+ content = `- Failed to load referenced file: ${reference.path}\n - Error: ${message}`
290
+ }
291
+ }
292
+
293
+ content = normalizeMindmapMarkdown(content, {
294
+ title: fenceOptions.title || reference?.title,
295
+ })
296
+ const props = [
297
+ `content="${encodeURIComponent(content.trim())}"`,
298
+ fenceOptions.initialExpandLevel === undefined
299
+ ? ''
300
+ : `:initialExpandLevel="${fenceOptions.initialExpandLevel}"`,
301
+ ].filter(Boolean).join(' ')
302
+ return `<MindmapPreview ${props}></MindmapPreview>\n`
303
+ }
304
+ }
305
+
250
306
  /**
251
307
  * Swiper 容器配置
252
308
  */
@@ -340,8 +396,9 @@ export function getMarkdownConfig(): MarkdownOptions {
340
396
  // 添加 Mermaid 支持
341
397
  simpleMermaidMarkdown(md)
342
398
 
343
- // 添加 MarkMap 支持
344
- configureMarkMapContainer(md)
399
+ // 添加 Mindmap 支持,并继续兼容旧 MarkMap 围栏
400
+ configureMindmapContainer(md)
401
+ configureMindmapFence(md)
345
402
 
346
403
  // 添加任务列表支持
347
404
  md.use(markdownItTaskLists)
@@ -22,8 +22,8 @@ import Footprints from '../components/Footprints/Footprints.vue'
22
22
  import { useRenameOverlay } from '../components/Layout/composables/useRenameOverlay'
23
23
  import { redirectAfterRename } from '../components/Layout/composables/useRenameRedirect'
24
24
  import Layout from '../components/Layout/Layout.vue'
25
- import MarkMap from '../components/MarkMap/MarkMap.vue'
26
25
  import Mermaid from '../components/Mermaid/Mermaid.vue'
26
+ import MindmapPreview from '../components/MindmapPreview/MindmapPreview.vue'
27
27
  import NotesTable from '../components/NotesTable/NotesTable.vue'
28
28
  import SidebarCard from '../components/SidebarCard/SidebarCard.vue'
29
29
  import Tooltip from '../components/Tooltip/Tooltip.vue'
@@ -45,7 +45,9 @@ function registerCoreComponents(ctx: EnhanceAppContext) {
45
45
  app.component('Footprints', Footprints)
46
46
  app.component('F', Footprints)
47
47
  app.component('SidebarCard', SidebarCard)
48
- app.component('MarkMap', MarkMap)
48
+ // Keep the historical component name so existing note fences need no migration.
49
+ app.component('MarkMap', MindmapPreview)
50
+ app.component('MindmapPreview', MindmapPreview)
49
51
  app.component('Mermaid', Mermaid)
50
52
  app.component('NotesTable', NotesTable)
51
53
  app.component('N', NotesTable)
@@ -100,8 +100,8 @@
100
100
  width: 100% !important;
101
101
  }
102
102
 
103
- /* aside 已 fixedcontainer 不再为右栏预留 flex */
104
- .VPDoc.has-aside .container {
103
+ /* aside 已 fixed,仅改 VPDoc 直接子级 container,避免误伤 DocFooter 等内部 .container */
104
+ .VPDoc.has-aside > .container {
105
105
  display: block !important;
106
106
  max-width: none !important;
107
107
  }
@@ -188,8 +188,8 @@ html.content-fullscreen {
188
188
  padding-right: 0 !important;
189
189
  }
190
190
 
191
- .VPDoc.has-aside .container,
192
- .VPDoc .container {
191
+ .VPDoc.has-aside > .container,
192
+ .VPDoc > .container {
193
193
  max-width: none !important;
194
194
  width: 100% !important;
195
195
  }
@@ -17,7 +17,6 @@
17
17
 
18
18
  /* 4. 组件全局层:跨组件共享的样式 */
19
19
  @use './components/swiper';
20
- @use './components/markmap';
21
20
  @use './components/collapse';
22
21
  /**
23
22
  * !404 不是一个有效的 Sass 标识符(不能以数字开头),需要为它添加一个别名
@@ -1,7 +0,0 @@
1
- /**
2
- * services/timestamp/index.ts
3
- *
4
- * Timestamp 服务入口
5
- */
6
-
7
- export { TimestampService } from './service'