@tnotesjs/core 0.1.21 → 0.1.23

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 (122) hide show
  1. package/README.md +87 -87
  2. package/dist/{chunk-4MO7F7Q4.js → chunk-BSTQOJVE.js} +1 -1
  3. package/dist/{chunk-SQVHJR2Z.js → chunk-O4DCXHOV.js} +0 -3
  4. package/dist/cli/index.js +2 -2
  5. package/dist/index.js +1 -1
  6. package/dist/vitepress/config/index.js +2 -2
  7. package/package.json +3 -4
  8. package/types/config.ts +60 -61
  9. package/types/index.ts +11 -11
  10. package/types/note.ts +33 -33
  11. package/vitepress/assets/icons/icon__check.svg +3 -3
  12. package/vitepress/assets/icons/icon__clipboard.svg +7 -7
  13. package/vitepress/assets/icons/icon__close.svg +1 -1
  14. package/vitepress/assets/icons/icon__collapse.svg +1 -1
  15. package/vitepress/assets/icons/icon__confirm.svg +1 -1
  16. package/vitepress/assets/icons/icon__copy.svg +4 -4
  17. package/vitepress/assets/icons/icon__focus.svg +1 -1
  18. package/vitepress/assets/icons/icon__fold.svg +3 -3
  19. package/vitepress/assets/icons/icon__folder.svg +1 -1
  20. package/vitepress/assets/icons/icon__fullscreen.svg +1 -1
  21. package/vitepress/assets/icons/icon__fullscreen_exit.svg +1 -1
  22. package/vitepress/assets/icons/icon__github.svg +3 -3
  23. package/vitepress/assets/icons/icon__mindmap.svg +1 -1
  24. package/vitepress/assets/icons/icon__next.svg +1 -1
  25. package/vitepress/assets/icons/icon__number_gray.svg +1 -1
  26. package/vitepress/assets/icons/icon__number_purple.svg +1 -1
  27. package/vitepress/assets/icons/icon__prev.svg +1 -1
  28. package/vitepress/assets/icons/icon__restore.svg +1 -1
  29. package/vitepress/assets/icons/icon__rotate.svg +4 -4
  30. package/vitepress/assets/icons/icon__search.svg +1 -1
  31. package/vitepress/assets/icons/icon__sidebar_collapsed.svg +1 -1
  32. package/vitepress/assets/icons/icon__sidebar_opened.svg +1 -1
  33. package/vitepress/assets/icons/icon__totop.svg +5 -5
  34. package/vitepress/assets/icons/icon__vscode.svg +5 -5
  35. package/vitepress/assets/icons/icon__zoom_fit.svg +1 -1
  36. package/vitepress/assets/icons/icon__zoom_in.svg +1 -1
  37. package/vitepress/assets/icons/icon__zoom_out.svg +1 -1
  38. package/vitepress/assets/icons/icon__zoom_reset.svg +1 -1
  39. package/vitepress/assets/icons/index.ts +39 -39
  40. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +20 -20
  41. package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +369 -369
  42. package/vitepress/components/CodeBlockFullscreen/index.ts +209 -213
  43. package/vitepress/components/CodeBlockFullscreen/styles.css +126 -126
  44. package/vitepress/components/Discussions/Discussions.vue +244 -211
  45. package/vitepress/components/EnWordList/EnWordList.vue +663 -543
  46. package/vitepress/components/EnWordList/RightClickMenu.vue +89 -66
  47. package/vitepress/components/Footprints/Footprints.vue +472 -377
  48. package/vitepress/components/Layout/AboutModal.vue +331 -105
  49. package/vitepress/components/Layout/AboutPanel.vue +484 -270
  50. package/vitepress/components/Layout/ContentCollapse.vue +590 -603
  51. package/vitepress/components/Layout/CustomSidebar.vue +817 -817
  52. package/vitepress/components/Layout/DocBeforeControls.vue +351 -149
  53. package/vitepress/components/Layout/DocFooter.vue +233 -233
  54. package/vitepress/components/Layout/ImagePreview.vue +484 -281
  55. package/vitepress/components/Layout/Layout.vue +744 -621
  56. package/vitepress/components/Layout/NavBarSettingsTrigger.vue +0 -2
  57. package/vitepress/components/Layout/NoteStatus.vue +140 -140
  58. package/vitepress/components/Layout/SidebarItems.vue +1083 -1083
  59. package/vitepress/components/Layout/SidebarNavBefore.vue +170 -171
  60. package/vitepress/components/Layout/SidebarResizeHandle.vue +311 -319
  61. package/vitepress/components/Layout/Swiper.vue +167 -167
  62. package/vitepress/components/Layout/ToggleFullContent.vue +47 -35
  63. package/vitepress/components/Layout/ToggleSidebar.vue +37 -26
  64. package/vitepress/components/Layout/composables/useCollapseControl.ts +88 -88
  65. package/vitepress/components/Layout/composables/useNoteConfig.ts +119 -119
  66. package/vitepress/components/Layout/composables/useNoteSave.ts +178 -178
  67. package/vitepress/components/Layout/composables/useNoteValidation.ts +85 -85
  68. package/vitepress/components/Layout/composables/useRedirect.ts +113 -113
  69. package/vitepress/components/Layout/composables/useSidebarLayout.ts +122 -122
  70. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +85 -85
  71. package/vitepress/components/Layout/homeReadme.data.ts +124 -124
  72. package/vitepress/components/LoadingPage/LoadingPage.vue +1 -6
  73. package/vitepress/components/MarkMap/MarkMap.vue +564 -405
  74. package/vitepress/components/Mermaid/Mermaid.vue +643 -365
  75. package/vitepress/components/NotesTable/NotesTable.vue +174 -98
  76. package/vitepress/components/NotesTable/README.md +67 -67
  77. package/vitepress/components/Settings/Settings.vue +711 -334
  78. package/vitepress/components/Settings/SettingsDialog.vue +1 -11
  79. package/vitepress/components/SidebarCard/MindMapView.vue +484 -484
  80. package/vitepress/components/SidebarCard/NotesTrendChart.vue +108 -108
  81. package/vitepress/components/SidebarCard/SidebarCard.vue +945 -946
  82. package/vitepress/components/Tooltip/Tooltip.vue +70 -70
  83. package/vitepress/components/constants.ts +109 -109
  84. package/vitepress/components/notesConfig.data.ts +73 -73
  85. package/vitepress/components/sidebar.data.ts +59 -59
  86. package/vitepress/components/tnotes-config.data.ts +21 -21
  87. package/vitepress/components/utils.ts +26 -26
  88. package/vitepress/config/index.ts +169 -169
  89. package/vitepress/configs/constants.ts +26 -26
  90. package/vitepress/configs/head.config.ts +25 -25
  91. package/vitepress/configs/index.ts +9 -9
  92. package/vitepress/configs/markdown-it.d.ts +23 -23
  93. package/vitepress/configs/markdown.config.ts +368 -367
  94. package/vitepress/configs/theme.config.ts +108 -108
  95. package/vitepress/plugins/buildProgressPlugin.ts +434 -434
  96. package/vitepress/plugins/getNoteByConfigIdPlugin.ts +107 -107
  97. package/vitepress/plugins/renameNotePlugin.ts +68 -68
  98. package/vitepress/plugins/sidebarStructurePlugin.ts +260 -260
  99. package/vitepress/plugins/updateConfigPlugin.ts +63 -63
  100. package/vitepress/theme/index.ts +137 -137
  101. package/vitepress/theme/styles/base.scss +66 -64
  102. package/vitepress/theme/styles/components/404.scss +31 -31
  103. package/vitepress/theme/styles/components/collapse.scss +172 -172
  104. package/vitepress/theme/styles/components/markmap.scss +101 -101
  105. package/vitepress/theme/styles/components/swiper.scss +255 -255
  106. package/vitepress/theme/styles/index.scss +25 -25
  107. package/vitepress/theme/styles/layout.scss +78 -78
  108. package/vitepress/theme/styles/utilities.scss +39 -39
  109. package/vitepress/theme/styles/vitepress-override.scss +25 -25
  110. package/vitepress/components/Discussions/Discussions.module.scss +0 -32
  111. package/vitepress/components/EnWordList/EnWordList.module.scss +0 -124
  112. package/vitepress/components/EnWordList/RightClickMenu.module.scss +0 -22
  113. package/vitepress/components/Footprints/Footprints.module.scss +0 -93
  114. package/vitepress/components/Layout/AboutModal.module.scss +0 -233
  115. package/vitepress/components/Layout/ImagePreview.module.scss +0 -201
  116. package/vitepress/components/Layout/Layout.module.scss +0 -661
  117. package/vitepress/components/Layout/ToggleFullContent.module.scss +0 -11
  118. package/vitepress/components/Layout/ToggleSidebar.module.scss +0 -11
  119. package/vitepress/components/MarkMap/MarkMap.module.scss +0 -159
  120. package/vitepress/components/Mermaid/Mermaid.module.scss +0 -275
  121. package/vitepress/components/NotesTable/NotesTable.module.scss +0 -77
  122. package/vitepress/components/Settings/Settings.module.scss +0 -375
@@ -1,167 +1,167 @@
1
- <template></template>
2
-
3
- <script setup>
4
- import { useData, onContentUpdated } from 'vitepress'
5
- import { ref, onMounted, onBeforeUnmount } from 'vue'
6
-
7
- import 'swiper/css'
8
-
9
- const vpData = useData()
10
-
11
- const swiperInstances = ref([])
12
-
13
- const initSwiper = () => {
14
- // 先清理旧实例
15
- destroySwiper()
16
-
17
- // 只在客户端动态加载
18
- import('swiper').then(({ default: Swiper }) => {
19
- import('swiper/modules').then(({ Navigation, Pagination }) => {
20
- const wrappers = document.querySelectorAll('.tn-swiper')
21
- wrappers.forEach((wrap) => {
22
- const container = wrap.querySelector('.swiper-container')
23
- const tabsEl = wrap.querySelector('.tn-swiper-tabs')
24
- if (!container || !tabsEl) return
25
-
26
- const instance = new Swiper(container, {
27
- // loop: false,
28
- // TODO 可配置
29
- // effect: 'fade',
30
- speed: 0, // 禁用动画
31
- on: {
32
- slideChange: () => {
33
- updateActiveTab(wrap, instance.activeIndex)
34
- updateContainerHeight(container, instance.activeIndex)
35
- },
36
- // 在初始化时也设置一次高度
37
- afterInit: () => {
38
- setTimeout(() => {
39
- updateContainerHeight(container, instance.activeIndex)
40
- }, 0)
41
- },
42
- },
43
- })
44
-
45
- // 生成 tabs(文案来自 data-title;为空则为 'img')
46
- const slides = wrap.querySelectorAll('.swiper-slide')
47
- const isTnTabNavVisible = slides.length >= 2
48
- tabsEl.innerHTML = ''
49
-
50
- // 微调 tabs 容器样式
51
- if (isTnTabNavVisible) {
52
- tabsEl.style.padding = '0 0.8rem 0 3rem'
53
- } else {
54
- tabsEl.style.padding = '0 0.8rem'
55
- }
56
-
57
- // 左按钮 - 上一页
58
- if (isTnTabNavVisible) {
59
- const prevBtn = document.createElement('button')
60
- prevBtn.type = 'button'
61
- prevBtn.className = 'tn-tab-nav tn-tab-prev'
62
- prevBtn.textContent = '<'
63
- prevBtn.title = '上一页'
64
- prevBtn.addEventListener('click', () => {
65
- if (instance.activeIndex === 0) {
66
- // 到头 -> 跳到最后一张
67
- instance.slideTo(slides.length - 1)
68
- } else {
69
- instance.slidePrev()
70
- }
71
- setTimeout(() => {
72
- updateContainerHeight(container, instance.activeIndex)
73
- }, 0)
74
- })
75
- tabsEl.appendChild(prevBtn)
76
-
77
- const line = document.createElement('span')
78
- line.className = 'tn-tab-nav tab-tab-line'
79
- line.textContent = '/'
80
- tabsEl.appendChild(line)
81
- }
82
-
83
- slides.forEach((slide, i) => {
84
- const label = slide.getAttribute('data-title') || 'img'
85
- const btn = document.createElement('button')
86
- btn.type = 'button'
87
- btn.className = 'tn-tab' + (i === 0 ? ' active' : '')
88
- btn.textContent = label
89
- btn.addEventListener('click', () => {
90
- instance.slideTo(i)
91
- // 点击tab时更新高度
92
- setTimeout(() => {
93
- updateContainerHeight(container, i)
94
- }, 0)
95
- })
96
- tabsEl.appendChild(btn)
97
- })
98
-
99
- // 右按钮 - 下一页
100
- if (isTnTabNavVisible) {
101
- const nextBtn = document.createElement('button')
102
- nextBtn.type = 'button'
103
- nextBtn.className = 'tn-tab-nav tn-tab-next'
104
- nextBtn.textContent = '>'
105
- nextBtn.title = '下一页'
106
- nextBtn.addEventListener('click', () => {
107
- if (instance.activeIndex === slides.length - 1) {
108
- // 到头 -> 跳到第一张
109
- instance.slideTo(0)
110
- } else {
111
- instance.slideNext()
112
- }
113
- setTimeout(() => {
114
- updateContainerHeight(container, instance.activeIndex)
115
- }, 0)
116
- })
117
- tabsEl.appendChild(nextBtn)
118
- }
119
-
120
- swiperInstances.value.push(instance)
121
- })
122
- })
123
- })
124
- }
125
-
126
- function updateActiveTab(wrap, activeIndex) {
127
- const btns = wrap.querySelectorAll('.tn-swiper-tabs .tn-tab')
128
- btns.forEach((b, i) => b.classList.toggle('active', i === activeIndex))
129
- }
130
-
131
- // 新增函数:根据当前slide中的图片高度更新容器高度
132
- function updateContainerHeight(container, activeIndex) {
133
- const slides = container.querySelectorAll('.swiper-slide')
134
- if (slides[activeIndex]) {
135
- const img = slides[activeIndex].querySelector('img')
136
- if (img && img.complete) {
137
- // 如果图片已加载完成,直接设置高度
138
- container.style.height = img.offsetHeight + 'px'
139
- } else if (img) {
140
- // 如果图片未加载完成,等待加载完成后设置高度
141
- img.onload = () => {
142
- container.style.height = img.offsetHeight + 'px'
143
- }
144
- }
145
- }
146
- }
147
-
148
- function destroySwiper() {
149
- swiperInstances.value.forEach((inst) => {
150
- try {
151
- inst.destroy(true, true)
152
- } catch {}
153
- })
154
- swiperInstances.value = []
155
- }
156
-
157
- onBeforeUnmount(destroySwiper)
158
-
159
- onMounted(() => {
160
- initSwiper()
161
- })
162
-
163
- // 监听内容更新(包括 HMR 和路由变化)
164
- onContentUpdated(() => {
165
- initSwiper()
166
- })
167
- </script>
1
+ <template></template>
2
+
3
+ <script setup>
4
+ import { useData, onContentUpdated } from 'vitepress'
5
+ import { ref, onMounted, onBeforeUnmount } from 'vue'
6
+
7
+ import 'swiper/css'
8
+
9
+ const vpData = useData()
10
+
11
+ const swiperInstances = ref([])
12
+
13
+ const initSwiper = () => {
14
+ // 先清理旧实例
15
+ destroySwiper()
16
+
17
+ // 只在客户端动态加载
18
+ import('swiper').then(({ default: Swiper }) => {
19
+ import('swiper/modules').then(({ Navigation, Pagination }) => {
20
+ const wrappers = document.querySelectorAll('.tn-swiper')
21
+ wrappers.forEach((wrap) => {
22
+ const container = wrap.querySelector('.swiper-container')
23
+ const tabsEl = wrap.querySelector('.tn-swiper-tabs')
24
+ if (!container || !tabsEl) return
25
+
26
+ const instance = new Swiper(container, {
27
+ // loop: false,
28
+ // TODO 可配置
29
+ // effect: 'fade',
30
+ speed: 0, // 禁用动画
31
+ on: {
32
+ slideChange: () => {
33
+ updateActiveTab(wrap, instance.activeIndex)
34
+ updateContainerHeight(container, instance.activeIndex)
35
+ },
36
+ // 在初始化时也设置一次高度
37
+ afterInit: () => {
38
+ setTimeout(() => {
39
+ updateContainerHeight(container, instance.activeIndex)
40
+ }, 0)
41
+ },
42
+ },
43
+ })
44
+
45
+ // 生成 tabs(文案来自 data-title;为空则为 'img')
46
+ const slides = wrap.querySelectorAll('.swiper-slide')
47
+ const isTnTabNavVisible = slides.length >= 2
48
+ tabsEl.innerHTML = ''
49
+
50
+ // 微调 tabs 容器样式
51
+ if (isTnTabNavVisible) {
52
+ tabsEl.style.padding = '0 0.8rem 0 3rem'
53
+ } else {
54
+ tabsEl.style.padding = '0 0.8rem'
55
+ }
56
+
57
+ // 左按钮 - 上一页
58
+ if (isTnTabNavVisible) {
59
+ const prevBtn = document.createElement('button')
60
+ prevBtn.type = 'button'
61
+ prevBtn.className = 'tn-tab-nav tn-tab-prev'
62
+ prevBtn.textContent = '<'
63
+ prevBtn.title = '上一页'
64
+ prevBtn.addEventListener('click', () => {
65
+ if (instance.activeIndex === 0) {
66
+ // 到头 -> 跳到最后一张
67
+ instance.slideTo(slides.length - 1)
68
+ } else {
69
+ instance.slidePrev()
70
+ }
71
+ setTimeout(() => {
72
+ updateContainerHeight(container, instance.activeIndex)
73
+ }, 0)
74
+ })
75
+ tabsEl.appendChild(prevBtn)
76
+
77
+ const line = document.createElement('span')
78
+ line.className = 'tn-tab-nav tab-tab-line'
79
+ line.textContent = '/'
80
+ tabsEl.appendChild(line)
81
+ }
82
+
83
+ slides.forEach((slide, i) => {
84
+ const label = slide.getAttribute('data-title') || 'img'
85
+ const btn = document.createElement('button')
86
+ btn.type = 'button'
87
+ btn.className = 'tn-tab' + (i === 0 ? ' active' : '')
88
+ btn.textContent = label
89
+ btn.addEventListener('click', () => {
90
+ instance.slideTo(i)
91
+ // 点击tab时更新高度
92
+ setTimeout(() => {
93
+ updateContainerHeight(container, i)
94
+ }, 0)
95
+ })
96
+ tabsEl.appendChild(btn)
97
+ })
98
+
99
+ // 右按钮 - 下一页
100
+ if (isTnTabNavVisible) {
101
+ const nextBtn = document.createElement('button')
102
+ nextBtn.type = 'button'
103
+ nextBtn.className = 'tn-tab-nav tn-tab-next'
104
+ nextBtn.textContent = '>'
105
+ nextBtn.title = '下一页'
106
+ nextBtn.addEventListener('click', () => {
107
+ if (instance.activeIndex === slides.length - 1) {
108
+ // 到头 -> 跳到第一张
109
+ instance.slideTo(0)
110
+ } else {
111
+ instance.slideNext()
112
+ }
113
+ setTimeout(() => {
114
+ updateContainerHeight(container, instance.activeIndex)
115
+ }, 0)
116
+ })
117
+ tabsEl.appendChild(nextBtn)
118
+ }
119
+
120
+ swiperInstances.value.push(instance)
121
+ })
122
+ })
123
+ })
124
+ }
125
+
126
+ function updateActiveTab(wrap, activeIndex) {
127
+ const btns = wrap.querySelectorAll('.tn-swiper-tabs .tn-tab')
128
+ btns.forEach((b, i) => b.classList.toggle('active', i === activeIndex))
129
+ }
130
+
131
+ // 新增函数:根据当前slide中的图片高度更新容器高度
132
+ function updateContainerHeight(container, activeIndex) {
133
+ const slides = container.querySelectorAll('.swiper-slide')
134
+ if (slides[activeIndex]) {
135
+ const img = slides[activeIndex].querySelector('img')
136
+ if (img && img.complete) {
137
+ // 如果图片已加载完成,直接设置高度
138
+ container.style.height = img.offsetHeight + 'px'
139
+ } else if (img) {
140
+ // 如果图片未加载完成,等待加载完成后设置高度
141
+ img.onload = () => {
142
+ container.style.height = img.offsetHeight + 'px'
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ function destroySwiper() {
149
+ swiperInstances.value.forEach((inst) => {
150
+ try {
151
+ inst.destroy(true, true)
152
+ } catch {}
153
+ })
154
+ swiperInstances.value = []
155
+ }
156
+
157
+ onBeforeUnmount(destroySwiper)
158
+
159
+ onMounted(() => {
160
+ initSwiper()
161
+ })
162
+
163
+ // 监听内容更新(包括 HMR 和路由变化)
164
+ onContentUpdated(() => {
165
+ initSwiper()
166
+ })
167
+ </script>
@@ -1,35 +1,47 @@
1
- <template>
2
- <img @click="toggle" :class="$style.contentToggleBtn" :aria-pressed="full" :title="full ? '退出全屏内容区' : '全屏显示内容区'" :src="full ? icon__fullscreen_exit : icon__fullscreen" alt="" />
3
- </template>
4
-
5
- <script setup lang="ts">
6
- import { onMounted, ref } from 'vue'
7
-
8
- import { icon__fullscreen, icon__fullscreen_exit } from '../../assets/icons'
9
-
10
- const KEY = 'vp:content:fullscreen'
11
- const full = ref(false)
12
-
13
- onMounted(() => {
14
- try {
15
- full.value = localStorage.getItem(KEY) === '1'
16
- } catch {}
17
- apply(full.value)
18
- })
19
-
20
- function apply(val: boolean) {
21
- const root = document.documentElement
22
- if (val) root.classList.add('content-fullscreen')
23
- else root.classList.remove('content-fullscreen')
24
- }
25
-
26
- function toggle() {
27
- full.value = !full.value
28
- apply(full.value)
29
- try {
30
- localStorage.setItem(KEY, full.value ? '1' : '0')
31
- } catch {}
32
- }
33
- </script>
34
-
35
- <style module src="./ToggleFullContent.module.scss"></style>
1
+ <template>
2
+ <img @click="toggle" class="contentToggleBtn" :title="full ? '退出全屏内容区' : '全屏显示内容区'" :src="full ? icon__fullscreen_exit : icon__fullscreen" alt="" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { onMounted, ref } from 'vue'
7
+
8
+ import { icon__fullscreen, icon__fullscreen_exit } from '../../assets/icons'
9
+
10
+ const KEY = 'vp:content:fullscreen'
11
+ const full = ref(false)
12
+
13
+ onMounted(() => {
14
+ try {
15
+ full.value = localStorage.getItem(KEY) === '1'
16
+ } catch {}
17
+ apply(full.value)
18
+ })
19
+
20
+ function apply(val: boolean) {
21
+ const root = document.documentElement
22
+ if (val) root.classList.add('content-fullscreen')
23
+ else root.classList.remove('content-fullscreen')
24
+ }
25
+
26
+ function toggle() {
27
+ full.value = !full.value
28
+ apply(full.value)
29
+ try {
30
+ localStorage.setItem(KEY, full.value ? '1' : '0')
31
+ } catch {}
32
+ }
33
+ </script>
34
+
35
+ <style scoped lang="scss">
36
+ .contentToggleBtn {
37
+ width: 1.5rem;
38
+ height: 1.5rem;
39
+ padding: 3px;
40
+ cursor: pointer;
41
+ transition: all 0.2s;
42
+
43
+ &:hover {
44
+ background: var(--vp-c-bg-alt);
45
+ }
46
+ }
47
+ </style>
@@ -1,26 +1,37 @@
1
- <!-- .vitepress\components\Layout\ToggleSidebar.vue -->
2
- <template>
3
- <img
4
- @click="toggleSidebar"
5
- :class="$style.sidebarToggleBtn"
6
- :aria-pressed="hidden"
7
- :title="hidden ? '显示侧边栏' : '隐藏侧边栏'"
8
- :src="hidden ? icon__next : icon__prev"
9
- alt=""
10
- />
11
- </template>
12
-
13
- <script setup lang="ts">
14
- import { onMounted } from 'vue'
15
-
16
- import { useSidebarLayout } from './composables/useSidebarLayout'
17
- import { icon__next, icon__prev } from '../../assets/icons'
18
-
19
- const { hidden, initSidebarLayout, toggleSidebar } = useSidebarLayout()
20
-
21
- onMounted(() => {
22
- initSidebarLayout()
23
- })
24
- </script>
25
-
26
- <style module src="./ToggleSidebar.module.scss"></style>
1
+ <!-- .vitepress\components\Layout\ToggleSidebar.vue -->
2
+ <template>
3
+ <img
4
+ @click="toggleSidebar"
5
+ class="sidebarToggleBtn"
6
+ :title="hidden ? '显示侧边栏' : '隐藏侧边栏'"
7
+ :src="hidden ? icon__next : icon__prev"
8
+ alt=""
9
+ />
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { onMounted } from 'vue'
14
+
15
+ import { useSidebarLayout } from './composables/useSidebarLayout'
16
+ import { icon__next, icon__prev } from '../../assets/icons'
17
+
18
+ const { hidden, initSidebarLayout, toggleSidebar } = useSidebarLayout()
19
+
20
+ onMounted(() => {
21
+ initSidebarLayout()
22
+ })
23
+ </script>
24
+
25
+ <style scoped lang="scss">
26
+ .sidebarToggleBtn {
27
+ width: 1.5rem;
28
+ height: 1.5rem;
29
+ padding: 3px;
30
+ cursor: pointer;
31
+ transition: all 0.2s;
32
+
33
+ &:hover {
34
+ background: var(--vp-c-bg-alt);
35
+ }
36
+ }
37
+ </style>
@@ -1,88 +1,88 @@
1
- import { useRoute } from 'vitepress'
2
- import { ref, watch } from 'vue'
3
-
4
- /**
5
- * 全局折叠/展开功能
6
- */
7
- export function useCollapseControl() {
8
- const route = useRoute()
9
- const allCollapsed = ref(false)
10
-
11
- function toggleAllCollapse() {
12
- if (typeof document === 'undefined') return
13
-
14
- allCollapsed.value = !allCollapsed.value
15
-
16
- // 获取所有折叠区域
17
- const tocHeaders = document.querySelectorAll('.toc-collapse-header')
18
- const h2Elements = document.querySelectorAll('.vp-doc h2.collapsible-h2')
19
-
20
- // 切换 TOC 区域
21
- tocHeaders.forEach((header) => {
22
- const content = header.nextElementSibling
23
- if (!content) return
24
-
25
- const isCollapsed = content.classList.contains('collapsed')
26
-
27
- // 根据目标状态决定是否需要切换
28
- if (allCollapsed.value && !isCollapsed) {
29
- // 需要折叠 - 直接操作 DOM
30
- content.classList.add('collapsed')
31
- header.classList.add('collapsed')
32
- // 保存状态到 localStorage
33
- const noteKey = route.path.replace(/\//g, '_')
34
- const storageKey = `tnotes_collapse_state_${noteKey}_toc`
35
- localStorage.setItem(storageKey, '1')
36
- } else if (!allCollapsed.value && isCollapsed) {
37
- // 需要展开 - 直接操作 DOM
38
- content.classList.remove('collapsed')
39
- header.classList.remove('collapsed')
40
- // 保存状态到 localStorage
41
- const noteKey = route.path.replace(/\//g, '_')
42
- const storageKey = `tnotes_collapse_state_${noteKey}_toc`
43
- localStorage.setItem(storageKey, '0')
44
- }
45
- })
46
-
47
- // 切换 H2 区域
48
- h2Elements.forEach((h2) => {
49
- const content = h2.nextElementSibling
50
- if (!content || !content.classList.contains('h2-collapse-content')) return
51
-
52
- const isCollapsed = content.classList.contains('collapsed')
53
- const h2Id = h2.id || `h2_${Array.from(h2Elements).indexOf(h2)}`
54
-
55
- // 根据目标状态决定是否需要切换
56
- if (allCollapsed.value && !isCollapsed) {
57
- // 需要折叠 - 直接操作 DOM
58
- content.classList.add('collapsed')
59
- h2.classList.add('collapsed')
60
- // 保存状态到 localStorage
61
- const noteKey = route.path.replace(/\//g, '_')
62
- const storageKey = `tnotes_collapse_state_${noteKey}_h2_${h2Id}`
63
- localStorage.setItem(storageKey, '1')
64
- } else if (!allCollapsed.value && isCollapsed) {
65
- // 需要展开 - 直接操作 DOM
66
- content.classList.remove('collapsed')
67
- h2.classList.remove('collapsed')
68
- // 保存状态到 localStorage
69
- const noteKey = route.path.replace(/\//g, '_')
70
- const storageKey = `tnotes_collapse_state_${noteKey}_h2_${h2Id}`
71
- localStorage.setItem(storageKey, '0')
72
- }
73
- })
74
- }
75
-
76
- // 监听路由变化,重置折叠状态
77
- watch(
78
- () => route.path,
79
- () => {
80
- allCollapsed.value = false
81
- }
82
- )
83
-
84
- return {
85
- allCollapsed,
86
- toggleAllCollapse,
87
- }
88
- }
1
+ import { useRoute } from 'vitepress'
2
+ import { ref, watch } from 'vue'
3
+
4
+ /**
5
+ * 全局折叠/展开功能
6
+ */
7
+ export function useCollapseControl() {
8
+ const route = useRoute()
9
+ const allCollapsed = ref(false)
10
+
11
+ function toggleAllCollapse() {
12
+ if (typeof document === 'undefined') return
13
+
14
+ allCollapsed.value = !allCollapsed.value
15
+
16
+ // 获取所有折叠区域
17
+ const tocHeaders = document.querySelectorAll('.toc-collapse-header')
18
+ const h2Elements = document.querySelectorAll('.vp-doc h2.collapsible-h2')
19
+
20
+ // 切换 TOC 区域
21
+ tocHeaders.forEach((header) => {
22
+ const content = header.nextElementSibling
23
+ if (!content) return
24
+
25
+ const isCollapsed = content.classList.contains('collapsed')
26
+
27
+ // 根据目标状态决定是否需要切换
28
+ if (allCollapsed.value && !isCollapsed) {
29
+ // 需要折叠 - 直接操作 DOM
30
+ content.classList.add('collapsed')
31
+ header.classList.add('collapsed')
32
+ // 保存状态到 localStorage
33
+ const noteKey = route.path.replace(/\//g, '_')
34
+ const storageKey = `tnotes_collapse_state_${noteKey}_toc`
35
+ localStorage.setItem(storageKey, '1')
36
+ } else if (!allCollapsed.value && isCollapsed) {
37
+ // 需要展开 - 直接操作 DOM
38
+ content.classList.remove('collapsed')
39
+ header.classList.remove('collapsed')
40
+ // 保存状态到 localStorage
41
+ const noteKey = route.path.replace(/\//g, '_')
42
+ const storageKey = `tnotes_collapse_state_${noteKey}_toc`
43
+ localStorage.setItem(storageKey, '0')
44
+ }
45
+ })
46
+
47
+ // 切换 H2 区域
48
+ h2Elements.forEach((h2) => {
49
+ const content = h2.nextElementSibling
50
+ if (!content || !content.classList.contains('h2-collapse-content')) return
51
+
52
+ const isCollapsed = content.classList.contains('collapsed')
53
+ const h2Id = h2.id || `h2_${Array.from(h2Elements).indexOf(h2)}`
54
+
55
+ // 根据目标状态决定是否需要切换
56
+ if (allCollapsed.value && !isCollapsed) {
57
+ // 需要折叠 - 直接操作 DOM
58
+ content.classList.add('collapsed')
59
+ h2.classList.add('collapsed')
60
+ // 保存状态到 localStorage
61
+ const noteKey = route.path.replace(/\//g, '_')
62
+ const storageKey = `tnotes_collapse_state_${noteKey}_h2_${h2Id}`
63
+ localStorage.setItem(storageKey, '1')
64
+ } else if (!allCollapsed.value && isCollapsed) {
65
+ // 需要展开 - 直接操作 DOM
66
+ content.classList.remove('collapsed')
67
+ h2.classList.remove('collapsed')
68
+ // 保存状态到 localStorage
69
+ const noteKey = route.path.replace(/\//g, '_')
70
+ const storageKey = `tnotes_collapse_state_${noteKey}_h2_${h2Id}`
71
+ localStorage.setItem(storageKey, '0')
72
+ }
73
+ })
74
+ }
75
+
76
+ // 监听路由变化,重置折叠状态
77
+ watch(
78
+ () => route.path,
79
+ () => {
80
+ allCollapsed.value = false
81
+ }
82
+ )
83
+
84
+ return {
85
+ allCollapsed,
86
+ toggleAllCollapse,
87
+ }
88
+ }