@sugarat/theme 0.1.41 → 0.1.43
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 +27 -4
- package/node.js +26 -10
- package/package.json +2 -2
- package/src/components/BlogApp.vue +57 -0
- package/src/components/BlogArticleAnalyze.vue +1 -1
- package/src/components/BlogComment.vue +21 -5
- package/src/components/BlogHotArticle.vue +1 -1
- package/src/components/BlogList.vue +30 -11
- package/src/components/BlogPopover.vue +8 -3
- package/src/components/BlogRecommendArticle.vue +1 -1
- package/src/components/BlogSearch.vue +2 -2
- package/src/components/UserWorks.vue +1 -1
- package/src/composables/config/blog.ts +19 -14
- package/src/composables/config/index.ts +35 -4
- package/src/index.ts +3 -0
- package/src/styles/index.scss +8 -7
- package/src/styles/scss/global.scss +1 -1
- package/src/styles/theme/inline-theme.var.css +56 -0
- package/src/utils/node/genFeed.ts +25 -6
- package/src/utils/node/mdPlugins.ts +15 -0
- package/src/utils/node/theme.ts +3 -3
package/node.d.ts
CHANGED
|
@@ -208,8 +208,15 @@ declare namespace Theme {
|
|
|
208
208
|
topTitle?: string;
|
|
209
209
|
list: UserWork[];
|
|
210
210
|
}
|
|
211
|
+
type ThemeColor = 'vp-default' | 'vp-green' | 'vp-yellow' | 'vp-red' | 'el-blue' | 'el-yellow' | 'el-green' | 'el-red';
|
|
211
212
|
interface BlogConfig {
|
|
212
213
|
blog?: false;
|
|
214
|
+
/**
|
|
215
|
+
* 内置一些主题色
|
|
216
|
+
* @default 'vp-default'
|
|
217
|
+
* 也可以自定义颜色,详见 TODO:文档
|
|
218
|
+
*/
|
|
219
|
+
themeColor?: ThemeColor;
|
|
213
220
|
pagesData: PageData[];
|
|
214
221
|
srcDir?: string;
|
|
215
222
|
author?: string;
|
|
@@ -260,22 +267,38 @@ declare namespace Theme {
|
|
|
260
267
|
*/
|
|
261
268
|
RSS?: RSSOptions;
|
|
262
269
|
}
|
|
263
|
-
type RSSOptions = FeedOptions & {
|
|
270
|
+
type RSSOptions = Omit<FeedOptions, 'id'> & {
|
|
271
|
+
id?: string;
|
|
272
|
+
/**
|
|
273
|
+
* 你的站点地址
|
|
274
|
+
* @example 'https://sugarat.top'
|
|
275
|
+
*/
|
|
264
276
|
baseUrl: string;
|
|
265
277
|
/**
|
|
266
278
|
* 线上访问的RSS地址
|
|
279
|
+
* @default
|
|
280
|
+
* @example https://sugarat.top/feed.rss
|
|
281
|
+
* ```ts
|
|
282
|
+
* `${baseUrl + VPConfig.site.base + (filename || 'feed.rss'}`
|
|
283
|
+
* ```
|
|
267
284
|
*/
|
|
268
|
-
url
|
|
285
|
+
url?: string;
|
|
269
286
|
/**
|
|
270
287
|
* 输出的RSS文件名
|
|
271
288
|
* @default 'feed.rss'
|
|
272
289
|
*/
|
|
273
290
|
filename?: string;
|
|
274
291
|
/**
|
|
275
|
-
*
|
|
292
|
+
* RSS的图标展示
|
|
276
293
|
* @default true
|
|
277
294
|
*/
|
|
278
|
-
|
|
295
|
+
icon?: boolean;
|
|
296
|
+
/**
|
|
297
|
+
* 限制输出文件包含的文章数量
|
|
298
|
+
* @default 0
|
|
299
|
+
* @description (0 不限制;> 1 会按照日期排序对输出内容进行调整)
|
|
300
|
+
*/
|
|
301
|
+
limit?: number;
|
|
279
302
|
};
|
|
280
303
|
interface Config extends DefaultTheme.Config {
|
|
281
304
|
blog?: BlogConfig;
|
package/node.js
CHANGED
|
@@ -32,7 +32,7 @@ __export(node_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(node_exports);
|
|
34
34
|
|
|
35
|
-
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.0-rc.
|
|
35
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.0-rc.11_vue@3.3.4/node_modules/vitepress-plugin-tabs/dist/index.js
|
|
36
36
|
var tabsMarker = "=tabs";
|
|
37
37
|
var tabsMarkerLen = tabsMarker.length;
|
|
38
38
|
var ruleBlockTabs = (state, startLine, endLine, silent) => {
|
|
@@ -352,6 +352,11 @@ function supportRunExtendsPlugin(config) {
|
|
|
352
352
|
markdownExtendsConfigOriginal?.(...rest);
|
|
353
353
|
};
|
|
354
354
|
}
|
|
355
|
+
const inlineConfig = config.extends;
|
|
356
|
+
if (inlineConfig.themeConfig?.blog?.RSS && inlineConfig.themeConfig?.blog?.RSS?.icon !== false && inlineConfig.themeConfig?.socialLinks?.length && !inlineConfig.themeConfig?.socialLinks?.[0].link) {
|
|
357
|
+
const { RSS } = inlineConfig.themeConfig?.blog;
|
|
358
|
+
inlineConfig.themeConfig.socialLinks[0].link = `${RSS.baseUrl}${(config.base || "/") + (RSS.filename || "feed.rss")}`;
|
|
359
|
+
}
|
|
355
360
|
}
|
|
356
361
|
|
|
357
362
|
// src/utils/node/theme.ts
|
|
@@ -430,13 +435,13 @@ function getArticles(cfg) {
|
|
|
430
435
|
}
|
|
431
436
|
function patchVPThemeConfig(cfg, vpThemeConfig = {}) {
|
|
432
437
|
const RSS = cfg?.RSS;
|
|
433
|
-
if (RSS && RSS.
|
|
438
|
+
if (RSS && RSS.icon !== false) {
|
|
434
439
|
vpThemeConfig.socialLinks = [
|
|
435
440
|
{
|
|
436
441
|
icon: {
|
|
437
442
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 448 512"><path d="M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM112 416c-26.51 0-48-21.49-48-48s21.49-48 48-48s48 21.49 48 48s-21.49 48-48 48zm157.533 0h-34.335c-6.011 0-11.051-4.636-11.442-10.634c-5.214-80.05-69.243-143.92-149.123-149.123c-5.997-.39-10.633-5.431-10.633-11.441v-34.335c0-6.535 5.468-11.777 11.994-11.425c110.546 5.974 198.997 94.536 204.964 204.964c.352 6.526-4.89 11.994-11.425 11.994zm103.027 0h-34.334c-6.161 0-11.175-4.882-11.427-11.038c-5.598-136.535-115.204-246.161-251.76-251.76C68.882 152.949 64 147.935 64 141.774V107.44c0-6.454 5.338-11.664 11.787-11.432c167.83 6.025 302.21 141.191 308.205 308.205c.232 6.449-4.978 11.787-11.432 11.787z" fill="currentColor"></path></svg>'
|
|
438
443
|
},
|
|
439
|
-
link: RSS
|
|
444
|
+
link: RSS?.url
|
|
440
445
|
}
|
|
441
446
|
];
|
|
442
447
|
}
|
|
@@ -454,7 +459,7 @@ var import_fs2 = __toESM(require("fs"));
|
|
|
454
459
|
var import_feed = require("feed");
|
|
455
460
|
async function genFeed(config) {
|
|
456
461
|
const blogCfg = config.userConfig.themeConfig.blog;
|
|
457
|
-
|
|
462
|
+
let posts = blogCfg.pagesData;
|
|
458
463
|
const { RSS, authorList = [] } = blogCfg;
|
|
459
464
|
if (!RSS)
|
|
460
465
|
return;
|
|
@@ -469,14 +474,20 @@ async function genFeed(config) {
|
|
|
469
474
|
console.log("=== feed: https://github.com/jpmonette/feed ===");
|
|
470
475
|
const { base } = config.userConfig;
|
|
471
476
|
const { baseUrl, filename } = RSS;
|
|
472
|
-
const feed = new import_feed.Feed(
|
|
477
|
+
const feed = new import_feed.Feed({
|
|
478
|
+
id: baseUrl,
|
|
479
|
+
link: baseUrl,
|
|
480
|
+
...RSS
|
|
481
|
+
});
|
|
473
482
|
posts.sort(
|
|
474
483
|
(a, b) => +new Date(b.meta.date) - +new Date(a.meta.date)
|
|
475
484
|
);
|
|
485
|
+
posts = posts.filter((v) => v.meta.layout !== "home").filter((v) => v.meta.hidden !== true);
|
|
486
|
+
if (void 0 !== RSS?.limit && RSS?.limit > 0) {
|
|
487
|
+
posts.splice(RSS.limit);
|
|
488
|
+
}
|
|
476
489
|
for (const { route, meta } of posts) {
|
|
477
|
-
const { title, description, date
|
|
478
|
-
if (hidden)
|
|
479
|
-
continue;
|
|
490
|
+
const { title, description, date } = meta;
|
|
480
491
|
const author = meta.author ?? blogCfg.author;
|
|
481
492
|
let link = `${baseUrl}${withBase(
|
|
482
493
|
base || "",
|
|
@@ -505,9 +516,14 @@ async function genFeed(config) {
|
|
|
505
516
|
date: new Date(date)
|
|
506
517
|
});
|
|
507
518
|
}
|
|
508
|
-
const
|
|
519
|
+
const RSSFilename = filename || "feed.rss";
|
|
520
|
+
const RSSFile = import_path2.default.join(config.outDir, RSSFilename);
|
|
509
521
|
(0, import_fs2.writeFileSync)(RSSFile, feed.rss2());
|
|
510
|
-
console.log("\u{1F389} RSS generated",
|
|
522
|
+
console.log("\u{1F389} RSS generated", RSSFilename);
|
|
523
|
+
console.log("rss filepath:", RSSFile);
|
|
524
|
+
console.log("rss url:", `${baseUrl}${config.site.base + RSSFilename}`);
|
|
525
|
+
console.log("include", posts.length, "posts");
|
|
526
|
+
console.log();
|
|
511
527
|
console.log();
|
|
512
528
|
}
|
|
513
529
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"sass": "^1.56.1",
|
|
52
52
|
"tsup": " ^6.5.0",
|
|
53
53
|
"typescript": "^4.8.2",
|
|
54
|
-
"vitepress": "1.0.0-rc.
|
|
54
|
+
"vitepress": "1.0.0-rc.11",
|
|
55
55
|
"vitepress-plugin-tabs": "^0.2.0",
|
|
56
56
|
"vue": "^3.3.4"
|
|
57
57
|
},
|
|
@@ -24,6 +24,7 @@ const { Layout } = Theme
|
|
|
24
24
|
</template>
|
|
25
25
|
|
|
26
26
|
<template #doc-before>
|
|
27
|
+
<slot name="doc-before" />
|
|
27
28
|
<!-- 阅读时间分析 -->
|
|
28
29
|
<ClientOnly>
|
|
29
30
|
<BlogArticleAnalyze />
|
|
@@ -34,10 +35,12 @@ const { Layout } = Theme
|
|
|
34
35
|
|
|
35
36
|
<!-- 自定义搜索,替代Algolia,未来择机移除 -->
|
|
36
37
|
<template #nav-bar-content-before>
|
|
38
|
+
<slot name="nav-bar-content-before" />
|
|
37
39
|
<BlogSearch />
|
|
38
40
|
</template>
|
|
39
41
|
<!-- 自定义首页 -->
|
|
40
42
|
<template #home-hero-before v-if="isBlogTheme">
|
|
43
|
+
<slot name="home-hero-before" />
|
|
41
44
|
<div class="home">
|
|
42
45
|
<div class="header-banner">
|
|
43
46
|
<BlogHomeBanner />
|
|
@@ -51,12 +54,66 @@ const { Layout } = Theme
|
|
|
51
54
|
</div>
|
|
52
55
|
</template>
|
|
53
56
|
<template #sidebar-nav-after v-if="isBlogTheme">
|
|
57
|
+
<slot name="sidebar-nav-after" />
|
|
54
58
|
<BlogSidebar />
|
|
55
59
|
</template>
|
|
56
60
|
<!-- 评论 -->
|
|
57
61
|
<template #doc-after>
|
|
62
|
+
<slot name="doc-after" />
|
|
58
63
|
<BlogComment />
|
|
59
64
|
</template>
|
|
65
|
+
|
|
66
|
+
<!-- 透传默认主题的其它插槽 -->
|
|
67
|
+
<!-- navbar -->
|
|
68
|
+
<template #nav-bar-title-before
|
|
69
|
+
><slot name="nav-bar-title-before"
|
|
70
|
+
/></template>
|
|
71
|
+
<template #nav-bar-title-after
|
|
72
|
+
><slot name="nav-bar-title-after"
|
|
73
|
+
/></template>
|
|
74
|
+
<template #nav-bar-content-after
|
|
75
|
+
><slot name="nav-bar-content-after"
|
|
76
|
+
/></template>
|
|
77
|
+
<template #nav-screen-content-before
|
|
78
|
+
><slot name="nav-screen-content-before"
|
|
79
|
+
/></template>
|
|
80
|
+
<template #nav-screen-content-after
|
|
81
|
+
><slot name="nav-screen-content-after"
|
|
82
|
+
/></template>
|
|
83
|
+
|
|
84
|
+
<!-- sidebar -->
|
|
85
|
+
<template #sidebar-nav-before><slot name="sidebar-nav-before" /></template>
|
|
86
|
+
|
|
87
|
+
<!-- content -->
|
|
88
|
+
<template #page-top><slot name="page-top" /></template>
|
|
89
|
+
<template #page-bottom><slot name="page-bottom" /></template>
|
|
90
|
+
|
|
91
|
+
<template #not-found><slot name="not-found" /></template>
|
|
92
|
+
<template #home-hero-info><slot name="home-hero-info" /></template>
|
|
93
|
+
<template #home-hero-image><slot name="home-hero-image" /></template>
|
|
94
|
+
<template #home-hero-after><slot name="home-hero-after" /></template>
|
|
95
|
+
<template #home-features-before
|
|
96
|
+
><slot name="home-features-before"
|
|
97
|
+
/></template>
|
|
98
|
+
<template #home-features-after
|
|
99
|
+
><slot name="home-features-after"
|
|
100
|
+
/></template>
|
|
101
|
+
|
|
102
|
+
<template #doc-footer-before><slot name="doc-footer-before" /></template>
|
|
103
|
+
|
|
104
|
+
<template #doc-top><slot name="doc-top" /></template>
|
|
105
|
+
<template #doc-bottom><slot name="doc-bottom" /></template>
|
|
106
|
+
|
|
107
|
+
<template #aside-top><slot name="aside-top" /></template>
|
|
108
|
+
<template #aside-bottom><slot name="aside-bottom" /></template>
|
|
109
|
+
<template #aside-outline-before
|
|
110
|
+
><slot name="aside-outline-before"
|
|
111
|
+
/></template>
|
|
112
|
+
<template #aside-outline-after
|
|
113
|
+
><slot name="aside-outline-after"
|
|
114
|
+
/></template>
|
|
115
|
+
<template #aside-ads-before><slot name="aside-ads-before" /></template>
|
|
116
|
+
<template #aside-ads-after><slot name="aside-ads-after" /></template>
|
|
60
117
|
</Layout>
|
|
61
118
|
</template>
|
|
62
119
|
<style scoped lang="scss">
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
</div>
|
|
44
44
|
</template>
|
|
45
45
|
<script setup lang="ts">
|
|
46
|
-
import {
|
|
46
|
+
import { useElementVisibility } from '@vueuse/core'
|
|
47
47
|
import { useData, useRoute } from 'vitepress'
|
|
48
|
-
import { computed, ref, watch } from 'vue'
|
|
48
|
+
import { computed, nextTick, ref, watch } from 'vue'
|
|
49
49
|
import { ElAffix, ElButton } from 'element-plus'
|
|
50
50
|
import { Comment } from '@element-plus/icons-vue'
|
|
51
51
|
import { useGiscusConfig } from '../composables/config/blog'
|
|
@@ -85,9 +85,7 @@ const show = computed(() => {
|
|
|
85
85
|
)
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
const isDark =
|
|
89
|
-
storageKey: 'vitepress-theme-appearance'
|
|
90
|
-
})
|
|
88
|
+
const { isDark } = useData()
|
|
91
89
|
|
|
92
90
|
const route = useRoute()
|
|
93
91
|
const showComment = ref(true)
|
|
@@ -103,12 +101,30 @@ watch(
|
|
|
103
101
|
immediate: true
|
|
104
102
|
}
|
|
105
103
|
)
|
|
104
|
+
|
|
105
|
+
// TODO:可以优化,不需要重载
|
|
106
|
+
watch(isDark, () => {
|
|
107
|
+
showComment.value = false
|
|
108
|
+
nextTick(() => {
|
|
109
|
+
showComment.value = true
|
|
110
|
+
})
|
|
111
|
+
})
|
|
106
112
|
</script>
|
|
107
113
|
<style scoped lang="scss">
|
|
108
114
|
.comment {
|
|
109
115
|
width: 100%;
|
|
110
116
|
text-align: center;
|
|
111
117
|
padding: 40px 0;
|
|
118
|
+
:deep(.el-button.el-button--primary:hover) {
|
|
119
|
+
background-color: var(--vp-c-brand-2);
|
|
120
|
+
border-color: var(--vp-c-brand-2);
|
|
121
|
+
color: #fff;
|
|
122
|
+
}
|
|
123
|
+
:deep(.el-button.el-button--primary) {
|
|
124
|
+
background-color: var(--vp-c-brand-soft);
|
|
125
|
+
border-color: var(--vp-c-brand-2);
|
|
126
|
+
color: var(--vp-c-brand-2);
|
|
127
|
+
}
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
.hidden {
|
|
@@ -16,17 +16,19 @@
|
|
|
16
16
|
</ul>
|
|
17
17
|
<!-- 解决element-ui bug -->
|
|
18
18
|
<ClientOnly>
|
|
19
|
-
<el-pagination
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
<div class="el-pagination-wrapper">
|
|
20
|
+
<el-pagination
|
|
21
|
+
v-if="wikiList.length >= pageSize"
|
|
22
|
+
small
|
|
23
|
+
background
|
|
24
|
+
:default-current-page="1"
|
|
25
|
+
:current-page="currentPage"
|
|
26
|
+
@update:current-page="handleUpdatePageNum"
|
|
27
|
+
:page-size="pageSize"
|
|
28
|
+
:total="filterData.length"
|
|
29
|
+
layout="prev, pager, next, jumper"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
30
32
|
</ClientOnly>
|
|
31
33
|
</template>
|
|
32
34
|
<script setup lang="ts">
|
|
@@ -116,3 +118,20 @@ watch(
|
|
|
116
118
|
}
|
|
117
119
|
)
|
|
118
120
|
</script>
|
|
121
|
+
<style lang="scss" scoped>
|
|
122
|
+
.el-pagination-wrapper {
|
|
123
|
+
:deep(.el-pagination li.is-active.number) {
|
|
124
|
+
background-color: var(--vp-c-brand-2);
|
|
125
|
+
}
|
|
126
|
+
:deep(.el-pagination button:hover) {
|
|
127
|
+
color: var(--vp-c-brand-2);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
:deep(.el-pager li:not(.is-active):hover) {
|
|
131
|
+
color: var(--vp-c-brand-2);
|
|
132
|
+
}
|
|
133
|
+
:deep(.el-input__wrapper.is-focus) {
|
|
134
|
+
box-shadow: 0 0 0 1px var(--vp-c-brand-2) inset;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
</style>
|
|
@@ -132,16 +132,21 @@ const PopoverValue = (
|
|
|
132
132
|
|
|
133
133
|
<style lang="scss" scoped>
|
|
134
134
|
.theme-blog-popover {
|
|
135
|
+
color: rgba(60, 60, 67);
|
|
135
136
|
width: 258px;
|
|
136
137
|
position: fixed;
|
|
137
138
|
top: 80px;
|
|
138
139
|
right: 20px;
|
|
139
140
|
z-index: 19;
|
|
140
141
|
box-sizing: border-box;
|
|
141
|
-
border: 1px solid var(--
|
|
142
|
+
border: 1px solid var(--vp-c-brand-3);
|
|
142
143
|
border-radius: 6px;
|
|
143
144
|
background-color: rgba(var(--bg-gradient-home));
|
|
144
145
|
box-shadow: var(--box-shadow);
|
|
146
|
+
:deep(.el-button.el-button--primary) {
|
|
147
|
+
background-color: var(--vp-c-brand-2);
|
|
148
|
+
border-color: var(--vp-c-brand-2);
|
|
149
|
+
}
|
|
145
150
|
}
|
|
146
151
|
@media screen and (min-width: 760px) and (max-width: 1140px) {
|
|
147
152
|
.theme-blog-popover {
|
|
@@ -149,7 +154,7 @@ const PopoverValue = (
|
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
.header {
|
|
152
|
-
background-color: var(--
|
|
157
|
+
background-color: var(--vp-c-brand-3);
|
|
153
158
|
color: #fff;
|
|
154
159
|
padding: 6px 4px;
|
|
155
160
|
display: flex;
|
|
@@ -207,7 +212,7 @@ const PopoverValue = (
|
|
|
207
212
|
top: 80px;
|
|
208
213
|
right: 10px;
|
|
209
214
|
position: fixed;
|
|
210
|
-
background-color: var(--
|
|
215
|
+
background-color: var(--vp-c-brand-3);
|
|
211
216
|
padding: 8px;
|
|
212
217
|
color: #fff;
|
|
213
218
|
font-size: 12px;
|
|
@@ -362,7 +362,7 @@ const handleSelect = (target: any) => {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
&:hover {
|
|
365
|
-
border: 1px solid var(--vp-c-brand);
|
|
365
|
+
border: 1px solid var(--vp-c-brand-1);
|
|
366
366
|
border-radius: 6px;
|
|
367
367
|
}
|
|
368
368
|
|
|
@@ -406,7 +406,7 @@ div[command-item] {
|
|
|
406
406
|
}
|
|
407
407
|
div[command-item] mark {
|
|
408
408
|
background: none;
|
|
409
|
-
color: var(--vp-c-brand);
|
|
409
|
+
color: var(--vp-c-brand-1);
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
div[command-item][aria-selected='true'] mark,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
reactive,
|
|
14
14
|
ref
|
|
15
15
|
} from 'vue'
|
|
16
|
+
import { useColorMode } from '@vueuse/core'
|
|
16
17
|
|
|
17
18
|
import type { Theme } from './index'
|
|
18
19
|
|
|
@@ -21,22 +22,13 @@ const configSymbol: InjectionKey<Ref<Theme.Config>> = Symbol('theme-config')
|
|
|
21
22
|
const activeTagSymbol: InjectionKey<Ref<Theme.activeTag>> = Symbol('active-tag')
|
|
22
23
|
|
|
23
24
|
const currentPageNum: InjectionKey<Ref<number>> = Symbol('home-page-num')
|
|
24
|
-
const homeConfigSymbol: InjectionKey<Theme.HomeConfig> = Symbol('home-config')
|
|
25
25
|
|
|
26
26
|
const userWorks: InjectionKey<Ref<Theme.UserWorks>> = Symbol('user-works')
|
|
27
27
|
|
|
28
28
|
export function withConfigProvider(App: Component) {
|
|
29
29
|
return defineComponent({
|
|
30
30
|
name: 'ConfigProvider',
|
|
31
|
-
|
|
32
|
-
handleChangeSlogan: {
|
|
33
|
-
type: Function,
|
|
34
|
-
required: false
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
setup(props, { slots }) {
|
|
38
|
-
provide(homeConfigSymbol, props as Theme.HomeConfig)
|
|
39
|
-
|
|
31
|
+
setup(_, { slots }) {
|
|
40
32
|
const { theme } = useData()
|
|
41
33
|
const config = computed(() => resolveConfig(theme.value))
|
|
42
34
|
provide(configSymbol, config)
|
|
@@ -59,6 +51,22 @@ export function withConfigProvider(App: Component) {
|
|
|
59
51
|
|
|
60
52
|
const pageNum = ref(1)
|
|
61
53
|
provide(currentPageNum, pageNum)
|
|
54
|
+
|
|
55
|
+
const mode = useColorMode({
|
|
56
|
+
attribute: 'theme',
|
|
57
|
+
modes: {
|
|
58
|
+
// 内置的颜色主题
|
|
59
|
+
'vp-default': 'vp-default',
|
|
60
|
+
'vp-green': 'vp-green',
|
|
61
|
+
'vp-yellow': 'vp-yellow',
|
|
62
|
+
'vp-red': 'vp-red',
|
|
63
|
+
'el-blue': 'el-blue',
|
|
64
|
+
'el-yellow': 'el-yellow',
|
|
65
|
+
'el-green': 'el-green',
|
|
66
|
+
'el-red': 'el-red'
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
mode.value = config.value.blog?.themeColor ?? 'vp-default'
|
|
62
70
|
return () => h(App, null, slots)
|
|
63
71
|
}
|
|
64
72
|
})
|
|
@@ -77,9 +85,6 @@ export function useBlogConfig() {
|
|
|
77
85
|
export function useBlogThemeMode() {
|
|
78
86
|
return inject(configSymbol)!.value?.blog?.blog ?? true
|
|
79
87
|
}
|
|
80
|
-
export function useHomeConfig() {
|
|
81
|
-
return inject(homeConfigSymbol)!
|
|
82
|
-
}
|
|
83
88
|
|
|
84
89
|
export function useGiscusConfig() {
|
|
85
90
|
const blogConfig = useConfig()
|
|
@@ -141,7 +146,7 @@ export function useActiveAnchor() {
|
|
|
141
146
|
onMounted(() => {
|
|
142
147
|
const { hash } = window.location
|
|
143
148
|
if (hash) {
|
|
144
|
-
el.value = document.querySelector(decodeURIComponent(hash))
|
|
149
|
+
el.value = document.querySelector(decodeURIComponent(hash)) as any
|
|
145
150
|
}
|
|
146
151
|
})
|
|
147
152
|
return el
|
|
@@ -228,8 +228,23 @@ export namespace Theme {
|
|
|
228
228
|
topTitle?: string
|
|
229
229
|
list: UserWork[]
|
|
230
230
|
}
|
|
231
|
+
export type ThemeColor =
|
|
232
|
+
| 'vp-default'
|
|
233
|
+
| 'vp-green'
|
|
234
|
+
| 'vp-yellow'
|
|
235
|
+
| 'vp-red'
|
|
236
|
+
| 'el-blue'
|
|
237
|
+
| 'el-yellow'
|
|
238
|
+
| 'el-green'
|
|
239
|
+
| 'el-red'
|
|
231
240
|
export interface BlogConfig {
|
|
232
241
|
blog?: false
|
|
242
|
+
/**
|
|
243
|
+
* 内置一些主题色
|
|
244
|
+
* @default 'vp-default'
|
|
245
|
+
* 也可以自定义颜色,详见 TODO:文档
|
|
246
|
+
*/
|
|
247
|
+
themeColor?: ThemeColor
|
|
233
248
|
pagesData: PageData[]
|
|
234
249
|
srcDir?: string
|
|
235
250
|
author?: string
|
|
@@ -281,22 +296,38 @@ export namespace Theme {
|
|
|
281
296
|
RSS?: RSSOptions
|
|
282
297
|
}
|
|
283
298
|
|
|
284
|
-
export type RSSOptions = FeedOptions & {
|
|
299
|
+
export type RSSOptions = Omit<FeedOptions, 'id'> & {
|
|
300
|
+
id?: string
|
|
301
|
+
/**
|
|
302
|
+
* 你的站点地址
|
|
303
|
+
* @example 'https://sugarat.top'
|
|
304
|
+
*/
|
|
285
305
|
baseUrl: string
|
|
286
306
|
/**
|
|
287
307
|
* 线上访问的RSS地址
|
|
308
|
+
* @default
|
|
309
|
+
* @example https://sugarat.top/feed.rss
|
|
310
|
+
* ```ts
|
|
311
|
+
* `${baseUrl + VPConfig.site.base + (filename || 'feed.rss'}`
|
|
312
|
+
* ```
|
|
288
313
|
*/
|
|
289
|
-
url
|
|
314
|
+
url?: string
|
|
290
315
|
/**
|
|
291
316
|
* 输出的RSS文件名
|
|
292
317
|
* @default 'feed.rss'
|
|
293
318
|
*/
|
|
294
319
|
filename?: string
|
|
295
320
|
/**
|
|
296
|
-
*
|
|
321
|
+
* RSS的图标展示
|
|
297
322
|
* @default true
|
|
298
323
|
*/
|
|
299
|
-
|
|
324
|
+
icon?: boolean
|
|
325
|
+
/**
|
|
326
|
+
* 限制输出文件包含的文章数量
|
|
327
|
+
* @default 0
|
|
328
|
+
* @description (0 不限制;> 1 会按照日期排序对输出内容进行调整)
|
|
329
|
+
*/
|
|
330
|
+
limit?: number
|
|
300
331
|
}
|
|
301
332
|
export interface Config extends DefaultTheme.Config {
|
|
302
333
|
blog?: BlogConfig
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,9 @@ import { withConfigProvider } from './composables/config/blog'
|
|
|
14
14
|
import TimelinePage from './components/TimelinePage.vue'
|
|
15
15
|
import UserWorksPage from './components/UserWorks.vue'
|
|
16
16
|
|
|
17
|
+
// 内置一些特殊的主题色
|
|
18
|
+
import './styles/theme/inline-theme.var.css'
|
|
19
|
+
|
|
17
20
|
export const BlogTheme: Theme = {
|
|
18
21
|
...DefaultTheme,
|
|
19
22
|
Layout: withConfigProvider(BlogApp),
|
package/src/styles/index.scss
CHANGED
|
@@ -8,7 +8,8 @@ html {
|
|
|
8
8
|
--nav-bgc: rgba(255, 255, 255, 0.9);
|
|
9
9
|
--badge-font-color: #4e5969;
|
|
10
10
|
--description-font-color: #86909c;
|
|
11
|
-
--blog-theme-color:
|
|
11
|
+
--blog-theme-color: var(--vp-c-brand-1);
|
|
12
|
+
// --blog-theme-color: #409eff;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
html[class='dark'] {
|
|
@@ -105,8 +106,8 @@ html[class='dark'] {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
::-webkit-scrollbar {
|
|
108
|
-
width:
|
|
109
|
-
height:
|
|
109
|
+
width: 4px;
|
|
110
|
+
height: 4px;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
::-webkit-scrollbar-track-piece {
|
|
@@ -114,13 +115,13 @@ html[class='dark'] {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
::-webkit-scrollbar-thumb:vertical {
|
|
117
|
-
height:
|
|
118
|
+
height: 4px;
|
|
118
119
|
border-radius: 4px;
|
|
119
|
-
background-color: var(--
|
|
120
|
+
background-color: var(--vp-c-brand-1);
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
::-webkit-scrollbar-thumb:horizontal {
|
|
123
|
-
width:
|
|
124
|
+
width: 4px;
|
|
124
125
|
border-radius: 4px;
|
|
125
|
-
background-color: var(--
|
|
126
|
+
background-color: var(--vp-c-brand-1);
|
|
126
127
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* 所有变量:https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */
|
|
2
|
+
|
|
3
|
+
/* VitePress 绿色 */
|
|
4
|
+
html[theme="vp-green"] {
|
|
5
|
+
--vp-c-brand-1: var(--vp-c-green-1);
|
|
6
|
+
--vp-c-brand-2: var(--vp-c-green-2);
|
|
7
|
+
--vp-c-brand-3: var(--vp-c-green-3);
|
|
8
|
+
--vp-c-brand-soft: var(--vp-c-green-soft);
|
|
9
|
+
}
|
|
10
|
+
/* VitePress 黄色 */
|
|
11
|
+
html[theme="vp-yellow"]{
|
|
12
|
+
--vp-c-brand-1: var(--vp-c-yellow-1);
|
|
13
|
+
--vp-c-brand-2: var(--vp-c-yellow-2);
|
|
14
|
+
--vp-c-brand-3: var(--vp-c-yellow-3);
|
|
15
|
+
--vp-c-brand-soft: var(--vp-c-yellow-soft);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* VitePress 红色 */
|
|
19
|
+
html[theme="vp-red"]{
|
|
20
|
+
--vp-c-brand-1: var(--vp-c-red-1);
|
|
21
|
+
--vp-c-brand-2: var(--vp-c-red-2);
|
|
22
|
+
--vp-c-brand-3: var(--vp-c-red-3);
|
|
23
|
+
--vp-c-brand-soft: var(--vp-c-red-soft);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* element plus 蓝色 */
|
|
27
|
+
html[theme="el-blue"]{
|
|
28
|
+
--vp-c-brand-1: var(--el-color-primary);
|
|
29
|
+
--vp-c-brand-2: var(--el-color-primary-light-3);
|
|
30
|
+
--vp-c-brand-3: var(--el-color-primary-light-5);
|
|
31
|
+
--vp-c-brand-soft: var(--el-color-primary-light-9);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* element plus 绿色 */
|
|
35
|
+
html[theme="el-green"]{
|
|
36
|
+
--vp-c-brand-1: var(--el-color-success);
|
|
37
|
+
--vp-c-brand-2: var(--el-color-success-light-3);
|
|
38
|
+
--vp-c-brand-3: var(--el-color-success-light-5);
|
|
39
|
+
--vp-c-brand-soft: var(--el-color-success-light-9);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* element plus 黄色 */
|
|
43
|
+
html[theme="el-yellow"]{
|
|
44
|
+
--vp-c-brand-1: var(--el-color-warning);
|
|
45
|
+
--vp-c-brand-2: var(--el-color-warning-light-3);
|
|
46
|
+
--vp-c-brand-3: var(--el-color-warning-light-5);
|
|
47
|
+
--vp-c-brand-soft: var(--el-color-warning-light-9);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* element plus 红色 */
|
|
51
|
+
html[theme="el-red"]{
|
|
52
|
+
--vp-c-brand-1: var(--el-color-danger);
|
|
53
|
+
--vp-c-brand-2: var(--el-color-danger-light-3);
|
|
54
|
+
--vp-c-brand-3: var(--el-color-danger-light-5);
|
|
55
|
+
--vp-c-brand-soft: var(--el-color-danger-light-9);
|
|
56
|
+
}
|
|
@@ -9,7 +9,7 @@ import { pageMap } from './theme'
|
|
|
9
9
|
|
|
10
10
|
export async function genFeed(config: SiteConfig) {
|
|
11
11
|
const blogCfg: Theme.BlogConfig = config.userConfig.themeConfig.blog
|
|
12
|
-
|
|
12
|
+
let posts: Theme.PageData[] = blogCfg.pagesData
|
|
13
13
|
const { RSS, authorList = [] } = blogCfg
|
|
14
14
|
if (!RSS) return
|
|
15
15
|
const { createMarkdownRenderer } = await import('vitepress')
|
|
@@ -25,16 +25,30 @@ export async function genFeed(config: SiteConfig) {
|
|
|
25
25
|
const { base } = config.userConfig
|
|
26
26
|
|
|
27
27
|
const { baseUrl, filename } = RSS
|
|
28
|
-
const feed = new Feed(
|
|
28
|
+
const feed = new Feed({
|
|
29
|
+
id: baseUrl,
|
|
30
|
+
link: baseUrl,
|
|
31
|
+
...RSS
|
|
32
|
+
})
|
|
29
33
|
|
|
30
34
|
posts.sort(
|
|
31
35
|
(a, b) =>
|
|
32
36
|
+new Date(b.meta.date as string) - +new Date(a.meta.date as string)
|
|
33
37
|
)
|
|
34
38
|
|
|
39
|
+
posts = posts
|
|
40
|
+
// 过滤掉 layout:home
|
|
41
|
+
.filter((v) => v.meta.layout !== 'home')
|
|
42
|
+
// 过滤掉不展示的
|
|
43
|
+
.filter((v) => v.meta.hidden !== true)
|
|
44
|
+
|
|
45
|
+
if (undefined !== RSS?.limit && RSS?.limit > 0) {
|
|
46
|
+
posts.splice(RSS.limit)
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
for (const { route, meta } of posts) {
|
|
36
|
-
const { title, description, date
|
|
37
|
-
|
|
50
|
+
const { title, description, date } = meta
|
|
51
|
+
|
|
38
52
|
const author = meta.author ?? blogCfg.author
|
|
39
53
|
let link = `${baseUrl}${withBase(
|
|
40
54
|
base || '',
|
|
@@ -68,8 +82,13 @@ export async function genFeed(config: SiteConfig) {
|
|
|
68
82
|
date: new Date(date)
|
|
69
83
|
})
|
|
70
84
|
}
|
|
71
|
-
const
|
|
85
|
+
const RSSFilename = filename || 'feed.rss'
|
|
86
|
+
const RSSFile = path.join(config.outDir, RSSFilename)
|
|
72
87
|
writeFileSync(RSSFile, feed.rss2())
|
|
73
|
-
console.log('🎉 RSS generated',
|
|
88
|
+
console.log('🎉 RSS generated', RSSFilename)
|
|
89
|
+
console.log('rss filepath:', RSSFile)
|
|
90
|
+
console.log('rss url:', `${baseUrl}${config.site.base + RSSFilename}`)
|
|
91
|
+
console.log('include', posts.length, 'posts')
|
|
92
|
+
console.log()
|
|
74
93
|
console.log()
|
|
75
94
|
}
|
|
@@ -92,4 +92,19 @@ export function supportRunExtendsPlugin(config: UserConfig<Theme.Config>) {
|
|
|
92
92
|
markdownExtendsConfigOriginal?.(...rest)
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
// 特殊处理RSS,自动生成url(未来统一维护到 RSS插件里,待下一版主题架构升级)
|
|
97
|
+
const inlineConfig = config.extends as UserConfig<Theme.Config>
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
inlineConfig.themeConfig?.blog?.RSS &&
|
|
101
|
+
inlineConfig.themeConfig?.blog?.RSS?.icon !== false &&
|
|
102
|
+
inlineConfig.themeConfig?.socialLinks?.length &&
|
|
103
|
+
!inlineConfig.themeConfig?.socialLinks?.[0].link
|
|
104
|
+
) {
|
|
105
|
+
const { RSS } = inlineConfig.themeConfig?.blog
|
|
106
|
+
inlineConfig.themeConfig.socialLinks[0].link = `${RSS.baseUrl}${
|
|
107
|
+
(config.base || '/') + (RSS.filename || 'feed.rss')
|
|
108
|
+
}`
|
|
109
|
+
}
|
|
95
110
|
}
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -127,15 +127,15 @@ export function patchVPThemeConfig(
|
|
|
127
127
|
cfg?: Partial<Theme.BlogConfig>,
|
|
128
128
|
vpThemeConfig: any = {}
|
|
129
129
|
) {
|
|
130
|
-
// 添加 icon
|
|
130
|
+
// 添加 RSS icon
|
|
131
131
|
const RSS = cfg?.RSS
|
|
132
|
-
if (RSS && RSS.
|
|
132
|
+
if (RSS && RSS.icon !== false) {
|
|
133
133
|
vpThemeConfig.socialLinks = [
|
|
134
134
|
{
|
|
135
135
|
icon: {
|
|
136
136
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 448 512"><path d="M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM112 416c-26.51 0-48-21.49-48-48s21.49-48 48-48s48 21.49 48 48s-21.49 48-48 48zm157.533 0h-34.335c-6.011 0-11.051-4.636-11.442-10.634c-5.214-80.05-69.243-143.92-149.123-149.123c-5.997-.39-10.633-5.431-10.633-11.441v-34.335c0-6.535 5.468-11.777 11.994-11.425c110.546 5.974 198.997 94.536 204.964 204.964c.352 6.526-4.89 11.994-11.425 11.994zm103.027 0h-34.334c-6.161 0-11.175-4.882-11.427-11.038c-5.598-136.535-115.204-246.161-251.76-251.76C68.882 152.949 64 147.935 64 141.774V107.44c0-6.454 5.338-11.664 11.787-11.432c167.83 6.025 302.21 141.191 308.205 308.205c.232 6.449-4.978 11.787-11.432 11.787z" fill="currentColor"></path></svg>'
|
|
137
137
|
},
|
|
138
|
-
link: RSS
|
|
138
|
+
link: RSS?.url
|
|
139
139
|
}
|
|
140
140
|
]
|
|
141
141
|
}
|