@sugarat/theme 0.5.14 → 0.5.15

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
@@ -622,6 +622,11 @@ declare namespace Theme {
622
622
  * @default '🏷 标签'
623
623
  */
624
624
  title?: string;
625
+ /**
626
+ * 首页标签默认展示数量,超出部分折叠
627
+ * @default 999
628
+ */
629
+ limit?: number;
625
630
  }
626
631
  }
627
632
 
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.7.3_vitepress@2.0.0-alpha.15_@types+node@24.5.2_async-validator_f00dcfd3cc5e72074cf41a606f1d799c/node_modules/vitepress-plugin-tabs/dist/node/index.js
43
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.7.3_vitepress@2.0.0-alpha.16_@types+node@24.5.2_async-validator@4.2.5_wszfouv2xxx6bizfwwcmbwut3e/node_modules/vitepress-plugin-tabs/dist/node/index.js
44
44
  function container_plugin(md, name, options) {
45
45
  function validateDefault(params) {
46
46
  return params.trim().split(" ", 2)[0] === name;
@@ -422,7 +422,8 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset,
422
422
  meta.tag = [meta.tag || []].flat().concat([
423
423
  .../* @__PURE__ */ new Set([...meta.categories || [], ...meta.tags || []])
424
424
  ]);
425
- meta.description = meta.description || (0, import_theme_shared2.getTextSummary)(content, 100) || excerpt;
425
+ const contentWithoutHeadings = content.replace(/^#+\s+.*$/gm, "");
426
+ meta.description = meta.description || (0, import_theme_shared2.getTextSummary)(contentWithoutHeadings, 100) || excerpt;
426
427
  meta.cover = meta.cover ?? getFirstImagURLFromMD(fileContent, route);
427
428
  if (meta.publish === false) {
428
429
  meta.hidden = true;
package/node.mjs CHANGED
@@ -9,7 +9,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  // src/utils/node/mdPlugins.ts
10
10
  import { createRequire } from "module";
11
11
 
12
- // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.7.3_vitepress@2.0.0-alpha.15_@types+node@24.5.2_async-validator_f00dcfd3cc5e72074cf41a606f1d799c/node_modules/vitepress-plugin-tabs/dist/node/index.js
12
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.7.3_vitepress@2.0.0-alpha.16_@types+node@24.5.2_async-validator@4.2.5_wszfouv2xxx6bizfwwcmbwut3e/node_modules/vitepress-plugin-tabs/dist/node/index.js
13
13
  function container_plugin(md, name, options) {
14
14
  function validateDefault(params) {
15
15
  return params.trim().split(" ", 2)[0] === name;
@@ -389,7 +389,8 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset,
389
389
  meta.tag = [meta.tag || []].flat().concat([
390
390
  .../* @__PURE__ */ new Set([...meta.categories || [], ...meta.tags || []])
391
391
  ]);
392
- meta.description = meta.description || getTextSummary(content, 100) || excerpt;
392
+ const contentWithoutHeadings = content.replace(/^#+\s+.*$/gm, "");
393
+ meta.description = meta.description || getTextSummary(contentWithoutHeadings, 100) || excerpt;
393
394
  meta.cover = meta.cover ?? getFirstImagURLFromMD(fileContent, route);
394
395
  if (meta.publish === false) {
395
396
  meta.hidden = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.5.14",
3
+ "version": "0.5.15",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -51,11 +51,11 @@
51
51
  "vitepress-plugin-group-icons": "1.6.5",
52
52
  "vitepress-plugin-mermaid": "2.0.13",
53
53
  "vitepress-plugin-tabs": "0.7.3",
54
- "vitepress-plugin-announcement": "0.1.7",
55
54
  "@sugarat/theme-shared": "0.0.7",
56
- "vitepress-plugin-image-preview": "0.1.0",
57
- "vitepress-plugin-rss": "0.4.2",
58
- "vitepress-plugin-pagefind": "0.4.18"
55
+ "vitepress-plugin-announcement": "0.1.7",
56
+ "vitepress-plugin-image-preview": "0.1.1",
57
+ "vitepress-plugin-pagefind": "0.4.19",
58
+ "vitepress-plugin-rss": "0.4.3"
59
59
  },
60
60
  "devDependencies": {
61
61
  "artalk": "^2.8.5",
@@ -63,7 +63,7 @@
63
63
  "pagefind": "^1.3.0",
64
64
  "typescript": "^5.4.5",
65
65
  "vite": "^5.4.9",
66
- "vitepress": "2.0.0-alpha.15",
66
+ "vitepress": "2.0.0-alpha.16",
67
67
  "vue": "^3.5.24",
68
68
  "vitepress-plugin-51la": "0.1.1"
69
69
  },
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import { computed, watch } from 'vue'
2
+ import { computed, ref, watch } from 'vue'
3
3
  import { useBrowserLocation, useUrlSearchParams } from '@vueuse/core'
4
4
  import { useRoute, useRouter } from 'vitepress'
5
5
  import {
@@ -19,9 +19,42 @@ const title = computed(() => (typeof homeTagsConfig.value === 'boolean' || !home
19
19
  ? `${tagsSvgStr}标签`
20
20
  : homeTagsConfig.value?.title
21
21
  )
22
- const tags = computed(() => {
23
- return [...new Set(docs.value.map(v => v.meta.tag || []).flat(3))]
22
+
23
+ // 统计每个标签的文章数量,并按数量降序排序
24
+ const tagsWithCount = computed(() => {
25
+ const tagCountMap = new Map<string, number>()
26
+ docs.value.forEach((v) => {
27
+ const articleTags = v.meta.tag || []
28
+ const flatTags = Array.isArray(articleTags) ? articleTags.flat(3) : [articleTags]
29
+ flatTags.forEach((tag: string) => {
30
+ tagCountMap.set(tag, (tagCountMap.get(tag) || 0) + 1)
31
+ })
32
+ })
33
+ // 按文章数量降序排序
34
+ return [...tagCountMap.entries()]
35
+ .sort((a, b) => b[1] - a[1])
36
+ .map(([tag, count]) => ({ tag, count }))
37
+ })
38
+
39
+ // 折叠/展开功能,从配置中读取 limit,默认 10
40
+ const showCount = computed(() => {
41
+ if (typeof homeTagsConfig.value === 'object' && homeTagsConfig.value?.limit) {
42
+ return homeTagsConfig.value.limit
43
+ }
44
+ return 999
45
+ })
46
+ const isExpanded = ref(false)
47
+ const displayTags = computed(() => {
48
+ if (isExpanded.value || tagsWithCount.value.length <= showCount.value) {
49
+ return tagsWithCount.value
50
+ }
51
+ return tagsWithCount.value.slice(0, showCount.value)
24
52
  })
53
+ const hasMore = computed(() => tagsWithCount.value.length > showCount.value)
54
+
55
+ function toggleExpand() {
56
+ isExpanded.value = !isExpanded.value
57
+ }
25
58
 
26
59
  const activeTag = useActiveTag()
27
60
 
@@ -78,7 +111,7 @@ watch(
78
111
  </script>
79
112
 
80
113
  <template>
81
- <div v-if="showTags && tags.length" class="card tags" data-pagefind-ignore="all">
114
+ <div v-if="showTags && tagsWithCount.length" class="card tags" data-pagefind-ignore="all">
82
115
  <!-- 头部 -->
83
116
  <div class="card-header">
84
117
  <span class="title svg-icon" v-html="title" />
@@ -91,15 +124,33 @@ watch(
91
124
  </div>
92
125
  <!-- 标签列表 -->
93
126
  <ul class="tag-list">
94
- <li v-for="(tag, idx) in tags" :key="tag">
127
+ <li v-for="(item, idx) in displayTags" :key="item.tag">
95
128
  <Tag
96
129
  :type="tagType[idx % tagType.length] || 'primary'"
97
- @click="handleTagClick(tag, tagType[idx % tagType.length])"
130
+ @click="handleTagClick(item.tag, tagType[idx % tagType.length])"
98
131
  >
99
- {{ tag }}
132
+ {{ item.tag }}
133
+ <span class="tag-count">{{ item.count }}</span>
100
134
  </Tag>
101
135
  </li>
102
136
  </ul>
137
+ <!-- 展开/收起按钮 -->
138
+ <div v-if="hasMore" class="expand-btn" @click="toggleExpand">
139
+ <span>{{ isExpanded ? '收起' : `展开全部 ${tagsWithCount.length} 个标签` }}</span>
140
+ <svg
141
+ class="expand-icon"
142
+ :class="{ 'is-expanded': isExpanded }"
143
+ viewBox="0 0 1024 1024"
144
+ xmlns="http://www.w3.org/2000/svg"
145
+ width="1em"
146
+ height="1em"
147
+ >
148
+ <path
149
+ fill="currentColor"
150
+ d="M488.832 344.32l-339.84 356.672a32 32 0 0 0 0 44.16l.384.384a29.44 29.44 0 0 0 42.688 0l320-335.872 319.872 335.872a29.44 29.44 0 0 0 42.688 0l.384-.384a32 32 0 0 0 0-44.16L535.168 344.32a32 32 0 0 0-46.336 0z"
151
+ />
152
+ </svg>
153
+ </div>
103
154
  </div>
104
155
  </template>
105
156
 
@@ -147,4 +198,43 @@ watch(
147
198
  margin-bottom: 10px;
148
199
  cursor: pointer;
149
200
  }
201
+
202
+ .tag-count {
203
+ display: inline-flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ margin-left: 4px;
207
+ min-width: 16px;
208
+ height: 16px;
209
+ padding: 0 4px;
210
+ font-size: 10px;
211
+ line-height: 1;
212
+ border-radius: 8px;
213
+ background-color: rgba(255, 255, 255, 0.3);
214
+ }
215
+
216
+ .expand-btn {
217
+ display: flex;
218
+ align-items: center;
219
+ justify-content: center;
220
+ gap: 4px;
221
+ margin-top: 6px;
222
+ padding: 4px 0;
223
+ font-size: 12px;
224
+ color: var(--vp-c-text-2);
225
+ cursor: pointer;
226
+ transition: color 0.3s;
227
+ user-select: none;
228
+ }
229
+ .expand-btn:hover {
230
+ color: var(--vp-c-brand);
231
+ }
232
+
233
+ .expand-icon {
234
+ transition: transform 0.3s;
235
+ transform: rotate(180deg);
236
+ }
237
+ .expand-icon.is-expanded {
238
+ transform: rotate(0deg);
239
+ }
150
240
  </style>
@@ -659,5 +659,10 @@ export namespace Theme {
659
659
  * @default '🏷 标签'
660
660
  */
661
661
  title?: string
662
+ /**
663
+ * 首页标签默认展示数量,超出部分折叠
664
+ * @default 999
665
+ */
666
+ limit?: number
662
667
  }
663
668
  }
@@ -66,8 +66,10 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
66
66
 
67
67
  // 获取摘要信息
68
68
  // TODO:摘要生成优化,支持AI?
69
+ // 先去除 Markdown 中的标题行(# 开头),避免 description 中重复出现标题文字
70
+ const contentWithoutHeadings = content.replace(/^#+\s+.*$/gm, '')
69
71
  meta.description
70
- = meta.description || getTextSummary(content, 100) || excerpt
72
+ = meta.description || getTextSummary(contentWithoutHeadings, 100) || excerpt
71
73
 
72
74
  // 获取封面图
73
75
  // TODO: 耦合信息优化