@sugarat/theme 0.2.17 → 0.2.19

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
@@ -365,8 +365,19 @@ declare namespace Theme {
365
365
  /**
366
366
  * 配置内置的 markdown-it-task-checkbox 插件,设置 false 则关闭
367
367
  * 详见 https://github.com/linsir/markdown-it-task-checkbox
368
+ * @default true
368
369
  */
369
370
  taskCheckbox?: TaskCheckbox | boolean;
371
+ /**
372
+ * 支持 markdown 时间线语法,在 vitepress 中使用 markdown 渲染时间线(时间轴)样式。
373
+ * 详见 https://github.com/HanochMa/vitepress-markdown-timeline
374
+ * @default true
375
+ */
376
+ timeline?: boolean;
377
+ /**
378
+ * 回到顶部
379
+ * @default true
380
+ */
370
381
  backToTop?: boolean | BackToTop;
371
382
  }
372
383
  interface BackToTop {
package/node.js CHANGED
@@ -203,6 +203,9 @@ var tabsPlugin = (md) => {
203
203
  };
204
204
  };
205
205
 
206
+ // src/utils/node/mdPlugins.ts
207
+ var import_vitepress_markdown_timeline = __toESM(require("vitepress-markdown-timeline"));
208
+
206
209
  // src/utils/node/index.ts
207
210
  var import_node_child_process = require("child_process");
208
211
  var import_node_path = __toESM(require("path"));
@@ -324,18 +327,15 @@ function getMarkdownPlugins(cfg) {
324
327
  if (cfg?.tabs !== false) {
325
328
  markdownPlugin.push(tabsPlugin);
326
329
  }
327
- if (cfg) {
328
- cfg.mermaid = cfg?.mermaid ?? true;
329
- if (cfg?.mermaid !== false) {
330
- const { MermaidMarkdown } = _require("vitepress-plugin-mermaid");
331
- markdownPlugin.push(MermaidMarkdown);
332
- }
330
+ if (cfg?.mermaid !== false) {
331
+ const { MermaidMarkdown } = _require("vitepress-plugin-mermaid");
332
+ markdownPlugin.push(MermaidMarkdown);
333
333
  }
334
- if (cfg) {
335
- cfg.taskCheckbox = cfg?.taskCheckbox ?? true;
336
- if (cfg.taskCheckbox !== false) {
337
- markdownPlugin.push(taskCheckboxPlugin(cfg.taskCheckbox));
338
- }
334
+ if (cfg.taskCheckbox !== false) {
335
+ markdownPlugin.push(taskCheckboxPlugin(typeof cfg?.taskCheckbox === "boolean" ? {} : cfg?.taskCheckbox));
336
+ }
337
+ if (cfg?.timeline !== false) {
338
+ markdownPlugin.push(import_vitepress_markdown_timeline.default);
339
339
  }
340
340
  return markdownPlugin;
341
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -42,6 +42,8 @@
42
42
  "gray-matter": "^4.0.3",
43
43
  "markdown-it-task-checkbox": "^1.0.6",
44
44
  "mermaid": "^10.2.4",
45
+ "swiper": "^11.0.5",
46
+ "vitepress-markdown-timeline": "^1.2.1",
45
47
  "vitepress-plugin-mermaid": "2.0.13",
46
48
  "vitepress-plugin-pagefind": "0.2.10",
47
49
  "vitepress-plugin-rss": "0.2.1",
@@ -37,9 +37,9 @@ const { Layout } = Theme
37
37
  <!-- 阅读时间分析 -->
38
38
  <ClientOnly>
39
39
  <BlogArticleAnalyze />
40
+ <!-- 图片预览 -->
41
+ <BlogImagePreview />
40
42
  </ClientOnly>
41
- <!-- 图片预览 -->
42
- <BlogImagePreview />
43
43
  </template>
44
44
 
45
45
  <template #nav-bar-content-before>
@@ -28,8 +28,8 @@ const iconSVGStr = computed(() => typeof backToTopConfig === 'boolean' ? '' : ba
28
28
 
29
29
  <template>
30
30
  <div v-if="open" v-show="show" class="back-to-top">
31
- <span class="icon-wrapper">
32
- <ElIcon @click="handleBackRoTop">
31
+ <span class="icon-wrapper" @click="handleBackRoTop">
32
+ <ElIcon :size="20">
33
33
  <i v-if="iconSVGStr" v-outer-html="iconSVGStr" />
34
34
  <svg v-else width="512" height="512" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
35
35
  <path
@@ -94,15 +94,15 @@ const labelText = computed(() => {
94
94
 
95
95
  <div v-show="!commentIsVisible" class="comment-btn-wrapper">
96
96
  <span v-if="!mobileMinify && labelText" class="icon-wrapper-text" @click="handleScrollToComment">
97
- <ElIcon>
97
+ <ElIcon :size="20">
98
98
  <CommentIcon />
99
99
  </ElIcon>
100
100
  <span class="text">
101
101
  {{ labelText }}
102
102
  </span>
103
103
  </span>
104
- <span v-else class="icon-wrapper">
105
- <ElIcon @click="handleScrollToComment">
104
+ <span v-else class="icon-wrapper" @click="handleScrollToComment">
105
+ <ElIcon :size="20">
106
106
  <CommentIcon />
107
107
  </ElIcon>
108
108
  </span>
@@ -1,7 +1,8 @@
1
1
  <script lang="ts" setup>
2
2
  import { ElAvatar } from 'element-plus'
3
- import { useDark } from '@vueuse/core'
4
- import { computed } from 'vue'
3
+ import { useDark, useIntervalFn } from '@vueuse/core'
4
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
5
+ import Swiper from 'swiper'
5
6
  import { useBlogConfig } from '../composables/config/blog'
6
7
  import { getImageUrl, shuffleArray } from '../utils/client'
7
8
  import type { Theme } from '../'
@@ -18,7 +19,6 @@ const friendConfig = computed<Theme.FriendConfig>(() => ({
18
19
  ...(Array.isArray(friend) ? { list: friend } : friend)
19
20
  }))
20
21
 
21
- // TODO: 待优化
22
22
  const limit = computed(() => {
23
23
  const { limit } = friendConfig.value
24
24
  return (!limit || limit <= 0) ? 0 : limit || Number.MAX_SAFE_INTEGER
@@ -26,7 +26,7 @@ const limit = computed(() => {
26
26
 
27
27
  const scrollSpeed = computed(() => {
28
28
  const { scrollSpeed } = friendConfig.value
29
- return (!scrollSpeed || scrollSpeed <= 0) ? (friendConfig.value.list.length - 1) * (friendConfig.value.list.length / limit.value) * 1000 : scrollSpeed
29
+ return scrollSpeed ?? 1500
30
30
  })
31
31
 
32
32
  const openScroll = computed(() => {
@@ -58,18 +58,37 @@ const friendList = computed(() => {
58
58
  alt
59
59
  }
60
60
  })
61
- return openScroll.value ? [...list, ...list] : list
61
+ return list
62
62
  })
63
63
 
64
- const cardHeight = 83
64
+ const cardHeight = 76
65
65
  const scrollWrapperHeight = computed(() => {
66
66
  return openScroll.value ? limit.value * cardHeight : 0
67
67
  })
68
68
  const containerHeight = computed(() => {
69
69
  return scrollWrapperHeight.value ? `${scrollWrapperHeight.value}px` : 'auto'
70
70
  })
71
- const scrollTop = computed(() => {
72
- return `-${scrollWrapperHeight.value * 2}px`
71
+
72
+ const swiper = ref<Swiper>()
73
+ const { resume, pause } = useIntervalFn(() => {
74
+ swiper.value?.slideNext()
75
+ }, scrollSpeed.value)
76
+
77
+ onMounted(() => {
78
+ pause()
79
+ if (openScroll.value) {
80
+ // eslint-disable-next-line no-new
81
+ swiper.value = new Swiper('.scroll-wrapper', {
82
+ direction: 'vertical',
83
+ slidesPerView: limit.value,
84
+ loop: true,
85
+ })
86
+ resume()
87
+ }
88
+ })
89
+
90
+ onUnmounted(() => {
91
+ pause()
73
92
  })
74
93
  </script>
75
94
 
@@ -102,17 +121,11 @@ const scrollTop = computed(() => {
102
121
  height: containerHeight,
103
122
  }"
104
123
  >
105
- <ol
106
- class="friend-list" :style="{
107
- animationPlayState: openScroll ? 'running' : 'paused',
108
- animationDuration: `${scrollSpeed / 1000}s`,
109
- }
110
- "
111
- >
112
- <li v-for="(v, idx) in friendList" :key="idx">
124
+ <ol class="friend-list swiper-wrapper">
125
+ <li v-for=" (v, idx) in friendList" :key="idx" class="swiper-slide">
113
126
  <a :href="v.url" target="_blank">
114
127
  <ElAvatar :size="50" :src="v.avatar" :alt="v.alt" />
115
- <div>
128
+ <div class="info-wrapper">
116
129
  <span class="nickname">{{ v.nickname }}</span>
117
130
  <p class="des">{{ v.des }}</p>
118
131
  </div>
@@ -159,15 +172,6 @@ const scrollTop = computed(() => {
159
172
  flex-direction: column;
160
173
  }
161
174
 
162
- @keyframes scrollList {
163
- 0% {
164
- top: 0;
165
- }
166
- 100% {
167
- top: v-bind(scrollTop);
168
- }
169
- }
170
-
171
175
  .scroll-wrapper {
172
176
  overflow: hidden;
173
177
  position: relative;
@@ -178,35 +182,35 @@ const scrollTop = computed(() => {
178
182
  flex-direction: column;
179
183
  list-style: none;
180
184
  margin: 0;
181
- padding: 0 10px 0 0px;
185
+ padding: 10px 10px 0 0px;
182
186
  width: 100%;
183
187
 
184
188
  position: relative;
185
189
  width: 100%;
186
- animation-name: scrollList;
187
- animation-timing-function:linear;
188
- animation-iteration-count:infinite;
189
-
190
- &:hover {
191
- animation-play-state: paused !important;
192
- }
193
190
 
194
191
  li {
195
- padding: 6px;
196
- margin-top: 10px;
197
-
192
+ box-sizing: border-box;
193
+ padding: 0 5px;
194
+ height: 76px;
198
195
  .el-avatar {
199
196
  min-width: 50px;
200
197
  }
201
198
 
202
199
  a {
203
200
  display: flex;
201
+ align-items: center;
204
202
  }
205
203
 
206
204
  div {
207
205
  padding-left: 10px;
208
206
  }
209
207
 
208
+ .info-wrapper {
209
+ display: flex;
210
+ flex-direction: column;
211
+ overflow: hidden;
212
+ }
213
+
210
214
  .nickname {
211
215
  font-size: 16px;
212
216
  font-weight: 450;
@@ -215,6 +219,9 @@ const scrollTop = computed(() => {
215
219
  .des {
216
220
  color: var(--vp-c-text-2);
217
221
  font-size: 14px;
222
+ overflow: hidden;
223
+ white-space: nowrap;
224
+ text-overflow: ellipsis;
218
225
  }
219
226
  }
220
227
  }
@@ -397,9 +397,19 @@ export namespace Theme {
397
397
  /**
398
398
  * 配置内置的 markdown-it-task-checkbox 插件,设置 false 则关闭
399
399
  * 详见 https://github.com/linsir/markdown-it-task-checkbox
400
+ * @default true
400
401
  */
401
402
  taskCheckbox?: TaskCheckbox | boolean
402
-
403
+ /**
404
+ * 支持 markdown 时间线语法,在 vitepress 中使用 markdown 渲染时间线(时间轴)样式。
405
+ * 详见 https://github.com/HanochMa/vitepress-markdown-timeline
406
+ * @default true
407
+ */
408
+ timeline?: boolean
409
+ /**
410
+ * 回到顶部
411
+ * @default true
412
+ */
403
413
  backToTop?: boolean | BackToTop
404
414
  }
405
415
 
package/src/index.ts CHANGED
@@ -5,9 +5,13 @@ import './styles/index.scss'
5
5
  import 'element-plus/dist/index.css'
6
6
  import 'element-plus/theme-chalk/dark/css-vars.css'
7
7
 
8
+ // 引入时间线组件样式
9
+ import 'vitepress-markdown-timeline/dist/theme/index.css'
8
10
  import type { Theme } from 'vitepress'
9
11
  import DefaultTheme from 'vitepress/theme'
10
12
  import { enhanceAppWithTabs } from 'vitepress-plugin-tabs/client'
13
+
14
+ // 图表渲染组件
11
15
  import Mermaid from 'vitepress-plugin-mermaid/Mermaid.vue'
12
16
  import BlogApp from './components/BlogApp.vue'
13
17
  import { withConfigProvider } from './composables/config/blog'
@@ -27,7 +31,7 @@ export const BlogTheme: Theme = {
27
31
  DefaultTheme.enhanceApp(ctx)
28
32
  ctx.app.component('TimelinePage', TimelinePage)
29
33
  ctx.app.component('UserWorksPage', UserWorksPage)
30
- ctx.app.component('Mermaid', Mermaid)
34
+ ctx.app.component('Mermaid', Mermaid as any)
31
35
  }
32
36
  }
33
37
 
@@ -2,6 +2,7 @@
2
2
  import { createRequire } from 'module'
3
3
  import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
4
4
  import type { UserConfig } from 'vitepress'
5
+ import timeline from 'vitepress-markdown-timeline'
5
6
  import type { Theme } from '../../composables/config/index'
6
7
  import { aliasObjectToArray } from './index'
7
8
 
@@ -17,25 +18,22 @@ export function getMarkdownPlugins(cfg?: Partial<Theme.BlogConfig>) {
17
18
  }
18
19
 
19
20
  // 添加mermaid markdown 插件
20
- if (cfg) {
21
- cfg.mermaid = cfg?.mermaid ?? true
22
- if (cfg?.mermaid !== false) {
23
- const { MermaidMarkdown } = _require('vitepress-plugin-mermaid')
24
- markdownPlugin.push(MermaidMarkdown)
25
- }
21
+ if (cfg?.mermaid !== false) {
22
+ const { MermaidMarkdown } = _require('vitepress-plugin-mermaid')
23
+ markdownPlugin.push(MermaidMarkdown)
26
24
  }
27
25
 
28
- if (cfg) {
29
- cfg.taskCheckbox = cfg?.taskCheckbox ?? true
30
- if (cfg.taskCheckbox !== false) {
31
- markdownPlugin.push(taskCheckboxPlugin(cfg.taskCheckbox))
32
- }
26
+ if (cfg.taskCheckbox !== false) {
27
+ markdownPlugin.push(taskCheckboxPlugin(typeof cfg?.taskCheckbox === 'boolean' ? {} : cfg?.taskCheckbox))
33
28
  }
34
29
 
30
+ if (cfg?.timeline !== false) {
31
+ markdownPlugin.push(timeline)
32
+ }
35
33
  return markdownPlugin
36
34
  }
37
35
 
38
- export function taskCheckboxPlugin(ops: Theme.TaskCheckbox | boolean) {
36
+ export function taskCheckboxPlugin(ops?: Theme.TaskCheckbox) {
39
37
  return (md: any) => {
40
38
  md.use(_require('markdown-it-task-checkbox'), ops)
41
39
  }