@sugarat/theme 0.3.4 → 0.3.6

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.
package/node.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { DefaultTheme, UserConfig } from 'vitepress';
1
+ import { Route, DefaultTheme, UserConfig } from 'vitepress';
2
2
  import { ElButton } from 'element-plus';
3
3
  import { RSSOptions } from 'vitepress-plugin-rss';
4
4
  import { Repo, Mapping } from '@giscus/vue';
5
5
  import { Options } from 'oh-my-live2d';
6
+ import { Ref } from 'vue';
6
7
  export { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
7
8
 
8
9
  type RSSPluginOptions = RSSOptions;
@@ -231,6 +232,11 @@ declare namespace Theme {
231
232
  * @default true
232
233
  */
233
234
  reopen?: boolean;
235
+ /**
236
+ * 是否打开闪烁提示,通常需要和 reopen 搭配使用
237
+ * @default true
238
+ */
239
+ twinkle?: boolean;
234
240
  /**
235
241
  * 设置展示图标,svg
236
242
  * @recommend https://iconbuddy.app/search?q=fire
@@ -241,6 +247,11 @@ declare namespace Theme {
241
247
  * @recommend https://iconbuddy.app/search?q=fire
242
248
  */
243
249
  closeIcon?: string;
250
+ /**
251
+ * 自定义展示策略
252
+ * @param to 切换到的目标路由
253
+ */
254
+ onRouteChanged?: (to: Route, show: Ref<boolean>) => void;
244
255
  }
245
256
  interface FriendLink {
246
257
  nickname: string;
package/node.js CHANGED
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(node_exports);
40
40
  // src/utils/node/mdPlugins.ts
41
41
  var import_module = require("module");
42
42
 
43
- // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.1.4_@algolia+client-search@4.19.1_@types+node@20.6.3__scid7oqqpyg2qxcz73ypk7jzz4/node_modules/vitepress-plugin-tabs/dist/index.js
43
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.2.2_@algolia+client-search@4.19.1_@types+node@20.6.3__yypdqxhxkwwat3gkog3hzzeasy/node_modules/vitepress-plugin-tabs/dist/index.js
44
44
  var tabsMarker = "=tabs";
45
45
  var tabsMarkerLen = tabsMarker.length;
46
46
  var ruleBlockTabs = (state, startLine, endLine, silent) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -46,23 +46,23 @@
46
46
  "gray-matter": "^4.0.3",
47
47
  "markdown-it-task-checkbox": "^1.0.6",
48
48
  "mermaid": "^10.9.0",
49
- "oh-my-live2d": "^0.17.0",
49
+ "oh-my-live2d": "^0.19.3",
50
50
  "swiper": "^11.1.1",
51
51
  "vitepress-markdown-timeline": "^1.2.1",
52
52
  "vitepress-plugin-mermaid": "2.0.13",
53
53
  "vitepress-plugin-tabs": "0.2.0",
54
- "vitepress-plugin-pagefind": "0.2.14",
55
- "vitepress-plugin-rss": "0.2.4"
54
+ "vitepress-plugin-pagefind": "0.3.3",
55
+ "vitepress-plugin-rss": "0.2.6"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@element-plus/icons-vue": "^2.3.1",
59
59
  "artalk": "^2.8.5",
60
60
  "element-plus": "^2.7.2",
61
- "pagefind": "1.1.0",
61
+ "pagefind": "^1.1.0",
62
62
  "sass": "^1.76.0",
63
63
  "typescript": "^5.4.5",
64
64
  "vite": "^5.2.11",
65
- "vitepress": "1.1.4",
65
+ "vitepress": "1.2.2",
66
66
  "vue": "^3.4.26"
67
67
  },
68
68
  "scripts": {
@@ -3,7 +3,6 @@ import Theme from 'vitepress/theme'
3
3
  import { useData } from 'vitepress'
4
4
  import { computed } from 'vue'
5
5
  import { useDarkTransition } from '../hooks/useDarkTransition'
6
- import { useOml2d } from '../hooks/useOml2d'
7
6
  import { useBlogThemeMode, useDarkTransitionConfig } from '../composables/config/blog'
8
7
  import BlogHomeInfo from './BlogHomeInfo.vue'
9
8
  import BlogHomeBanner from './BlogHomeBanner.vue'
@@ -17,6 +16,7 @@ import BlogFooter from './BlogFooter.vue'
17
16
  import BlogHomeHeaderAvatar from './BlogHomeHeaderAvatar.vue'
18
17
  import BlogBackToTop from './BlogBackToTop.vue'
19
18
  import CommentGiscus from './CommentGiscus.vue'
19
+ import BlogOml2d from './BlogOml2d.vue'
20
20
 
21
21
  import CommentArtalk from './CommentArtalk.vue'
22
22
  import BlogButtonAfterArticle from './BlogButtonAfterArticle.vue'
@@ -27,8 +27,6 @@ const layout = computed(() => frontmatter.value.layout)
27
27
  const isBlogTheme = useBlogThemeMode()
28
28
  const { Layout } = Theme
29
29
 
30
- // oh-my-live2d 扩展
31
- useOml2d()
32
30
  // 切换深色模式过渡
33
31
  // https://vitepress.dev/zh/guide/extending-default-theme#on-appearance-toggle
34
32
  useDarkTransition()
@@ -40,6 +38,7 @@ const openTransition = useDarkTransitionConfig()
40
38
  <template #layout-top>
41
39
  <slot name="layout-top" />
42
40
  <ClientOnly>
41
+ <BlogOml2d />
43
42
  <BlogAlert />
44
43
  <BlogPopover />
45
44
  </ClientOnly>
@@ -1,8 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted } from 'vue'
2
+ import { computed, watch } from 'vue'
3
3
  import { ElPagination } from 'element-plus'
4
- import { useData, useRouter } from 'vitepress'
5
- import { useBrowserLocation } from '@vueuse/core'
4
+ import { useData, useRoute, useRouter } from 'vitepress'
6
5
  import {
7
6
  useActiveTag,
8
7
  useArticles,
@@ -54,12 +53,12 @@ const currentWikiData = computed(() => {
54
53
  })
55
54
 
56
55
  const router = useRouter()
57
- const location = useBrowserLocation()
58
56
  const queryPageNumKey = 'pageNum'
59
57
  function handleUpdatePageNum(current: number) {
60
58
  if (currentPage.value === current) {
61
59
  return
62
60
  }
61
+ currentPage.value = current
63
62
  const { searchParams } = new URL(window.location.href!)
64
63
  searchParams.delete(queryPageNumKey)
65
64
  searchParams.append(queryPageNumKey, String(current))
@@ -69,25 +68,26 @@ function handleUpdatePageNum(current: number) {
69
68
  )
70
69
  }
71
70
 
72
- function refreshCurrentPage(search?: string) {
73
- if (location.value?.href) {
74
- const searchParams = new URLSearchParams(search || location.value.search)
75
- const pageNum = Number(searchParams.get(queryPageNumKey)) || 1
76
- if (pageNum !== currentPage.value) {
77
- currentPage.value = pageNum
78
- }
71
+ const route = useRoute()
72
+
73
+ function refreshCurrentPage() {
74
+ if (typeof window === 'undefined')
75
+ return
76
+ const search = window.location.search.slice(1)
77
+ const searchParams = new URLSearchParams(search)
78
+ const pageNum = Number(searchParams.get(queryPageNumKey)) || 1
79
+ if (pageNum !== currentPage.value) {
80
+ currentPage.value = pageNum
79
81
  }
80
82
  }
81
- router.onBeforeRouteChange = (to) => {
82
- refreshCurrentPage(to.slice(to.indexOf('?') + 1))
83
- }
84
- // 未覆盖的场景处理
85
- router.onAfterRouteChanged = (to) => {
86
- refreshCurrentPage(to.slice(to.indexOf('?') + 1))
87
- }
88
- onMounted(() => {
83
+ watch(route, () => {
89
84
  refreshCurrentPage()
90
- })
85
+ }, { immediate: true })
86
+
87
+ // 未覆盖的场景处理 左上回到首页
88
+ router.onAfterRouteChanged = () => {
89
+ refreshCurrentPage()
90
+ }
91
91
  </script>
92
92
 
93
93
  <template>
@@ -0,0 +1,10 @@
1
+ <script lang="ts" setup>
2
+ import { useOml2d } from '../hooks/useOml2d'
3
+
4
+ // oh-my-live2d 扩展
5
+ useOml2d()
6
+ </script>
7
+
8
+ <template>
9
+ <div id="oh-my-live2d" style="display: none;" />
10
+ </template>
@@ -1,10 +1,11 @@
1
1
  <script lang="ts" setup>
2
2
  import { ElButton, ElIcon } from 'element-plus'
3
3
  import { CircleCloseFilled } from '@element-plus/icons-vue'
4
- import { computed, h, onMounted, ref } from 'vue'
4
+ import { computed, h, onMounted, ref, watch } from 'vue'
5
5
  import type { BlogPopover } from '@sugarat/theme'
6
6
  import { parseStringStyle } from '@vue/shared'
7
- import { useWindowSize } from '@vueuse/core'
7
+ import { useDebounceFn, useWindowSize } from '@vueuse/core'
8
+ import { useRoute, useRouter } from 'vitepress'
8
9
  import { useBlogConfig } from '../composables/config/blog'
9
10
  import { vOuterHtml } from '../directives'
10
11
 
@@ -24,7 +25,8 @@ const closeFlag = `${storageKey}-close`
24
25
 
25
26
  // 移动端最小化
26
27
  const { width } = useWindowSize()
27
-
28
+ const router = useRouter()
29
+ const route = useRoute()
28
30
  onMounted(() => {
29
31
  if (!popoverProps?.title) {
30
32
  return
@@ -65,6 +67,12 @@ onMounted(() => {
65
67
  }
66
68
  })
67
69
 
70
+ const onAfterRouteChanged = useDebounceFn(() => {
71
+ popoverProps?.onRouteChanged?.(route, show)
72
+ }, 10)
73
+
74
+ watch(route, onAfterRouteChanged, { immediate: true })
75
+
68
76
  function handleClose() {
69
77
  show.value = false
70
78
  if (popoverProps?.duration === -1) {
@@ -105,7 +113,12 @@ function PopoverValue(props: { key: number; item: BlogPopover.Value },
105
113
  {
106
114
  type: 'primary',
107
115
  onClick: () => {
108
- window.open(item.link, '_self')
116
+ if (/^\s*http(s)?:\/\//.test(item.link)) {
117
+ window.open(item.link)
118
+ }
119
+ else {
120
+ router.go(item.link)
121
+ }
109
122
  },
110
123
  style: parseStringStyle(item.style || ''),
111
124
  ...item.props
@@ -129,9 +142,7 @@ function PopoverValue(props: { key: number; item: BlogPopover.Value },
129
142
  <div class="title-wrapper">
130
143
  <ElIcon size="20px">
131
144
  <i v-if="popoverProps?.icon" v-outer-html="popoverProps.icon" />
132
- <svg v-else width="512" height="512" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
133
- <path fill="currentColor" d="M880 112c-3.8 0-7.7.7-11.6 2.3L292 345.9H128c-8.8 0-16 7.4-16 16.6v299c0 9.2 7.2 16.6 16 16.6h101.6c-3.7 11.6-5.6 23.9-5.6 36.4c0 65.9 53.8 119.5 120 119.5c55.4 0 102.1-37.6 115.9-88.4l408.6 164.2c3.9 1.5 7.8 2.3 11.6 2.3c16.9 0 32-14.2 32-33.2V145.2C912 126.2 897 112 880 112M344 762.3c-26.5 0-48-21.4-48-47.8c0-11.2 3.9-21.9 11-30.4l84.9 34.1c-2 24.6-22.7 44.1-47.9 44.1" />
134
- </svg>
145
+ <svg v-else t="1716085184855" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4274" width="200" height="200"><path d="M660.48 872.448q6.144 0-3.584 15.36t-29.696 33.792-47.104 33.792-57.856 15.36q-27.648 0-53.248-15.36t-45.056-33.792-29.696-33.792-6.144-15.36l272.384 0zM914.432 785.408q7.168 9.216 6.656 17.92t-4.608 14.848-10.24 9.728-12.288 3.584l-747.52 0q-14.336 0-20.992-11.776t4.608-29.184q17.408-30.72 40.96-68.608t44.544-81.408 36.352-92.16 15.36-101.888q0-51.2 14.336-92.16t37.376-71.68 53.248-52.224 62.976-32.768q-16.384-26.624-16.384-55.296 0-41.984 28.672-70.656t70.656-28.672 70.656 28.672 28.672 70.656q0 14.336-4.096 28.16t-11.264 25.088q34.816 11.264 66.048 32.768t54.272 53.248 36.864 72.704 13.824 91.136q0 51.2 15.36 100.864t36.864 94.208 45.568 81.408 43.52 63.488zM478.208 142.336q0 16.384 11.264 28.16t27.648 11.776l2.048 0q16.384-1.024 27.648-12.288t11.264-27.648q0-17.408-11.264-28.672t-28.672-11.264-28.672 11.264-11.264 28.672z" p-id="4275" /></svg>
135
146
  </ElIcon>
136
147
  <span class="title">{{ popoverProps?.title }}</span>
137
148
  </div>
@@ -154,13 +165,12 @@ function PopoverValue(props: { key: number; item: BlogPopover.Value },
154
165
  </div>
155
166
  <div
156
167
  v-show="!show && (popoverProps?.reopen ?? true) && popoverProps?.title" class="theme-blog-popover-close"
168
+ :class="{ twinkle: !show && (popoverProps?.twinkle ?? true) }"
157
169
  @click="show = true"
158
170
  >
159
171
  <ElIcon>
160
172
  <i v-if="popoverProps?.icon" v-outer-html="popoverProps.icon" />
161
- <svg v-else width="512" height="512" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
162
- <path fill="currentColor" d="M880 112c-3.8 0-7.7.7-11.6 2.3L292 345.9H128c-8.8 0-16 7.4-16 16.6v299c0 9.2 7.2 16.6 16 16.6h101.6c-3.7 11.6-5.6 23.9-5.6 36.4c0 65.9 53.8 119.5 120 119.5c55.4 0 102.1-37.6 115.9-88.4l408.6 164.2c3.9 1.5 7.8 2.3 11.6 2.3c16.9 0 32-14.2 32-33.2V145.2C912 126.2 897 112 880 112M344 762.3c-26.5 0-48-21.4-48-47.8c0-11.2 3.9-21.9 11-30.4l84.9 34.1c-2 24.6-22.7 44.1-47.9 44.1" />
163
- </svg>
173
+ <svg v-else t="1716085184855" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4274" width="200" height="200"><path d="M660.48 872.448q6.144 0-3.584 15.36t-29.696 33.792-47.104 33.792-57.856 15.36q-27.648 0-53.248-15.36t-45.056-33.792-29.696-33.792-6.144-15.36l272.384 0zM914.432 785.408q7.168 9.216 6.656 17.92t-4.608 14.848-10.24 9.728-12.288 3.584l-747.52 0q-14.336 0-20.992-11.776t4.608-29.184q17.408-30.72 40.96-68.608t44.544-81.408 36.352-92.16 15.36-101.888q0-51.2 14.336-92.16t37.376-71.68 53.248-52.224 62.976-32.768q-16.384-26.624-16.384-55.296 0-41.984 28.672-70.656t70.656-28.672 70.656 28.672 28.672 70.656q0 14.336-4.096 28.16t-11.264 25.088q34.816 11.264 66.048 32.768t54.272 53.248 36.864 72.704 13.824 91.136q0 51.2 15.36 100.864t36.864 94.208 45.568 81.408 43.52 63.488zM478.208 142.336q0 16.384 11.264 28.16t27.648 11.776l2.048 0q16.384-1.024 27.648-12.288t11.264-27.648q0-17.408-11.264-28.672t-28.672-11.264-28.672 11.264-11.264 28.672z" p-id="4275" /></svg>
164
174
  </ElIcon>
165
175
  </div>
166
176
  </template>
@@ -262,4 +272,19 @@ function PopoverValue(props: { key: number; item: BlogPopover.Value },
262
272
  display: flex;
263
273
  flex-direction: column;
264
274
  }
275
+ .theme-blog-popover-close.twinkle {
276
+ animation: twinkle 1s ease-in-out infinite;
277
+ }
278
+
279
+ @keyframes twinkle {
280
+ 0% {
281
+ opacity: 0.5;
282
+ }
283
+ 50% {
284
+ opacity: 0;
285
+ }
286
+ 100% {
287
+ opacity: 0.5;
288
+ }
289
+ }
265
290
  </style>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { useData, useRoute } from 'vitepress'
3
- import { computed, ref, watch } from 'vue'
3
+ import { computed, nextTick, ref, watch } from 'vue'
4
4
  import Giscus from '@giscus/vue'
5
5
  import { useBlogConfig } from '../composables/config/blog'
6
6
 
@@ -23,14 +23,14 @@ const commentConfig = computed(() => {
23
23
  const { isDark } = useData()
24
24
 
25
25
  const route = useRoute()
26
- const showComment = ref(true)
26
+ const showComment = ref(false)
27
27
  watch(
28
- () => route.path,
28
+ route,
29
29
  () => {
30
30
  showComment.value = false
31
- setTimeout(() => {
31
+ nextTick(() => {
32
32
  showComment.value = true
33
- }, 200)
33
+ })
34
34
  },
35
35
  {
36
36
  immediate: true
@@ -40,7 +40,7 @@ watch(
40
40
 
41
41
  <template>
42
42
  <Giscus
43
- v-if="commentConfig" :repo="commentConfig.repo" :repo-id="commentConfig.repoId"
43
+ v-if="commentConfig && showComment" :repo="commentConfig.repo" :repo-id="commentConfig.repoId"
44
44
  :category="commentConfig.category" :category-id="commentConfig.categoryId"
45
45
  :mapping="commentConfig.mapping || 'pathname'" reactions-enabled="1" emit-metadata="0"
46
46
  :input-position="commentConfig.inputPosition || 'top'" :theme="isDark ? 'dark' : 'light'"
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable ts/no-namespace */
2
2
  import type { ElButton } from 'element-plus'
3
- import type { DefaultTheme } from 'vitepress'
3
+ import type { DefaultTheme, Route } from 'vitepress'
4
4
  import type { RSSOptions } from 'vitepress-plugin-rss'
5
5
  import type { Mapping, Repo } from '@giscus/vue'
6
6
  import type { Options as Oml2dOptions } from 'oh-my-live2d'
7
+ import type { Ref } from 'vue'
7
8
 
8
9
  type RSSPluginOptions = RSSOptions
9
10
 
@@ -243,6 +244,11 @@ export namespace Theme {
243
244
  * @default true
244
245
  */
245
246
  reopen?: boolean
247
+ /**
248
+ * 是否打开闪烁提示,通常需要和 reopen 搭配使用
249
+ * @default true
250
+ */
251
+ twinkle?: boolean
246
252
  /**
247
253
  * 设置展示图标,svg
248
254
  * @recommend https://iconbuddy.app/search?q=fire
@@ -253,6 +259,11 @@ export namespace Theme {
253
259
  * @recommend https://iconbuddy.app/search?q=fire
254
260
  */
255
261
  closeIcon?: string
262
+ /**
263
+ * 自定义展示策略
264
+ * @param to 切换到的目标路由
265
+ */
266
+ onRouteChanged?: (to: Route, show: Ref<boolean>) => void
256
267
  }
257
268
  export interface FriendLink {
258
269
  nickname: string