@sugarat/theme 0.5.13 → 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 +10 -0
- package/node.js +5 -2
- package/node.mjs +5 -2
- package/package.json +6 -5
- package/src/components/BlogApp.vue +1 -7
- package/src/components/BlogHomeTags.vue +97 -7
- package/src/composables/config/index.ts +10 -0
- package/src/utils/node/theme.ts +3 -1
- package/src/utils/node/vitePlugins.ts +4 -0
package/node.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Repo, Mapping } from '@giscus/vue';
|
|
|
4
4
|
import { Options } from 'oh-my-live2d';
|
|
5
5
|
import { PagefindConfig } from 'vitepress-plugin-pagefind';
|
|
6
6
|
import { AnnouncementOptions } from 'vitepress-plugin-announcement';
|
|
7
|
+
import { ImagePreviewOptions } from 'vitepress-plugin-image-preview';
|
|
7
8
|
|
|
8
9
|
type RSSPluginOptions = RSSOptions;
|
|
9
10
|
type ThemeableImage = string | {
|
|
@@ -392,6 +393,10 @@ declare namespace Theme {
|
|
|
392
393
|
*/
|
|
393
394
|
alert?: Alert;
|
|
394
395
|
popover?: AnnouncementOptions;
|
|
396
|
+
/**
|
|
397
|
+
* 图片预览插件配置
|
|
398
|
+
*/
|
|
399
|
+
imagePreview?: ImagePreviewOptions;
|
|
395
400
|
friend?: FriendLink[] | FriendConfig;
|
|
396
401
|
authorList?: Omit<FriendLink, 'avatar'>[];
|
|
397
402
|
/**
|
|
@@ -617,6 +622,11 @@ declare namespace Theme {
|
|
|
617
622
|
* @default '🏷 标签'
|
|
618
623
|
*/
|
|
619
624
|
title?: string;
|
|
625
|
+
/**
|
|
626
|
+
* 首页标签默认展示数量,超出部分折叠
|
|
627
|
+
* @default 999
|
|
628
|
+
*/
|
|
629
|
+
limit?: number;
|
|
620
630
|
}
|
|
621
631
|
}
|
|
622
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.
|
|
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
|
-
|
|
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;
|
|
@@ -487,6 +488,7 @@ var import_vitepress_plugin_rss = require("vitepress-plugin-rss");
|
|
|
487
488
|
var import_theme_shared4 = require("@sugarat/theme-shared");
|
|
488
489
|
var import_vitepress_plugin_announcement = require("vitepress-plugin-announcement");
|
|
489
490
|
var import_vitepress_plugin_group_icons2 = require("vitepress-plugin-group-icons");
|
|
491
|
+
var import_vitepress_plugin_image_preview = require("vitepress-plugin-image-preview");
|
|
490
492
|
|
|
491
493
|
// src/utils/node/hot-reload-plugin.ts
|
|
492
494
|
var import_fs = __toESM(require("fs"));
|
|
@@ -569,6 +571,7 @@ function themeReloadPlugin() {
|
|
|
569
571
|
function getVitePlugins(cfg = {}) {
|
|
570
572
|
const plugins = [];
|
|
571
573
|
plugins.push(cacheAllGitTimestampsPlugin());
|
|
574
|
+
plugins.push((0, import_vitepress_plugin_image_preview.ImagePreviewPlugin)(cfg?.imagePreview));
|
|
572
575
|
if (cfg.themeColor) {
|
|
573
576
|
plugins.push(setThemeScript(cfg.themeColor));
|
|
574
577
|
}
|
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.
|
|
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
|
-
|
|
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;
|
|
@@ -456,6 +457,7 @@ import { RssPlugin } from "vitepress-plugin-rss";
|
|
|
456
457
|
import { cacheAllGitTimestamps, joinPath as joinPath2 } from "@sugarat/theme-shared";
|
|
457
458
|
import { AnnouncementPlugin } from "vitepress-plugin-announcement";
|
|
458
459
|
import { groupIconVitePlugin } from "vitepress-plugin-group-icons";
|
|
460
|
+
import { ImagePreviewPlugin } from "vitepress-plugin-image-preview";
|
|
459
461
|
|
|
460
462
|
// src/utils/node/hot-reload-plugin.ts
|
|
461
463
|
import fs2 from "fs";
|
|
@@ -538,6 +540,7 @@ function themeReloadPlugin() {
|
|
|
538
540
|
function getVitePlugins(cfg = {}) {
|
|
539
541
|
const plugins = [];
|
|
540
542
|
plugins.push(cacheAllGitTimestampsPlugin());
|
|
543
|
+
plugins.push(ImagePreviewPlugin(cfg?.imagePreview));
|
|
541
544
|
if (cfg.themeColor) {
|
|
542
545
|
plugins.push(setThemeScript(cfg.themeColor));
|
|
543
546
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"author": "sugar",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,9 +52,10 @@
|
|
|
52
52
|
"vitepress-plugin-mermaid": "2.0.13",
|
|
53
53
|
"vitepress-plugin-tabs": "0.7.3",
|
|
54
54
|
"@sugarat/theme-shared": "0.0.7",
|
|
55
|
-
"vitepress-plugin-
|
|
56
|
-
"vitepress-plugin-
|
|
57
|
-
"vitepress-plugin-
|
|
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"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"artalk": "^2.8.5",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"pagefind": "^1.3.0",
|
|
63
64
|
"typescript": "^5.4.5",
|
|
64
65
|
"vite": "^5.4.9",
|
|
65
|
-
"vitepress": "2.0.0-alpha.
|
|
66
|
+
"vitepress": "2.0.0-alpha.16",
|
|
66
67
|
"vue": "^3.5.24",
|
|
67
68
|
"vitepress-plugin-51la": "0.1.1"
|
|
68
69
|
},
|
|
@@ -8,7 +8,7 @@ import BlogHomeInfo from './BlogHomeInfo.vue'
|
|
|
8
8
|
import BlogHomeBanner from './BlogHomeBanner.vue'
|
|
9
9
|
import BlogList from './BlogList.vue'
|
|
10
10
|
import BlogSidebar from './BlogSidebar.vue'
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import BlogArticleAnalyze from './BlogArticleAnalyze.vue'
|
|
13
13
|
import BlogAlert from './BlogAlert.vue'
|
|
14
14
|
import BlogFooter from './BlogFooter.vue'
|
|
@@ -49,8 +49,6 @@ const openTransition = useDarkTransitionConfig()
|
|
|
49
49
|
<!-- 阅读时间分析 -->
|
|
50
50
|
<ClientOnly>
|
|
51
51
|
<BlogArticleAnalyze />
|
|
52
|
-
<!-- 图片预览 -->
|
|
53
|
-
<BlogImagePreview />
|
|
54
52
|
</ClientOnly>
|
|
55
53
|
</template>
|
|
56
54
|
|
|
@@ -128,10 +126,6 @@ const openTransition = useDarkTransitionConfig()
|
|
|
128
126
|
<!-- content -->
|
|
129
127
|
<template #page-top>
|
|
130
128
|
<slot name="page-top" />
|
|
131
|
-
<ClientOnly>
|
|
132
|
-
<!-- 图片预览 -->
|
|
133
|
-
<BlogImagePreview />
|
|
134
|
-
</ClientOnly>
|
|
135
129
|
</template>
|
|
136
130
|
<template #page-bottom>
|
|
137
131
|
<slot name="page-bottom" />
|
|
@@ -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
|
-
|
|
23
|
-
|
|
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 &&
|
|
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="(
|
|
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>
|
|
@@ -5,6 +5,7 @@ import type { Mapping, Repo } from '@giscus/vue'
|
|
|
5
5
|
import type { Options as Oml2dOptions } from 'oh-my-live2d'
|
|
6
6
|
import type { PagefindConfig } from 'vitepress-plugin-pagefind'
|
|
7
7
|
import type { AnnouncementOptions } from 'vitepress-plugin-announcement'
|
|
8
|
+
import type { ImagePreviewOptions } from 'vitepress-plugin-image-preview'
|
|
8
9
|
|
|
9
10
|
type RSSPluginOptions = RSSOptions
|
|
10
11
|
|
|
@@ -420,6 +421,10 @@ export namespace Theme {
|
|
|
420
421
|
*/
|
|
421
422
|
alert?: Alert
|
|
422
423
|
popover?: AnnouncementOptions
|
|
424
|
+
/**
|
|
425
|
+
* 图片预览插件配置
|
|
426
|
+
*/
|
|
427
|
+
imagePreview?: ImagePreviewOptions
|
|
423
428
|
friend?: FriendLink[] | FriendConfig
|
|
424
429
|
authorList?: Omit<FriendLink, 'avatar'>[]
|
|
425
430
|
/**
|
|
@@ -654,5 +659,10 @@ export namespace Theme {
|
|
|
654
659
|
* @default '🏷 标签'
|
|
655
660
|
*/
|
|
656
661
|
title?: string
|
|
662
|
+
/**
|
|
663
|
+
* 首页标签默认展示数量,超出部分折叠
|
|
664
|
+
* @default 999
|
|
665
|
+
*/
|
|
666
|
+
limit?: number
|
|
657
667
|
}
|
|
658
668
|
}
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -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(
|
|
72
|
+
= meta.description || getTextSummary(contentWithoutHeadings, 100) || excerpt
|
|
71
73
|
|
|
72
74
|
// 获取封面图
|
|
73
75
|
// TODO: 耦合信息优化
|
|
@@ -7,6 +7,7 @@ import type { PluginOption } from 'vite'
|
|
|
7
7
|
import { cacheAllGitTimestamps, joinPath } from '@sugarat/theme-shared'
|
|
8
8
|
import { AnnouncementPlugin } from 'vitepress-plugin-announcement'
|
|
9
9
|
import { groupIconVitePlugin } from 'vitepress-plugin-group-icons'
|
|
10
|
+
import { ImagePreviewPlugin } from 'vitepress-plugin-image-preview'
|
|
10
11
|
import type { Theme } from '../../composables/config/index'
|
|
11
12
|
import { _require } from './mdPlugins'
|
|
12
13
|
import { themeReloadPlugin } from './hot-reload-plugin'
|
|
@@ -18,6 +19,9 @@ export function getVitePlugins(cfg: Partial<Theme.BlogConfig> = {}) {
|
|
|
18
19
|
// 缓存所有文章的 git 提交时间
|
|
19
20
|
plugins.push(cacheAllGitTimestampsPlugin())
|
|
20
21
|
|
|
22
|
+
// 图片预览
|
|
23
|
+
plugins.push(ImagePreviewPlugin(cfg?.imagePreview))
|
|
24
|
+
|
|
21
25
|
// 处理自定义主题色
|
|
22
26
|
if (cfg.themeColor) {
|
|
23
27
|
plugins.push(setThemeScript(cfg.themeColor))
|