@tnotesjs/core 0.0.6 → 0.0.8

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 (116) hide show
  1. package/README.md +87 -84
  2. package/dist/{chunk-JDVN2QYW.js → chunk-JUMVJKWV.js} +615 -614
  3. package/dist/cli/index.js +125 -125
  4. package/dist/vitepress/config/index.js +184 -210
  5. package/package.json +15 -3
  6. package/types/config.ts +61 -61
  7. package/types/index.ts +11 -11
  8. package/types/note.ts +33 -33
  9. package/types/shims.d.ts +3 -4
  10. package/vitepress/assets/icons/icon__check.svg +3 -3
  11. package/vitepress/assets/icons/icon__clipboard.svg +7 -7
  12. package/vitepress/assets/icons/icon__close.svg +1 -1
  13. package/vitepress/assets/icons/icon__collapse.svg +1 -1
  14. package/vitepress/assets/icons/icon__confirm.svg +1 -1
  15. package/vitepress/assets/icons/icon__copy.svg +4 -4
  16. package/vitepress/assets/icons/icon__focus.svg +1 -1
  17. package/vitepress/assets/icons/icon__fold.svg +3 -3
  18. package/vitepress/assets/icons/icon__folder.svg +1 -1
  19. package/vitepress/assets/icons/icon__fullscreen.svg +1 -1
  20. package/vitepress/assets/icons/icon__fullscreen_exit.svg +1 -1
  21. package/vitepress/assets/icons/icon__github.svg +3 -3
  22. package/vitepress/assets/icons/icon__mindmap.svg +1 -1
  23. package/vitepress/assets/icons/icon__next.svg +1 -1
  24. package/vitepress/assets/icons/icon__number_gray.svg +1 -1
  25. package/vitepress/assets/icons/icon__number_purple.svg +1 -1
  26. package/vitepress/assets/icons/icon__prev.svg +1 -1
  27. package/vitepress/assets/icons/icon__restore.svg +1 -1
  28. package/vitepress/assets/icons/icon__rotate.svg +4 -4
  29. package/vitepress/assets/icons/icon__search.svg +1 -1
  30. package/vitepress/assets/icons/icon__sidebar_collapsed.svg +1 -1
  31. package/vitepress/assets/icons/icon__sidebar_opened.svg +1 -1
  32. package/vitepress/assets/icons/icon__totop.svg +5 -5
  33. package/vitepress/assets/icons/icon__vscode.svg +5 -5
  34. package/vitepress/assets/icons/icon__zoom_fit.svg +1 -1
  35. package/vitepress/assets/icons/icon__zoom_in.svg +1 -1
  36. package/vitepress/assets/icons/icon__zoom_out.svg +1 -1
  37. package/vitepress/assets/icons/icon__zoom_reset.svg +1 -1
  38. package/vitepress/assets/icons/index.ts +38 -38
  39. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +20 -20
  40. package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +373 -372
  41. package/vitepress/components/CodeBlockFullscreen/index.ts +115 -114
  42. package/vitepress/components/CodeBlockFullscreen/styles.css +64 -64
  43. package/vitepress/components/Discussions/Discussions.module.scss +32 -32
  44. package/vitepress/components/Discussions/Discussions.vue +211 -210
  45. package/vitepress/components/EnWordList/EnWordList.module.scss +124 -124
  46. package/vitepress/components/EnWordList/EnWordList.vue +543 -542
  47. package/vitepress/components/EnWordList/RightClickMenu.module.scss +22 -22
  48. package/vitepress/components/EnWordList/RightClickMenu.vue +66 -66
  49. package/vitepress/components/Footprints/Footprints.module.scss +93 -93
  50. package/vitepress/components/Footprints/Footprints.vue +377 -377
  51. package/vitepress/components/Layout/AboutModal.module.scss +233 -233
  52. package/vitepress/components/Layout/AboutModal.vue +105 -105
  53. package/vitepress/components/Layout/AboutPanel.vue +270 -265
  54. package/vitepress/components/Layout/ContentCollapse.vue +603 -602
  55. package/vitepress/components/Layout/CustomSidebar.vue +608 -605
  56. package/vitepress/components/Layout/DocBeforeControls.vue +149 -139
  57. package/vitepress/components/Layout/DocFooter.vue +233 -232
  58. package/vitepress/components/Layout/ImagePreview.module.scss +201 -201
  59. package/vitepress/components/Layout/ImagePreview.vue +281 -280
  60. package/vitepress/components/Layout/Layout.module.scss +661 -661
  61. package/vitepress/components/Layout/Layout.vue +539 -542
  62. package/vitepress/components/Layout/NoteStatus.vue +140 -139
  63. package/vitepress/components/Layout/SidebarItems.vue +267 -262
  64. package/vitepress/components/Layout/SidebarNavBefore.vue +92 -92
  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 -34
  68. package/vitepress/components/Layout/ToggleSidebar.module.scss +11 -11
  69. package/vitepress/components/Layout/ToggleSidebar.vue +36 -35
  70. package/vitepress/components/Layout/composables/useCollapseControl.ts +88 -88
  71. package/vitepress/components/Layout/composables/useNoteConfig.ts +119 -121
  72. package/vitepress/components/Layout/composables/useNoteSave.ts +173 -172
  73. package/vitepress/components/Layout/composables/useNoteValidation.ts +85 -85
  74. package/vitepress/components/Layout/composables/useRedirect.ts +113 -110
  75. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +86 -83
  76. package/vitepress/components/Layout/homeReadme.data.ts +124 -124
  77. package/vitepress/components/LoadingPage/LoadingPage.vue +192 -192
  78. package/vitepress/components/MarkMap/MarkMap.module.scss +159 -159
  79. package/vitepress/components/MarkMap/MarkMap.vue +405 -404
  80. package/vitepress/components/Mermaid/Mermaid.module.scss +275 -275
  81. package/vitepress/components/Mermaid/Mermaid.vue +365 -363
  82. package/vitepress/components/NotesTable/NotesTable.module.scss +77 -77
  83. package/vitepress/components/NotesTable/NotesTable.vue +98 -97
  84. package/vitepress/components/NotesTable/README.md +67 -67
  85. package/vitepress/components/Settings/Settings.module.scss +433 -433
  86. package/vitepress/components/Settings/Settings.vue +306 -305
  87. package/vitepress/components/SidebarCard/MindMapView.vue +484 -483
  88. package/vitepress/components/SidebarCard/NotesTrendChart.vue +108 -108
  89. package/vitepress/components/SidebarCard/SidebarCard.vue +946 -948
  90. package/vitepress/components/Tooltip/Tooltip.vue +70 -70
  91. package/vitepress/components/constants.ts +91 -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 +160 -146
  97. package/vitepress/configs/constants.ts +26 -26
  98. package/vitepress/configs/head.config.ts +25 -24
  99. package/vitepress/configs/index.ts +9 -9
  100. package/vitepress/configs/markdown-it.d.ts +23 -20
  101. package/vitepress/configs/markdown.config.ts +366 -365
  102. package/vitepress/configs/theme.config.ts +108 -108
  103. package/vitepress/plugins/buildProgressPlugin.ts +434 -470
  104. package/vitepress/plugins/getNoteByConfigIdPlugin.ts +107 -106
  105. package/vitepress/plugins/renameNotePlugin.ts +60 -59
  106. package/vitepress/plugins/updateConfigPlugin.ts +63 -62
  107. package/vitepress/theme/index.ts +95 -93
  108. package/vitepress/theme/styles/base.scss +50 -50
  109. package/vitepress/theme/styles/components/404.scss +31 -31
  110. package/vitepress/theme/styles/components/collapse.scss +175 -175
  111. package/vitepress/theme/styles/components/markmap.scss +101 -101
  112. package/vitepress/theme/styles/components/swiper.scss +255 -255
  113. package/vitepress/theme/styles/index.scss +25 -25
  114. package/vitepress/theme/styles/layout.scss +62 -62
  115. package/vitepress/theme/styles/utilities.scss +39 -39
  116. package/vitepress/theme/styles/vitepress-override.scss +25 -25
@@ -1,92 +1,92 @@
1
- <template>
2
- <div class="sidebar-toggle-wrapper">
3
- <!-- 笔记编号显示切换按钮 -->
4
- <button
5
- class="toggle-btn"
6
- @click="$emit('toggle-note-id')"
7
- :title="showNoteId ? '隐藏笔记编号' : '显示笔记编号'"
8
- >
9
- <img
10
- :src="showNoteId ? icon__number_purple : icon__number_gray"
11
- class="toggle-icon"
12
- alt="切换笔记编号"
13
- />
14
- </button>
15
-
16
- <!-- 展开/折叠全部按钮 -->
17
- <button
18
- class="toggle-btn"
19
- @click="$emit('toggle-expand')"
20
- :title="isExpanded ? '全部折叠' : '全部展开'"
21
- >
22
- <img :src="icon__fold" class="toggle-icon" alt="切换展开折叠" />
23
- </button>
24
-
25
- <!-- 聚焦到当前笔记按钮 -->
26
- <button
27
- class="toggle-btn"
28
- @click="$emit('focus-current')"
29
- title="聚焦到当前笔记(点击切换多个位置)"
30
- >
31
- <img :src="icon__focus" class="toggle-icon" alt="聚焦当前笔记" />
32
- </button>
33
- </div>
34
- </template>
35
-
36
- <script setup lang="ts">
37
- import { icon__fold, icon__number_purple, icon__number_gray, icon__focus } from '../../assets/icons'
38
-
39
- defineProps<{
40
- isExpanded: boolean
41
- showNoteId: boolean
42
- }>()
43
-
44
- defineEmits<{
45
- 'toggle-expand': []
46
- 'toggle-note-id': []
47
- 'focus-current': []
48
- }>()
49
- </script>
50
-
51
- <style scoped>
52
- .sidebar-toggle-wrapper {
53
- display: flex;
54
- align-items: center;
55
- justify-content: center;
56
- gap: 8px;
57
- padding: 12px 0 16px 0;
58
- border-bottom: 1px solid var(--vp-c-divider);
59
- margin-bottom: 16px;
60
- }
61
-
62
- .toggle-btn {
63
- display: inline-flex;
64
- align-items: center;
65
- justify-content: center;
66
- padding: 8px;
67
- cursor: pointer;
68
- background: transparent;
69
- border: none;
70
- border-radius: 6px;
71
- transition: all 0.2s ease;
72
- }
73
-
74
- .toggle-btn:hover {
75
- background: var(--vp-c-bg-soft);
76
- }
77
-
78
- .toggle-btn:active .toggle-icon {
79
- transform: scale(0.95);
80
- }
81
-
82
- .toggle-icon {
83
- width: 20px;
84
- height: 20px;
85
- display: block;
86
- transition: transform 0.2s ease;
87
- }
88
-
89
- .toggle-btn:hover .toggle-icon {
90
- transform: scale(1.1);
91
- }
92
- </style>
1
+ <template>
2
+ <div class="sidebar-toggle-wrapper">
3
+ <!-- 笔记编号显示切换按钮 -->
4
+ <button
5
+ class="toggle-btn"
6
+ @click="$emit('toggle-note-id')"
7
+ :title="showNoteId ? '隐藏笔记编号' : '显示笔记编号'"
8
+ >
9
+ <img
10
+ :src="showNoteId ? icon__number_purple : icon__number_gray"
11
+ class="toggle-icon"
12
+ alt="切换笔记编号"
13
+ />
14
+ </button>
15
+
16
+ <!-- 展开/折叠全部按钮 -->
17
+ <button
18
+ class="toggle-btn"
19
+ @click="$emit('toggle-expand')"
20
+ :title="isExpanded ? '全部折叠' : '全部展开'"
21
+ >
22
+ <img :src="icon__fold" class="toggle-icon" alt="切换展开折叠" />
23
+ </button>
24
+
25
+ <!-- 聚焦到当前笔记按钮 -->
26
+ <button
27
+ class="toggle-btn"
28
+ @click="$emit('focus-current')"
29
+ title="聚焦到当前笔记(点击切换多个位置)"
30
+ >
31
+ <img :src="icon__focus" class="toggle-icon" alt="聚焦当前笔记" />
32
+ </button>
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { icon__fold, icon__number_purple, icon__number_gray, icon__focus } from '../../assets/icons'
38
+
39
+ defineProps<{
40
+ isExpanded: boolean
41
+ showNoteId: boolean
42
+ }>()
43
+
44
+ defineEmits<{
45
+ 'toggle-expand': []
46
+ 'toggle-note-id': []
47
+ 'focus-current': []
48
+ }>()
49
+ </script>
50
+
51
+ <style scoped>
52
+ .sidebar-toggle-wrapper {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ gap: 8px;
57
+ padding: 12px 0 16px 0;
58
+ border-bottom: 1px solid var(--vp-c-divider);
59
+ margin-bottom: 16px;
60
+ }
61
+
62
+ .toggle-btn {
63
+ display: inline-flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ padding: 8px;
67
+ cursor: pointer;
68
+ background: transparent;
69
+ border: none;
70
+ border-radius: 6px;
71
+ transition: all 0.2s ease;
72
+ }
73
+
74
+ .toggle-btn:hover {
75
+ background: var(--vp-c-bg-soft);
76
+ }
77
+
78
+ .toggle-btn:active .toggle-icon {
79
+ transform: scale(0.95);
80
+ }
81
+
82
+ .toggle-icon {
83
+ width: 20px;
84
+ height: 20px;
85
+ display: block;
86
+ transition: transform 0.2s ease;
87
+ }
88
+
89
+ .toggle-btn:hover .toggle-icon {
90
+ transform: scale(1.1);
91
+ }
92
+ </style>
@@ -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,11 +1,11 @@
1
- .contentToggleBtn {
2
- width: 1.5rem;
3
- height: 1.5rem;
4
- padding: 3px;
5
- cursor: pointer;
6
- transition: all 0.2s;
7
-
8
- &:hover {
9
- background: var(--vp-c-bg-alt);
10
- }
11
- }
1
+ .contentToggleBtn {
2
+ width: 1.5rem;
3
+ height: 1.5rem;
4
+ padding: 3px;
5
+ cursor: pointer;
6
+ transition: all 0.2s;
7
+
8
+ &:hover {
9
+ background: var(--vp-c-bg-alt);
10
+ }
11
+ }
@@ -1,34 +1,35 @@
1
- <template>
2
- <img @click="toggle" :class="$style.contentToggleBtn" :aria-pressed="full.toString()" :title="full ? '退出全屏内容区' : '全屏显示内容区'" :src="full ? icon__fullscreen_exit : icon__fullscreen" alt=""></img>
3
- </template>
4
-
5
- <script setup lang="ts">
6
- import { onMounted, ref } from 'vue'
7
- import { icon__fullscreen, icon__fullscreen_exit } from '../../assets/icons'
8
-
9
- const KEY = 'vp:content:fullscreen'
10
- const full = ref(false)
11
-
12
- onMounted(() => {
13
- try {
14
- full.value = localStorage.getItem(KEY) === '1'
15
- } catch {}
16
- apply(full.value)
17
- })
18
-
19
- function apply(val: boolean) {
20
- const root = document.documentElement
21
- if (val) root.classList.add('content-fullscreen')
22
- else root.classList.remove('content-fullscreen')
23
- }
24
-
25
- function toggle() {
26
- full.value = !full.value
27
- apply(full.value)
28
- try {
29
- localStorage.setItem(KEY, full.value ? '1' : '0')
30
- } catch {}
31
- }
32
- </script>
33
-
34
- <style module src="./ToggleFullContent.module.scss"></style>
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,11 +1,11 @@
1
- .sidebarToggleBtn {
2
- width: 1.5rem;
3
- height: 1.5rem;
4
- padding: 3px;
5
- cursor: pointer;
6
- transition: all 0.2s;
7
-
8
- &:hover {
9
- background: var(--vp-c-bg-alt);
10
- }
11
- }
1
+ .sidebarToggleBtn {
2
+ width: 1.5rem;
3
+ height: 1.5rem;
4
+ padding: 3px;
5
+ cursor: pointer;
6
+ transition: all 0.2s;
7
+
8
+ &:hover {
9
+ background: var(--vp-c-bg-alt);
10
+ }
11
+ }