@tnotesjs/core 0.1.15 → 0.1.17

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 (117) hide show
  1. package/README.md +87 -87
  2. package/dist/{chunk-FVKQPBPP.js → chunk-4MO7F7Q4.js} +2005 -1769
  3. package/dist/cli/index.js +1 -1
  4. package/dist/vitepress/config/index.js +212 -4
  5. package/package.json +1 -1
  6. package/types/config.ts +61 -61
  7. package/types/index.ts +11 -11
  8. package/types/note.ts +33 -33
  9. package/vitepress/assets/icons/icon__check.svg +3 -3
  10. package/vitepress/assets/icons/icon__clipboard.svg +7 -7
  11. package/vitepress/assets/icons/icon__close.svg +1 -1
  12. package/vitepress/assets/icons/icon__collapse.svg +1 -1
  13. package/vitepress/assets/icons/icon__confirm.svg +1 -1
  14. package/vitepress/assets/icons/icon__copy.svg +4 -4
  15. package/vitepress/assets/icons/icon__focus.svg +1 -1
  16. package/vitepress/assets/icons/icon__fold.svg +3 -3
  17. package/vitepress/assets/icons/icon__folder.svg +1 -1
  18. package/vitepress/assets/icons/icon__fullscreen.svg +1 -1
  19. package/vitepress/assets/icons/icon__fullscreen_exit.svg +1 -1
  20. package/vitepress/assets/icons/icon__github.svg +3 -3
  21. package/vitepress/assets/icons/icon__mindmap.svg +1 -1
  22. package/vitepress/assets/icons/icon__next.svg +1 -1
  23. package/vitepress/assets/icons/icon__number_gray.svg +1 -1
  24. package/vitepress/assets/icons/icon__number_purple.svg +1 -1
  25. package/vitepress/assets/icons/icon__prev.svg +1 -1
  26. package/vitepress/assets/icons/icon__restore.svg +1 -1
  27. package/vitepress/assets/icons/icon__rotate.svg +4 -4
  28. package/vitepress/assets/icons/icon__search.svg +1 -1
  29. package/vitepress/assets/icons/icon__sidebar_collapsed.svg +1 -1
  30. package/vitepress/assets/icons/icon__sidebar_opened.svg +1 -1
  31. package/vitepress/assets/icons/icon__totop.svg +5 -5
  32. package/vitepress/assets/icons/icon__vscode.svg +5 -5
  33. package/vitepress/assets/icons/icon__zoom_fit.svg +1 -1
  34. package/vitepress/assets/icons/icon__zoom_in.svg +1 -1
  35. package/vitepress/assets/icons/icon__zoom_out.svg +1 -1
  36. package/vitepress/assets/icons/icon__zoom_reset.svg +1 -1
  37. package/vitepress/assets/icons/index.ts +39 -39
  38. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +20 -20
  39. package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +373 -373
  40. package/vitepress/components/CodeBlockFullscreen/index.ts +115 -115
  41. package/vitepress/components/CodeBlockFullscreen/styles.css +64 -64
  42. package/vitepress/components/Discussions/Discussions.module.scss +32 -32
  43. package/vitepress/components/Discussions/Discussions.vue +211 -211
  44. package/vitepress/components/EnWordList/EnWordList.module.scss +124 -124
  45. package/vitepress/components/EnWordList/EnWordList.vue +543 -543
  46. package/vitepress/components/EnWordList/RightClickMenu.module.scss +22 -22
  47. package/vitepress/components/EnWordList/RightClickMenu.vue +66 -66
  48. package/vitepress/components/Footprints/Footprints.module.scss +93 -93
  49. package/vitepress/components/Footprints/Footprints.vue +377 -377
  50. package/vitepress/components/Layout/AboutModal.module.scss +233 -233
  51. package/vitepress/components/Layout/AboutModal.vue +105 -105
  52. package/vitepress/components/Layout/AboutPanel.vue +270 -270
  53. package/vitepress/components/Layout/ContentCollapse.vue +603 -603
  54. package/vitepress/components/Layout/CustomSidebar.vue +817 -608
  55. package/vitepress/components/Layout/DocBeforeControls.vue +149 -149
  56. package/vitepress/components/Layout/DocFooter.vue +233 -233
  57. package/vitepress/components/Layout/ImagePreview.module.scss +201 -201
  58. package/vitepress/components/Layout/ImagePreview.vue +281 -281
  59. package/vitepress/components/Layout/Layout.module.scss +661 -661
  60. package/vitepress/components/Layout/Layout.vue +621 -559
  61. package/vitepress/components/Layout/NoteStatus.vue +140 -140
  62. package/vitepress/components/Layout/SidebarItems.vue +1083 -268
  63. package/vitepress/components/Layout/SidebarNavBefore.vue +171 -108
  64. package/vitepress/components/Layout/SidebarResizeHandle.vue +319 -0
  65. package/vitepress/components/Layout/Swiper.vue +167 -167
  66. package/vitepress/components/Layout/ToggleFullContent.module.scss +11 -11
  67. package/vitepress/components/Layout/ToggleFullContent.vue +35 -35
  68. package/vitepress/components/Layout/ToggleSidebar.module.scss +11 -11
  69. package/vitepress/components/Layout/ToggleSidebar.vue +26 -36
  70. package/vitepress/components/Layout/composables/useCollapseControl.ts +88 -88
  71. package/vitepress/components/Layout/composables/useNoteConfig.ts +119 -119
  72. package/vitepress/components/Layout/composables/useNoteSave.ts +178 -178
  73. package/vitepress/components/Layout/composables/useNoteValidation.ts +85 -85
  74. package/vitepress/components/Layout/composables/useRedirect.ts +113 -113
  75. package/vitepress/components/Layout/composables/useSidebarLayout.ts +122 -0
  76. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +85 -85
  77. package/vitepress/components/Layout/homeReadme.data.ts +124 -124
  78. package/vitepress/components/MarkMap/MarkMap.module.scss +159 -159
  79. package/vitepress/components/MarkMap/MarkMap.vue +405 -405
  80. package/vitepress/components/Mermaid/Mermaid.module.scss +275 -275
  81. package/vitepress/components/Mermaid/Mermaid.vue +365 -365
  82. package/vitepress/components/NotesTable/NotesTable.module.scss +77 -77
  83. package/vitepress/components/NotesTable/NotesTable.vue +98 -98
  84. package/vitepress/components/NotesTable/README.md +67 -67
  85. package/vitepress/components/Settings/Settings.module.scss +375 -433
  86. package/vitepress/components/Settings/Settings.vue +333 -306
  87. package/vitepress/components/SidebarCard/MindMapView.vue +484 -484
  88. package/vitepress/components/SidebarCard/NotesTrendChart.vue +108 -108
  89. package/vitepress/components/SidebarCard/SidebarCard.vue +946 -946
  90. package/vitepress/components/Tooltip/Tooltip.vue +70 -70
  91. package/vitepress/components/constants.ts +109 -91
  92. package/vitepress/components/notesConfig.data.ts +73 -73
  93. package/vitepress/components/sidebar.data.ts +59 -59
  94. package/vitepress/components/tnotes-config.data.ts +21 -21
  95. package/vitepress/components/utils.ts +26 -26
  96. package/vitepress/config/index.ts +169 -167
  97. package/vitepress/configs/constants.ts +26 -26
  98. package/vitepress/configs/head.config.ts +25 -25
  99. package/vitepress/configs/index.ts +9 -9
  100. package/vitepress/configs/markdown-it.d.ts +23 -23
  101. package/vitepress/configs/markdown.config.ts +366 -366
  102. package/vitepress/configs/theme.config.ts +108 -108
  103. package/vitepress/plugins/buildProgressPlugin.ts +434 -434
  104. package/vitepress/plugins/getNoteByConfigIdPlugin.ts +107 -107
  105. package/vitepress/plugins/renameNotePlugin.ts +68 -68
  106. package/vitepress/plugins/sidebarStructurePlugin.ts +260 -0
  107. package/vitepress/plugins/updateConfigPlugin.ts +63 -63
  108. package/vitepress/theme/index.ts +137 -137
  109. package/vitepress/theme/styles/base.scss +51 -50
  110. package/vitepress/theme/styles/components/404.scss +31 -31
  111. package/vitepress/theme/styles/components/collapse.scss +185 -175
  112. package/vitepress/theme/styles/components/markmap.scss +101 -101
  113. package/vitepress/theme/styles/components/swiper.scss +255 -255
  114. package/vitepress/theme/styles/index.scss +25 -25
  115. package/vitepress/theme/styles/layout.scss +78 -62
  116. package/vitepress/theme/styles/utilities.scss +39 -39
  117. package/vitepress/theme/styles/vitepress-override.scss +25 -25
@@ -1,307 +1,334 @@
1
- <template>
2
- <div :class="$style.settingsWrapper">
3
- <!-- 本地路径配置 -->
4
- <div :class="$style.settingItem">
5
- <div :class="$style.itemHeader">
6
- <div :class="$style.itemTitle">
7
- <span :class="$style.itemIcon">📁</span>
8
- <span :class="$style.itemName">本地知识库路径</span>
9
- </div>
10
- <span :class="$style.statusBadge" v-if="path">✓</span>
11
- </div>
12
-
13
- <div :class="$style.helpText">
14
- 适用于 PC 桌面环境,需要本地安装 VS Code
15
- 编辑器。配置后可在侧边栏快速打开笔记。
16
- </div>
17
-
18
- <div :class="$style.inputGroup">
19
- <input
20
- v-model="path"
21
- type="text"
22
- placeholder="例如: C:\notes 或 /Users/username/notes"
23
- :class="$style.input"
24
- />
25
- <button
26
- v-if="path"
27
- @click="clearPath"
28
- :class="$style.clearBtn"
29
- title="清空"
30
- >
31
-
32
- </button>
33
- </div>
34
- </div>
35
-
36
- <!-- 内容宽度配置 -->
37
- <div :class="$style.settingItem">
38
- <div :class="$style.itemHeader">
39
- <div :class="$style.itemTitle">
40
- <span :class="$style.itemIcon">📏</span>
41
- <span :class="$style.itemName">内容区宽度</span>
42
- </div>
43
- <span :class="$style.currentValue">{{ contentWidth }}</span>
44
- </div>
45
-
46
- <div :class="$style.helpText">
47
- 调整文章内容区域的最大宽度(全屏模式下不限制宽度)。
48
- </div>
49
-
50
- <select
51
- v-model="contentWidth"
52
- @change="applyContentWidth"
53
- :class="$style.select"
54
- >
55
- <option value="688px">标准 (688px)</option>
56
- <option value="755px">较大 (755px)</option>
57
- </select>
58
- </div>
59
-
60
- <!-- 侧边栏配置 -->
61
- <div :class="$style.settingItem">
62
- <div :class="$style.itemHeader">
63
- <div :class="$style.itemTitle">
64
- <span :class="$style.itemIcon">📑</span>
65
- <span :class="$style.itemName">侧边栏配置</span>
66
- </div>
67
- <span :class="$style.statusBadge" v-if="showNoteId">显示编号</span>
68
- </div>
69
-
70
- <div :class="$style.helpText">
71
- 控制侧边栏中是否显示笔记编号(如 "0001. ")。
72
- </div>
73
-
74
- <div :class="$style.field">
75
- <label :class="$style.checkboxLabel">
76
- <input
77
- v-model="showNoteId"
78
- type="checkbox"
79
- :class="$style.checkbox"
80
- />
81
- <span>显示笔记编号</span>
82
- </label>
83
- <div :class="$style.fieldHelp">
84
- 勾选后,侧边栏将显示完整的笔记标题(包含编号),例如 "0001. TNotes
85
- 简介"
86
- </div>
87
- </div>
88
- </div>
89
-
90
- <!-- MarkMap 配置 -->
91
- <div :class="$style.settingItem">
92
- <div :class="$style.itemHeader">
93
- <div :class="$style.itemTitle">
94
- <span :class="$style.itemIcon">💡</span>
95
- <span :class="$style.itemName">MarkMap 思维导图</span>
96
- </div>
97
- </div>
98
-
99
- <div :class="$style.helpText">配置思维导图的默认显示效果。</div>
100
-
101
- <div :class="$style.field">
102
- <div :class="$style.fieldLabel">
103
- <span>分支主题</span>
104
- </div>
105
- <div :class="$style.fieldHelp">选择思维导图分支的配色方案</div>
106
- <select v-model="markmapTheme" :class="$style.select">
107
- <option value="default">默认主题</option>
108
- <option value="colorful">多彩主题</option>
109
- <option value="dark">深色主题</option>
110
- </select>
111
- </div>
112
-
113
- <div :class="$style.field">
114
- <div :class="$style.fieldLabel">
115
- <span>展开层级</span>
116
- </div>
117
- <div :class="$style.fieldHelp">
118
- 设置思维导图初始展开的层级深度(1-100)
119
- </div>
120
- <div :class="$style.inputWithUnit">
121
- <input
122
- v-model.number="markmapExpandLevel"
123
- type="number"
124
- min="1"
125
- max="100"
126
- :class="$style.input"
127
- />
128
- <span :class="$style.unit">层</span>
129
- </div>
130
- </div>
131
- </div>
132
-
133
- <!-- 操作栏 -->
134
- <div :class="$style.actionBar">
135
- <button
136
- @click="save"
137
- :class="[$style.saveBtn, { [$style.disabled]: !hasChanges }]"
138
- :disabled="!hasChanges"
139
- >
140
- {{ saveText }}
141
- </button>
142
- <button v-if="hasChanges" @click="reset" :class="$style.resetBtn">
143
- 重置
144
- </button>
145
- </div>
146
-
147
- <!-- 保存成功提示 -->
148
- <Transition name="toast">
149
- <div v-if="showSuccessToast" :class="$style.toast">✓ 保存成功</div>
150
- </Transition>
151
- </div>
152
- </template>
153
-
154
- <script setup lang="ts">
1
+ <template>
2
+ <div :class="$style.settingsWrapper">
3
+ <section :class="$style.settingsSection">
4
+ <div :class="$style.settingItem">
5
+ <div :class="$style.settingMeta">
6
+ <div :class="$style.labelLine">
7
+ <span :class="$style.itemName">本地知识库路径</span>
8
+ <span :class="$style.infoWrap">
9
+ <span :class="$style.infoIcon">?</span>
10
+ <span :class="$style.tooltip">
11
+ 适用于 PC 桌面环境,需要本地安装 VS Code。配置后可从页面快速打开本地笔记目录。
12
+ </span>
13
+ </span>
14
+ </div>
15
+ <span v-if="path" :class="$style.statusText">已配置</span>
16
+ </div>
17
+
18
+ <div :class="$style.inputGroup">
19
+ <input
20
+ v-model="path"
21
+ type="text"
22
+ placeholder="/Users/username/notes"
23
+ :class="$style.input"
24
+ />
25
+ <button
26
+ v-if="path"
27
+ @click="clearPath"
28
+ :class="$style.clearBtn"
29
+ title="清空"
30
+ type="button"
31
+ >
32
+ ×
33
+ </button>
34
+ </div>
35
+ </div>
36
+
37
+ <div :class="$style.settingItem">
38
+ <div :class="$style.settingMeta">
39
+ <div :class="$style.labelLine">
40
+ <span :class="$style.itemName">侧边栏目录</span>
41
+ <span :class="$style.infoWrap">
42
+ <span :class="$style.infoIcon">?</span>
43
+ <span :class="$style.tooltip">
44
+ 控制侧边栏笔记编号显示,以及目录行距密度。保存后会刷新页面以应用侧边栏配置。
45
+ </span>
46
+ </span>
47
+ </div>
48
+ <span v-if="showNoteId" :class="$style.statusText">显示编号</span>
49
+ </div>
50
+
51
+ <div :class="$style.fieldStack">
52
+ <label :class="$style.checkRow">
53
+ <input
54
+ v-model="showNoteId"
55
+ type="checkbox"
56
+ :class="$style.checkbox"
57
+ />
58
+ <span>显示笔记编号</span>
59
+ </label>
60
+
61
+ <div :class="$style.controlRow">
62
+ <span :class="$style.controlLabel">目录风格</span>
63
+ <div :class="$style.segmented">
64
+ <label
65
+ v-for="option in sidebarDensityOptions"
66
+ :key="option.value"
67
+ :class="[
68
+ $style.segment,
69
+ { [$style.activeSegment]: sidebarDensity === option.value },
70
+ ]"
71
+ >
72
+ <input
73
+ v-model="sidebarDensity"
74
+ type="radio"
75
+ name="sidebar-density"
76
+ :value="option.value"
77
+ />
78
+ <span>{{ option.label }}</span>
79
+ </label>
80
+ </div>
81
+ </div>
82
+
83
+ <div :class="$style.prefixGrid">
84
+ <label :class="$style.field">
85
+ <span :class="$style.controlLabel">已完成笔记的前缀</span>
86
+ <input
87
+ v-model="donePrefix"
88
+ type="text"
89
+ placeholder="可留空"
90
+ :class="[$style.input, $style.prefixInput]"
91
+ />
92
+ </label>
93
+
94
+ <label :class="$style.field">
95
+ <span :class="$style.controlLabel">未完成笔记前缀</span>
96
+ <input
97
+ v-model="undonePrefix"
98
+ type="text"
99
+ placeholder="可留空"
100
+ :class="[$style.input, $style.prefixInput]"
101
+ />
102
+ </label>
103
+ </div>
104
+ </div>
105
+ </div>
106
+
107
+ <div :class="$style.settingItem">
108
+ <div :class="$style.settingMeta">
109
+ <div :class="$style.labelLine">
110
+ <span :class="$style.itemName">MarkMap 思维导图</span>
111
+ <span :class="$style.infoWrap">
112
+ <span :class="$style.infoIcon">?</span>
113
+ <span :class="$style.tooltip">
114
+ 配置 MarkMap 的默认分支配色和初始展开层级。
115
+ </span>
116
+ </span>
117
+ </div>
118
+ </div>
119
+
120
+ <div :class="$style.inlineGrid">
121
+ <label :class="$style.field">
122
+ <span :class="$style.controlLabel">分支主题</span>
123
+ <select v-model="markmapTheme" :class="$style.select">
124
+ <option value="default">默认</option>
125
+ <option value="colorful">多彩</option>
126
+ <option value="dark">深色</option>
127
+ </select>
128
+ </label>
129
+
130
+ <label :class="$style.field">
131
+ <span :class="$style.controlLabel">展开层级</span>
132
+ <div :class="$style.inputWithUnit">
133
+ <input
134
+ v-model.number="markmapExpandLevel"
135
+ type="number"
136
+ min="1"
137
+ max="100"
138
+ :class="$style.input"
139
+ />
140
+ <span :class="$style.unit">层</span>
141
+ </div>
142
+ </label>
143
+ </div>
144
+ </div>
145
+ </section>
146
+
147
+ <div :class="$style.actionBar">
148
+ <button v-if="hasChanges" @click="reset" :class="$style.resetBtn">
149
+ 重置
150
+ </button>
151
+ <button
152
+ @click="save"
153
+ :class="[$style.saveBtn, { [$style.disabled]: !hasChanges }]"
154
+ :disabled="!hasChanges"
155
+ >
156
+ {{ saveText }}
157
+ </button>
158
+ </div>
159
+
160
+ <Transition name="toast">
161
+ <div v-if="showSuccessToast" :class="$style.toast">保存成功</div>
162
+ </Transition>
163
+ </div>
164
+ </template>
165
+
166
+ <script setup lang="ts">
155
167
  import { ref, computed, onMounted } from 'vue'
156
-
157
- import {
158
- NOTES_DIR_KEY,
159
- MARKMAP_THEME_KEY,
160
- MARKMAP_EXPAND_LEVEL_KEY,
161
- SIDEBAR_SHOW_NOTE_ID_KEY,
162
- } from '../constants'
163
- // @ts-expect-error - VitePress Data Loader
164
- import { data as tnotesConfig } from '../tnotes-config.data'
165
-
166
- const CONTENT_WIDTH_KEY = 'tnotes-content-width'
167
-
168
- // ===================================
169
- // #region 响应式数据
170
- // ===================================
171
- const path = ref('')
172
- const originalPath = ref('')
173
- const markmapTheme = ref('default')
174
- const originalMarkmapTheme = ref('default')
175
- const markmapExpandLevel = ref(5)
176
- const originalMarkmapExpandLevel = ref(5)
177
- const contentWidth = ref('688px')
178
- const showNoteId = ref(false)
179
- const originalShowNoteId = ref(false)
180
- const showSuccessToast = ref(false)
181
- // #endregion
182
-
183
- // ===================================
184
- // #region 计算属性
185
- // ===================================
186
- const hasChanges = computed(
187
- () =>
188
- path.value !== originalPath.value ||
189
- markmapTheme.value !== originalMarkmapTheme.value ||
190
- markmapExpandLevel.value !== originalMarkmapExpandLevel.value ||
191
- showNoteId.value !== originalShowNoteId.value
192
- )
193
-
194
- const saveText = computed(() => {
195
- if (!hasChanges.value) return '无更改'
196
- return '保存配置'
197
- })
198
- // #endregion
199
-
200
- // ===================================
201
- // #region 生命周期
202
- // ===================================
203
- onMounted(() => {
204
- if (typeof window !== 'undefined') {
205
- const savedPath = localStorage.getItem(NOTES_DIR_KEY) || ''
206
- path.value = savedPath
207
- originalPath.value = savedPath
208
-
209
- const savedTheme = localStorage.getItem(MARKMAP_THEME_KEY) || 'default'
210
- markmapTheme.value = savedTheme
211
- originalMarkmapTheme.value = savedTheme
212
-
213
- const savedLevel = localStorage.getItem(MARKMAP_EXPAND_LEVEL_KEY) || '5'
214
- markmapExpandLevel.value = parseInt(savedLevel)
215
- originalMarkmapExpandLevel.value = parseInt(savedLevel)
216
-
217
- const savedWidth = localStorage.getItem(CONTENT_WIDTH_KEY) || '688px'
218
- contentWidth.value = savedWidth
219
- applyContentWidth()
220
-
221
- // 读取侧边栏显示笔记 ID 配置
222
- // 优先使用 localStorage 中的用户自定义配置,否则使用配置文件中的默认值
223
- const savedShowNoteId = localStorage.getItem(SIDEBAR_SHOW_NOTE_ID_KEY)
224
- if (savedShowNoteId !== null) {
225
- showNoteId.value = savedShowNoteId === 'true'
226
- } else {
227
- showNoteId.value = tnotesConfig?.sidebarShowNoteId ?? false
228
- }
229
- originalShowNoteId.value = showNoteId.value
230
- }
231
- })
232
- // #endregion
233
-
234
- // ===================================
235
- // #region 事件处理
236
- // ===================================
237
- function handlePathChange() {
238
- // 可以在这里添加路径格式验证
239
- }
240
-
241
- function clearPath() {
242
- path.value = ''
243
- }
244
-
245
- function save() {
246
- if (!hasChanges.value) return
247
-
248
- try {
249
- // 保存前先记录是否需要刷新页面
250
- const needReload = showNoteId.value !== originalShowNoteId.value
251
-
252
- localStorage.setItem(NOTES_DIR_KEY, path.value)
253
- localStorage.setItem(MARKMAP_THEME_KEY, markmapTheme.value)
254
- localStorage.setItem(
255
- MARKMAP_EXPAND_LEVEL_KEY,
256
- markmapExpandLevel.value.toString()
257
- )
258
- localStorage.setItem(SIDEBAR_SHOW_NOTE_ID_KEY, showNoteId.value.toString())
259
-
260
- console.log('💾 [Settings] Saved showNoteId:', showNoteId.value)
261
-
262
- originalPath.value = path.value
263
- originalMarkmapTheme.value = markmapTheme.value
264
- originalMarkmapExpandLevel.value = markmapExpandLevel.value
265
- originalShowNoteId.value = showNoteId.value
266
-
267
- // 显示成功提示
268
- showSuccessToast.value = true
269
- setTimeout(() => {
270
- showSuccessToast.value = false
271
- }, 3000)
272
-
273
- // 触发页面刷新以应用侧边栏配置变化
274
- if (needReload) {
275
- console.log(
276
- '🔄 [Settings] Reloading page to apply sidebar config change...'
277
- )
278
- setTimeout(() => {
279
- window.location.reload()
280
- }, 500)
281
- }
282
- } catch (error) {
283
- console.error('保存配置失败:', error)
284
- alert('保存失败,请检查浏览器设置')
285
- }
286
- }
287
-
288
- function reset() {
289
- path.value = originalPath.value
290
- markmapTheme.value = originalMarkmapTheme.value
291
- markmapExpandLevel.value = originalMarkmapExpandLevel.value
292
- showNoteId.value = originalShowNoteId.value
293
- }
294
-
295
- // 应用内容宽度(通过 CSS 变量)
296
- function applyContentWidth() {
297
- if (typeof document === 'undefined') return
298
- document.documentElement.style.setProperty(
299
- '--tn-content-width',
300
- contentWidth.value
301
- )
302
- localStorage.setItem(CONTENT_WIDTH_KEY, contentWidth.value)
303
- }
304
- // #endregion
305
- </script>
306
-
307
- <style module src="./Settings.module.scss"></style>
168
+
169
+ import {
170
+ NOTES_DIR_KEY,
171
+ MARKMAP_THEME_KEY,
172
+ MARKMAP_EXPAND_LEVEL_KEY,
173
+ SIDEBAR_SHOW_NOTE_ID_KEY,
174
+ SIDEBAR_DENSITY_KEY,
175
+ SIDEBAR_DONE_PREFIX_KEY,
176
+ SIDEBAR_UNDONE_PREFIX_KEY,
177
+ } from '../constants'
178
+ // @ts-expect-error - VitePress Data Loader
179
+ import { data as tnotesConfig } from '../tnotes-config.data'
180
+
181
+ type SidebarDensity = 'compact' | 'default' | 'loose'
182
+
183
+ const DEFAULT_SIDEBAR_DENSITY: SidebarDensity = 'default'
184
+ const DEFAULT_DONE_PREFIX = ''
185
+ const DEFAULT_UNDONE_PREFIX = ''
186
+ const sidebarDensityOptions: Array<{
187
+ label: string
188
+ value: SidebarDensity
189
+ }> = [
190
+ { label: '紧凑', value: 'compact' },
191
+ { label: '默认', value: 'default' },
192
+ { label: '宽松', value: 'loose' },
193
+ ]
194
+
195
+ const path = ref('')
196
+ const originalPath = ref('')
197
+ const markmapTheme = ref('default')
198
+ const originalMarkmapTheme = ref('default')
199
+ const markmapExpandLevel = ref(5)
200
+ const originalMarkmapExpandLevel = ref(5)
201
+ const showNoteId = ref(false)
202
+ const originalShowNoteId = ref(false)
203
+ const sidebarDensity = ref<SidebarDensity>(DEFAULT_SIDEBAR_DENSITY)
204
+ const originalSidebarDensity = ref<SidebarDensity>(DEFAULT_SIDEBAR_DENSITY)
205
+ const donePrefix = ref(DEFAULT_DONE_PREFIX)
206
+ const originalDonePrefix = ref(DEFAULT_DONE_PREFIX)
207
+ const undonePrefix = ref(DEFAULT_UNDONE_PREFIX)
208
+ const originalUndonePrefix = ref(DEFAULT_UNDONE_PREFIX)
209
+ const showSuccessToast = ref(false)
210
+
211
+ const hasChanges = computed(
212
+ () =>
213
+ path.value !== originalPath.value ||
214
+ markmapTheme.value !== originalMarkmapTheme.value ||
215
+ markmapExpandLevel.value !== originalMarkmapExpandLevel.value ||
216
+ showNoteId.value !== originalShowNoteId.value ||
217
+ sidebarDensity.value !== originalSidebarDensity.value ||
218
+ donePrefix.value !== originalDonePrefix.value ||
219
+ undonePrefix.value !== originalUndonePrefix.value,
220
+ )
221
+
222
+ const saveText = computed(() => {
223
+ if (!hasChanges.value) return '无更改'
224
+ return '保存'
225
+ })
226
+
227
+ onMounted(() => {
228
+ if (typeof window === 'undefined') return
229
+
230
+ const savedPath = localStorage.getItem(NOTES_DIR_KEY) || ''
231
+ path.value = savedPath
232
+ originalPath.value = savedPath
233
+
234
+ const savedTheme = localStorage.getItem(MARKMAP_THEME_KEY) || 'default'
235
+ markmapTheme.value = savedTheme
236
+ originalMarkmapTheme.value = savedTheme
237
+
238
+ const savedLevel = localStorage.getItem(MARKMAP_EXPAND_LEVEL_KEY) || '5'
239
+ markmapExpandLevel.value = parseInt(savedLevel, 10)
240
+ originalMarkmapExpandLevel.value = markmapExpandLevel.value
241
+
242
+ const savedShowNoteId = localStorage.getItem(SIDEBAR_SHOW_NOTE_ID_KEY)
243
+ showNoteId.value =
244
+ savedShowNoteId !== null
245
+ ? savedShowNoteId === 'true'
246
+ : tnotesConfig?.sidebarShowNoteId ?? false
247
+ originalShowNoteId.value = showNoteId.value
248
+
249
+ const savedSidebarDensity = normalizeSidebarDensity(
250
+ localStorage.getItem(SIDEBAR_DENSITY_KEY),
251
+ )
252
+ sidebarDensity.value = savedSidebarDensity
253
+ originalSidebarDensity.value = savedSidebarDensity
254
+
255
+ const savedDonePrefix = localStorage.getItem(SIDEBAR_DONE_PREFIX_KEY)
256
+ donePrefix.value =
257
+ savedDonePrefix !== null ? savedDonePrefix : DEFAULT_DONE_PREFIX
258
+ originalDonePrefix.value = donePrefix.value
259
+
260
+ const savedUndonePrefix = localStorage.getItem(SIDEBAR_UNDONE_PREFIX_KEY)
261
+ undonePrefix.value =
262
+ savedUndonePrefix !== null ? savedUndonePrefix : DEFAULT_UNDONE_PREFIX
263
+ originalUndonePrefix.value = undonePrefix.value
264
+ })
265
+
266
+ function normalizeSidebarDensity(value: string | null): SidebarDensity {
267
+ if (value === 'compact' || value === 'default' || value === 'loose') {
268
+ return value
269
+ }
270
+
271
+ return DEFAULT_SIDEBAR_DENSITY
272
+ }
273
+
274
+ function clearPath() {
275
+ path.value = ''
276
+ }
277
+
278
+ function save() {
279
+ if (!hasChanges.value) return
280
+
281
+ try {
282
+ const needReload =
283
+ showNoteId.value !== originalShowNoteId.value ||
284
+ sidebarDensity.value !== originalSidebarDensity.value ||
285
+ donePrefix.value !== originalDonePrefix.value ||
286
+ undonePrefix.value !== originalUndonePrefix.value
287
+
288
+ localStorage.setItem(NOTES_DIR_KEY, path.value)
289
+ localStorage.setItem(MARKMAP_THEME_KEY, markmapTheme.value)
290
+ localStorage.setItem(
291
+ MARKMAP_EXPAND_LEVEL_KEY,
292
+ markmapExpandLevel.value.toString(),
293
+ )
294
+ localStorage.setItem(SIDEBAR_SHOW_NOTE_ID_KEY, showNoteId.value.toString())
295
+ localStorage.setItem(SIDEBAR_DENSITY_KEY, sidebarDensity.value)
296
+ localStorage.setItem(SIDEBAR_DONE_PREFIX_KEY, donePrefix.value)
297
+ localStorage.setItem(SIDEBAR_UNDONE_PREFIX_KEY, undonePrefix.value)
298
+
299
+ originalPath.value = path.value
300
+ originalMarkmapTheme.value = markmapTheme.value
301
+ originalMarkmapExpandLevel.value = markmapExpandLevel.value
302
+ originalShowNoteId.value = showNoteId.value
303
+ originalSidebarDensity.value = sidebarDensity.value
304
+ originalDonePrefix.value = donePrefix.value
305
+ originalUndonePrefix.value = undonePrefix.value
306
+
307
+ showSuccessToast.value = true
308
+ setTimeout(() => {
309
+ showSuccessToast.value = false
310
+ }, 2400)
311
+
312
+ if (needReload) {
313
+ setTimeout(() => {
314
+ window.location.reload()
315
+ }, 450)
316
+ }
317
+ } catch (error) {
318
+ console.error('保存配置失败:', error)
319
+ alert('保存失败,请检查浏览器设置')
320
+ }
321
+ }
322
+
323
+ function reset() {
324
+ path.value = originalPath.value
325
+ markmapTheme.value = originalMarkmapTheme.value
326
+ markmapExpandLevel.value = originalMarkmapExpandLevel.value
327
+ showNoteId.value = originalShowNoteId.value
328
+ sidebarDensity.value = originalSidebarDensity.value
329
+ donePrefix.value = originalDonePrefix.value
330
+ undonePrefix.value = originalUndonePrefix.value
331
+ }
332
+ </script>
333
+
334
+ <style module src="./Settings.module.scss"></style>