@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 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: string;
285
+ url?: string;
269
286
  /**
270
287
  * 输出的RSS文件名
271
288
  * @default 'feed.rss'
272
289
  */
273
290
  filename?: string;
274
291
  /**
275
- * 是否展示RSS的图标
292
+ * RSS的图标展示
276
293
  * @default true
277
294
  */
278
- showIcon?: boolean;
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.4_vue@3.3.4/node_modules/vitepress-plugin-tabs/dist/index.js
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.showIcon !== false) {
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.url
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
- const posts = blogCfg.pagesData;
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(RSS);
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, hidden } = meta;
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 RSSFile = import_path2.default.join(config.outDir, filename || "feed.rss");
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", filename || "feed.rss");
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.41",
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.4",
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">
@@ -206,7 +206,7 @@ watch(
206
206
  .link {
207
207
  color: var(--vp-c-text-2);
208
208
  &:hover {
209
- color: var(--vp-c-brand);
209
+ color: var(--vp-c-brand-1);
210
210
  cursor: pointer;
211
211
  }
212
212
  }
@@ -43,9 +43,9 @@
43
43
  </div>
44
44
  </template>
45
45
  <script setup lang="ts">
46
- import { useDark, useElementVisibility } from '@vueuse/core'
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 = useDark({
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 {
@@ -138,7 +138,7 @@ const showChangeBtn = computed(() => {
138
138
  }
139
139
 
140
140
  &:nth-child(3) .num {
141
- background-color: #409eff;
141
+ background-color: var(--vp-c-brand-2);
142
142
  color: #fff;
143
143
  font-size: 12px;
144
144
  border-radius: 6px;
@@ -16,17 +16,19 @@
16
16
  </ul>
17
17
  <!-- 解决element-ui bug -->
18
18
  <ClientOnly>
19
- <el-pagination
20
- v-if="wikiList.length >= pageSize"
21
- small
22
- background
23
- :default-current-page="1"
24
- :current-page="currentPage"
25
- @update:current-page="handleUpdatePageNum"
26
- :page-size="pageSize"
27
- :total="filterData.length"
28
- layout="prev, pager, next, jumper"
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(--el-color-primary-light-3);
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(--el-color-primary-light-3);
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(--el-color-primary-light-3);
215
+ background-color: var(--vp-c-brand-3);
211
216
  padding: 8px;
212
217
  color: #fff;
213
218
  font-size: 12px;
@@ -191,7 +191,7 @@ const showChangeBtn = computed(() => {
191
191
  word-break: break-all;
192
192
  white-space: break-spaces;
193
193
  &.current {
194
- color: var(--vp-c-brand);
194
+ color: var(--vp-c-brand-1);
195
195
  }
196
196
  }
197
197
 
@@ -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,
@@ -376,7 +376,7 @@ const handleChooseTag = (tag: string) => {
376
376
  }
377
377
  a {
378
378
  font-weight: 500;
379
- color: var(--vp-c-brand);
379
+ color: var(--vp-c-brand-1);
380
380
  }
381
381
  }
382
382
  .works-container {
@@ -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
- props: {
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: string
314
+ url?: string
290
315
  /**
291
316
  * 输出的RSS文件名
292
317
  * @default 'feed.rss'
293
318
  */
294
319
  filename?: string
295
320
  /**
296
- * 是否展示RSS的图标
321
+ * RSS的图标展示
297
322
  * @default true
298
323
  */
299
- showIcon?: boolean
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),
@@ -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: #409eff;
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: 5px;
109
- height: 5px;
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: 5px;
118
+ height: 4px;
118
119
  border-radius: 4px;
119
- background-color: var(--el-color-primary);
120
+ background-color: var(--vp-c-brand-1);
120
121
  }
121
122
 
122
123
  ::-webkit-scrollbar-thumb:horizontal {
123
- width: 5px;
124
+ width: 4px;
124
125
  border-radius: 4px;
125
- background-color: var(--el-color-primary);
126
+ background-color: var(--vp-c-brand-1);
126
127
  }
@@ -24,7 +24,7 @@ ul {
24
24
 
25
25
  --lowContrast: #ffffff;
26
26
  --highContrast: #000000;
27
- --vcp-c-brand: #44bd87;
27
+ --vcp-c-brand: var(--vp-c-brand-2);
28
28
  --vcp-c-accent: #35495e;
29
29
 
30
30
  --gray1: hsl(0, 0%, 98%);
@@ -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
- const posts: Theme.PageData[] = blogCfg.pagesData
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(RSS)
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, hidden } = meta
37
- if (hidden) continue
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 RSSFile = path.join(config.outDir, filename || 'feed.rss')
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', filename || 'feed.rss')
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
  }
@@ -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.showIcon !== false) {
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.url
138
+ link: RSS?.url
139
139
  }
140
140
  ]
141
141
  }