@sugarat/theme 0.5.4 → 0.5.6

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
@@ -181,6 +181,11 @@ declare namespace Theme {
181
181
  * 首页数据分析卡片
182
182
  */
183
183
  analysis?: HomeAnalysis;
184
+ /**
185
+ * 首页博客信息卡片是否在移动端折叠展示
186
+ * @default false
187
+ */
188
+ blogInfoCollapsible?: boolean;
184
189
  }
185
190
  interface ArticleConfig {
186
191
  /**
@@ -423,7 +428,7 @@ declare namespace Theme {
423
428
  backToTop?: boolean | BackToTop;
424
429
  /**
425
430
  * oh-my-live2d 的 loadOml2d 方法的配置选项
426
- * 详见 https://oml2d.com/options/Options.html
431
+ * 详见 https://oml2d.hacxy.cn/api/interfaces/Options.html
427
432
  */
428
433
  oml2d?: Options;
429
434
  homeTags?: boolean | HomeTagsConfig;
@@ -440,7 +445,7 @@ declare namespace Theme {
440
445
  imageStyle?: ImageStyleConfig;
441
446
  groupIcon?: {
442
447
  customIcon: Record<string, string>;
443
- };
448
+ } | false;
444
449
  }
445
450
  type FormatShowDate = {
446
451
  /**
package/node.js CHANGED
@@ -41,7 +41,7 @@ module.exports = __toCommonJS(node_exports);
41
41
  // src/utils/node/mdPlugins.ts
42
42
  var import_module = require("module");
43
43
 
44
- // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.6.3_@algolia+client-search@5.20.0_@types+node@2_0c9e09a0b1912fa528cd2bc14eecd563/node_modules/vitepress-plugin-tabs/dist/index.js
44
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.6.3_@algolia+client-search@5.20.0_@types+node@2_89d33a1149fc4afc3a4b1eeb07b93bba/node_modules/vitepress-plugin-tabs/dist/index.js
45
45
  var tabsMarker = "=tabs";
46
46
  var tabsMarkerLen = tabsMarker.length;
47
47
  var ruleBlockTabs = (state, startLine, endLine, silent) => {
@@ -289,7 +289,9 @@ function getMarkdownPlugins(cfg) {
289
289
  if (cfg?.timeline !== false) {
290
290
  markdownPlugin.push(import_vitepress_markdown_timeline.default);
291
291
  }
292
- markdownPlugin.push(import_vitepress_plugin_group_icons.groupIconMdPlugin);
292
+ if (cfg?.groupIcon !== false) {
293
+ markdownPlugin.push(import_vitepress_plugin_group_icons.groupIconMdPlugin);
294
+ }
293
295
  return markdownPlugin;
294
296
  }
295
297
  function taskCheckboxPlugin(ops) {
@@ -397,7 +399,7 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset,
397
399
  }
398
400
  const utcValue = timeZone >= 0 ? `+${timeZone}` : `${timeZone}`;
399
401
  const date = await (meta.date && /* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}${utcValue}`) || (0, import_theme_shared2.getFileLastModifyTime)(filepath));
400
- meta.date = formatDate(date || /* @__PURE__ */ new Date());
402
+ meta.date = formatDate(date || /* @__PURE__ */ new Date(), "yyyy/MM/dd hh:mm:ss");
401
403
  meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
402
404
  meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
403
405
  meta.tag = [meta.tag || []].flat().concat([
@@ -566,9 +568,25 @@ function getVitePlugins(cfg = {}) {
566
568
  if (cfg?.popover) {
567
569
  plugins.push((0, import_vitepress_plugin_announcement.AnnouncementPlugin)(cfg.popover));
568
570
  }
569
- plugins.push((0, import_vitepress_plugin_group_icons2.groupIconVitePlugin)(cfg?.groupIcon));
571
+ if (cfg?.groupIcon !== false) {
572
+ plugins.push(patchGroupIconPlugin());
573
+ plugins.push((0, import_vitepress_plugin_group_icons2.groupIconVitePlugin)(cfg?.groupIcon));
574
+ }
570
575
  return plugins;
571
576
  }
577
+ function patchGroupIconPlugin() {
578
+ return {
579
+ name: "@sugarat/theme-plugin-patch-group-icon",
580
+ enforce: "pre",
581
+ transform(code, id) {
582
+ if (id.match(/[\/\\]theme[\/\\]index\.(ts|js)$/)) {
583
+ return `import 'virtual:group-icons.css'
584
+ ${code}`;
585
+ }
586
+ return code;
587
+ }
588
+ };
589
+ }
572
590
  function registerVitePlugins(vpCfg, plugins) {
573
591
  vpCfg.vite = {
574
592
  plugins,
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.2.0_vitepress@1.6.3_@algolia+client-search@5.20.0_@types+node@2_0c9e09a0b1912fa528cd2bc14eecd563/node_modules/vitepress-plugin-tabs/dist/index.js
12
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.6.3_@algolia+client-search@5.20.0_@types+node@2_89d33a1149fc4afc3a4b1eeb07b93bba/node_modules/vitepress-plugin-tabs/dist/index.js
13
13
  var tabsMarker = "=tabs";
14
14
  var tabsMarkerLen = tabsMarker.length;
15
15
  var ruleBlockTabs = (state, startLine, endLine, silent) => {
@@ -256,7 +256,9 @@ function getMarkdownPlugins(cfg) {
256
256
  if (cfg?.timeline !== false) {
257
257
  markdownPlugin.push(timeline);
258
258
  }
259
- markdownPlugin.push(groupIconMdPlugin);
259
+ if (cfg?.groupIcon !== false) {
260
+ markdownPlugin.push(groupIconMdPlugin);
261
+ }
260
262
  return markdownPlugin;
261
263
  }
262
264
  function taskCheckboxPlugin(ops) {
@@ -363,7 +365,7 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset,
363
365
  }
364
366
  const utcValue = timeZone >= 0 ? `+${timeZone}` : `${timeZone}`;
365
367
  const date = await (meta.date && /* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}${utcValue}`) || getFileLastModifyTime(filepath));
366
- meta.date = formatDate(date || /* @__PURE__ */ new Date());
368
+ meta.date = formatDate(date || /* @__PURE__ */ new Date(), "yyyy/MM/dd hh:mm:ss");
367
369
  meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
368
370
  meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
369
371
  meta.tag = [meta.tag || []].flat().concat([
@@ -534,9 +536,25 @@ function getVitePlugins(cfg = {}) {
534
536
  if (cfg?.popover) {
535
537
  plugins.push(AnnouncementPlugin(cfg.popover));
536
538
  }
537
- plugins.push(groupIconVitePlugin(cfg?.groupIcon));
539
+ if (cfg?.groupIcon !== false) {
540
+ plugins.push(patchGroupIconPlugin());
541
+ plugins.push(groupIconVitePlugin(cfg?.groupIcon));
542
+ }
538
543
  return plugins;
539
544
  }
545
+ function patchGroupIconPlugin() {
546
+ return {
547
+ name: "@sugarat/theme-plugin-patch-group-icon",
548
+ enforce: "pre",
549
+ transform(code, id) {
550
+ if (id.match(/[\/\\]theme[\/\\]index\.(ts|js)$/)) {
551
+ return `import 'virtual:group-icons.css'
552
+ ${code}`;
553
+ }
554
+ return code;
555
+ }
556
+ };
557
+ }
540
558
  function registerVitePlugins(vpCfg, plugins) {
541
559
  vpCfg.vite = {
542
560
  plugins,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -50,12 +50,12 @@
50
50
  "oh-my-live2d": "^0.19.3",
51
51
  "swiper": "^11.1.1",
52
52
  "vitepress-markdown-timeline": "^1.2.1",
53
- "vitepress-plugin-group-icons": "^1.2.4",
53
+ "vitepress-plugin-group-icons": "1.2.4",
54
54
  "vitepress-plugin-mermaid": "2.0.13",
55
55
  "vitepress-plugin-tabs": "0.2.0",
56
- "@sugarat/theme-shared": "0.0.4",
57
- "vitepress-plugin-announcement": "0.1.4",
58
- "vitepress-plugin-pagefind": "0.4.13",
56
+ "@sugarat/theme-shared": "0.0.5",
57
+ "vitepress-plugin-announcement": "0.1.5",
58
+ "vitepress-plugin-pagefind": "0.4.14",
59
59
  "vitepress-plugin-rss": "0.3.1"
60
60
  },
61
61
  "devDependencies": {
@@ -3,7 +3,7 @@ import Theme from 'vitepress/theme'
3
3
  import { useData } from 'vitepress'
4
4
  import { computed } from 'vue'
5
5
  import { useDarkTransition } from '../hooks/useDarkTransition'
6
- import { useBlogThemeMode, useDarkTransitionConfig } from '../composables/config/blog'
6
+ import { useBlogInfoCollapsible, useBlogThemeMode, useDarkTransitionConfig } from '../composables/config/blog'
7
7
  import BlogHomeInfo from './BlogHomeInfo.vue'
8
8
  import BlogHomeBanner from './BlogHomeBanner.vue'
9
9
  import BlogList from './BlogList.vue'
@@ -26,6 +26,8 @@ const layout = computed(() => frontmatter.value.layout)
26
26
  const isBlogTheme = useBlogThemeMode()
27
27
  const { Layout } = Theme
28
28
 
29
+ const blogInfoCollapsible = useBlogInfoCollapsible()
30
+
29
31
  // 切换深色模式过渡
30
32
  // https://vitepress.dev/zh/guide/extending-default-theme#on-appearance-toggle
31
33
  useDarkTransition()
@@ -67,7 +69,11 @@ const openTransition = useDarkTransitionConfig()
67
69
  <div class="blog-list-wrapper">
68
70
  <BlogList />
69
71
  </div>
70
- <div class="blog-info-wrapper">
72
+ <div
73
+ :class="{
74
+ 'normal-mode': blogInfoCollapsible,
75
+ }" class="blog-info-wrapper"
76
+ >
71
77
  <BlogHomeInfo />
72
78
  </div>
73
79
  </div>
@@ -108,6 +114,9 @@ const openTransition = useDarkTransitionConfig()
108
114
  <slot name="nav-screen-content-before" />
109
115
  </template>
110
116
  <template #nav-screen-content-after>
117
+ <div v-if="blogInfoCollapsible" class="minify-mode blog-info-wrapper">
118
+ <BlogHomeInfo />
119
+ </div>
111
120
  <slot name="nav-screen-content-after" />
112
121
  </template>
113
122
 
@@ -226,6 +235,24 @@ const openTransition = useDarkTransitionConfig()
226
235
  margin: 20px 0;
227
236
  width: 100%;
228
237
  }
238
+
239
+ .normal-mode {
240
+ display: none;
241
+ }
242
+
243
+ .minify-mode {
244
+ display: block;
245
+ }
246
+ }
247
+
248
+ @media screen and (min-width: 768px) {
249
+ .minify-mode {
250
+ display: none;
251
+ }
252
+
253
+ .normal-mode {
254
+ display: block;
255
+ }
229
256
  }
230
257
  </style>
231
258
 
@@ -131,24 +131,25 @@ const timeTitle = computed(() =>
131
131
  <template>
132
132
  <div v-if="showAnalyze && readingTimePosition === 'top'" class="doc-analyze" data-pagefind-ignore="all">
133
133
  <span>
134
- <ElIcon><EditPen /></ElIcon>
134
+ <ElIcon>
135
+ <EditPen />
136
+ </ElIcon>
135
137
  {{ topWordCount }}
136
138
  </span>
137
139
  <span>
138
- <ElIcon><AlarmClock /></ElIcon>
140
+ <ElIcon>
141
+ <AlarmClock />
142
+ </ElIcon>
139
143
  {{ topReadTime }}
140
144
  </span>
141
145
  </div>
142
146
  <div id="hack-article-des" ref="$des" class="meta-des">
143
147
  <!-- TODO:是否需要原创?转载等标签,理论上可以添加标签解决,可以参考 charles7c -->
144
148
  <span v-if="author && !hiddenAuthor" class="author" :title="authorTitle">
145
- <ElIcon><UserFilled /></ElIcon>
146
- <a
147
- v-if="currentAuthorInfo"
148
- class="link"
149
- :href="currentAuthorInfo.url"
150
- :title="currentAuthorInfo.des"
151
- >
149
+ <ElIcon>
150
+ <UserFilled />
151
+ </ElIcon>
152
+ <a v-if="currentAuthorInfo" class="link" :href="currentAuthorInfo.url" :title="currentAuthorInfo.des">
152
153
  {{ currentAuthorInfo.nickname }}
153
154
  </a>
154
155
  <template v-else>
@@ -156,36 +157,48 @@ const timeTitle = computed(() =>
156
157
  </template>
157
158
  </span>
158
159
  <span v-if="publishDate && !hiddenTime" class="publishDate" :title="timeTitle + hoverDate">
159
- <ElIcon><Clock /></ElIcon>
160
+ <ElIcon>
161
+ <Clock />
162
+ </ElIcon>
160
163
  {{ publishDate }}
161
164
  </span>
162
- <span v-if="tags.length" class="tags" :title="tagTitle">
163
- <ElIcon><CollectionTag /></ElIcon>
164
- <a v-for="tag in tags" :key="tag" class="link" :href="`/?tag=${tag}`">{{ tag }}
165
- </a>
166
- </span>
167
165
  <template v-if="readingTimePosition === 'inline' && showAnalyze">
168
166
  <span :title="wordCountTitle">
169
- <ElIcon><EditPen /></ElIcon>
167
+ <ElIcon>
168
+ <EditPen />
169
+ </ElIcon>
170
170
  {{ inlineWordCount }}
171
171
  </span>
172
172
  <span :title="readTimeTitle">
173
- <ElIcon><AlarmClock /></ElIcon>
173
+ <ElIcon>
174
+ <AlarmClock />
175
+ </ElIcon>
174
176
  {{ inlineReadTime }}
175
177
  </span>
176
178
  </template>
177
179
  <template v-if="readingTimePosition === 'newLine' && showAnalyze">
178
180
  <div style="width: 100%;" class="new-line-meta-des">
179
181
  <span :title="wordCountTitle">
180
- <ElIcon><EditPen /></ElIcon>
182
+ <ElIcon>
183
+ <EditPen />
184
+ </ElIcon>
181
185
  {{ inlineWordCount }}
182
186
  </span>
183
187
  <span :title="readTimeTitle">
184
- <ElIcon><AlarmClock /></ElIcon>
188
+ <ElIcon>
189
+ <AlarmClock />
190
+ </ElIcon>
185
191
  {{ inlineReadTime }}
186
192
  </span>
187
193
  </div>
188
194
  </template>
195
+ <span v-if="tags.length" class="tags" :title="tagTitle">
196
+ <ElIcon>
197
+ <CollectionTag />
198
+ </ElIcon>
199
+ <a v-for="tag in tags" :key="tag" class="link" :href="`/?tag=${tag}`">{{ tag }}
200
+ </a>
201
+ </span>
189
202
  <!-- 封面展示 -->
190
203
  <ClientOnly>
191
204
  <BlogDocCover />
@@ -200,26 +213,33 @@ const timeTitle = computed(() =>
200
213
  margin-bottom: 20px;
201
214
  display: flex;
202
215
  justify-content: center;
216
+
203
217
  span {
204
218
  margin-right: 16px;
205
219
  display: flex;
206
220
  align-items: center;
221
+
207
222
  .el-icon {
208
223
  margin-right: 4px;
209
224
  }
210
225
  }
211
226
  }
212
- .meta-des,.new-line-meta-des {
227
+
228
+ .meta-des,
229
+ .new-line-meta-des {
213
230
  text-align: left;
214
231
  color: var(--vp-c-text-2);
215
232
  font-size: 14px;
216
233
  margin-top: 6px;
217
234
  display: flex;
218
235
  flex-wrap: wrap;
236
+
219
237
  >span {
220
238
  margin-right: 16px;
221
239
  display: flex;
222
240
  align-items: center;
241
+ flex-wrap: wrap;
242
+
223
243
  .el-icon {
224
244
  margin-right: 4px;
225
245
  }
@@ -227,12 +247,14 @@ const timeTitle = computed(() =>
227
247
 
228
248
  .link {
229
249
  color: var(--vp-c-text-2);
250
+
230
251
  &:hover {
231
252
  color: var(--vp-c-brand-1);
232
253
  cursor: pointer;
233
254
  }
234
255
  }
235
256
  }
257
+
236
258
  .tags {
237
259
  a.link:not(:last-child) {
238
260
  &::after {
@@ -1,7 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { useElementSize, useElementVisibility, useWindowSize } from '@vueuse/core'
3
3
  import { computed, ref } from 'vue'
4
- import { Comment } from '@element-plus/icons-vue'
5
4
  import { useCommentConfig, useOpenCommentConfig } from '../composables/config/blog'
6
5
  import Icon from './Icon.vue'
7
6
 
@@ -38,7 +37,7 @@ const labelText = computed(() => {
38
37
  <div v-show="!commentIsVisible" class="comment-btn-wrapper">
39
38
  <span v-if="!mobileMinify && labelText" class="icon-wrapper-text" @click="handleScrollToComment">
40
39
  <Icon :size="20" :icon="commentConfig?.icon">
41
- <Comment />
40
+ <svg data-v-f0aeb853="" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1024 1024"><path fill="currentColor" d="M736 504a56 56 0 1 1 0-112 56 56 0 0 1 0 112m-224 0a56 56 0 1 1 0-112 56 56 0 0 1 0 112m-224 0a56 56 0 1 1 0-112 56 56 0 0 1 0 112M128 128v640h192v160l224-160h352V128z" /></svg>
42
41
  </Icon>
43
42
  <span class="text">
44
43
  {{ labelText }}
@@ -46,7 +45,7 @@ const labelText = computed(() => {
46
45
  </span>
47
46
  <span v-else class="icon-wrapper" @click="handleScrollToComment">
48
47
  <Icon :size="20" :icon="commentConfig?.icon">
49
- <Comment />
48
+ <svg data-v-f0aeb853="" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 1024 1024"><path fill="currentColor" d="M736 504a56 56 0 1 1 0-112 56 56 0 0 1 0 112m-224 0a56 56 0 1 1 0-112 56 56 0 0 1 0 112m-224 0a56 56 0 1 1 0-112 56 56 0 0 1 0 112M128 128v640h192v160l224-160h352V128z" /></svg>
50
49
  </Icon>
51
50
  </span>
52
51
  </div>
@@ -213,11 +213,7 @@ function handleChooseTag(tag: string) {
213
213
  <!-- times -->
214
214
  <div class="times">
215
215
  <span class="icon">
216
- <svg
217
- xmlns="http://www.w3.org/2000/svg"
218
- xmlns:xlink="http://www.w3.org/1999/xlink"
219
- viewBox="0 0 24 24"
220
- >
216
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
221
217
  <title>上线时间</title>
222
218
  <path
223
219
  d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8zm-.22-13h-.06c-.4 0-.72.32-.72.72v4.72c0 .35.18.68.49.86l4.15 2.49c.34.2.78.1.98-.24a.71.71 0 0 0-.25-.99l-3.87-2.3V7.72c0-.4-.32-.72-.72-.72z"
@@ -230,17 +226,10 @@ function handleChooseTag(tag: string) {
230
226
  </div>
231
227
  <!-- GitHub links -->
232
228
  <div v-if="work.github" class="links">
233
- <a
234
- v-if="work.github"
235
- class="github-link"
236
- :href="work.github as string"
237
- target="_blank"
238
- rel="noopener"
239
- >
229
+ <a v-if="work.github" class="github-link" :href="work.github as string" target="_blank" rel="noopener">
240
230
  <i class="icon">
241
231
  <svg
242
- xmlns="http://www.w3.org/2000/svg"
243
- xmlns:xlink="http://www.w3.org/1999/xlink"
232
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
244
233
  viewBox="0 0 496 512"
245
234
  >
246
235
  <path
@@ -255,35 +244,16 @@ function handleChooseTag(tag: string) {
255
244
  <!-- 其它自定义链接 -->
256
245
  <div v-if="work.links?.length" class="links">
257
246
  <i v-if="work.links?.length" class="icon">
258
- <svg
259
- xmlns="http://www.w3.org/2000/svg"
260
- xmlns:xlink="http://www.w3.org/1999/xlink"
261
- viewBox="0 0 24 24"
262
- >
263
- <g
264
- fill="none"
265
- stroke="currentColor"
266
- stroke-width="2"
267
- stroke-linecap="round"
268
- stroke-linejoin="round"
269
- >
270
- <path
271
- d="M10 14a3.5 3.5 0 0 0 5 0l4-4a3.5 3.5 0 0 0-5-5l-.5.5"
272
- />
273
- <path
274
- d="M14 10a3.5 3.5 0 0 0-5 0l-4 4a3.5 3.5 0 0 0 5 5l.5-.5"
275
- />
247
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
248
+ <g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
249
+ <path d="M10 14a3.5 3.5 0 0 0 5 0l4-4a3.5 3.5 0 0 0-5-5l-.5.5" />
250
+ <path d="M14 10a3.5 3.5 0 0 0-5 0l-4 4a3.5 3.5 0 0 0 5 5l.5-.5" />
276
251
  </g>
277
252
  </svg>
278
253
  </i>
279
254
  <a
280
- v-for="link in work.links || []"
281
- :key="link.url"
282
- class="link"
283
- :href="link.url"
284
- :title="link.title"
285
- target="_blank"
286
- rel="noopener"
255
+ v-for="link in work.links || []" :key="link.url" class="link" :href="link.url" :title="link.title"
256
+ target="_blank" rel="noopener"
287
257
  >
288
258
  {{ link.title }}
289
259
  </a>
@@ -291,23 +261,14 @@ function handleChooseTag(tag: string) {
291
261
  <!-- tags -->
292
262
  <div v-if="work.tags?.length" class="tags">
293
263
  <i class="icon">
294
- <svg
295
- xmlns="http://www.w3.org/2000/svg"
296
- viewBox="0 0 1024 1024"
297
- data-v-d328c40a=""
298
- >
264
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" data-v-d328c40a="">
299
265
  <path
300
266
  fill="currentColor"
301
267
  d="M256 128v698.88l196.032-156.864a96 96 0 0 1 119.936 0L768 826.816V128H256zm-32-64h576a32 32 0 0 1 32 32v797.44a32 32 0 0 1-51.968 24.96L531.968 720a32 32 0 0 0-39.936 0L243.968 918.4A32 32 0 0 1 192 893.44V96a32 32 0 0 1 32-32z"
302
268
  />
303
269
  </svg>
304
270
  </i>
305
- <span
306
- v-for="tag in work.tags"
307
- :key="tag"
308
- class="tag"
309
- @click="handleChooseTag(tag)"
310
- >{{ tag }}
271
+ <span v-for="tag in work.tags" :key="tag" class="tag" @click="handleChooseTag(tag)">{{ tag }}
311
272
  </span>
312
273
  </div>
313
274
  </div>
@@ -315,25 +276,11 @@ function handleChooseTag(tag: string) {
315
276
  <div v-if="work.covers?.length" class="images">
316
277
  <!-- swiper -->
317
278
  <div v-if="work.coverLayout === 'swiper'" class="swiper-mode">
318
- <ElCarousel
319
- autoplay
320
- height="260px"
321
- :type="isCardMode && work.covers.length >= 3 ? 'card' : ''"
322
- >
323
- <ElCarouselItem
324
- v-for="(url, idx) in work.covers"
325
- :key="url"
326
- style="text-align: center"
327
- >
279
+ <ElCarousel autoplay height="260px" :type="isCardMode && work.covers.length >= 3 ? 'card' : ''">
280
+ <ElCarouselItem v-for="(url, idx) in work.covers" :key="url" style="text-align: center">
328
281
  <ElImage
329
- :key="url"
330
- preview-teleported
331
- :src="url"
332
- loading="lazy"
333
- :preview-src-list="work.covers"
334
- :initial-index="idx"
335
- hide-on-click-modal
336
- :alt="`${work.title}-${idx}`"
282
+ :key="url" preview-teleported :src="url" loading="lazy" :preview-src-list="work.covers"
283
+ :initial-index="idx" hide-on-click-modal :alt="`${work.title}-${idx}`"
337
284
  />
338
285
  </ElCarouselItem>
339
286
  </ElCarousel>
@@ -341,13 +288,8 @@ function handleChooseTag(tag: string) {
341
288
  <!-- list -->
342
289
  <div v-if="work.coverLayout === 'list'" class="list-mode">
343
290
  <ElImage
344
- v-for="(url, idx) in work.covers"
345
- :key="url"
346
- :src="url"
347
- loading="lazy"
348
- :preview-src-list="work.covers"
349
- :initial-index="idx"
350
- hide-on-click-modal
291
+ v-for="(url, idx) in work.covers" :key="url" :src="url" loading="lazy"
292
+ :preview-src-list="work.covers" :initial-index="idx" hide-on-click-modal
351
293
  />
352
294
  </div>
353
295
  </div>
@@ -369,24 +311,29 @@ function handleChooseTag(tag: string) {
369
311
  width: 100%;
370
312
  margin: 20px auto;
371
313
  padding: 16px;
314
+
372
315
  h1 {
373
316
  font-size: 32px;
374
317
  font-weight: bold;
375
318
  }
319
+
376
320
  .description {
377
321
  margin-top: 16px;
378
322
  color: #999;
379
323
  font-size: 16px;
380
324
  }
325
+
381
326
  a {
382
327
  font-weight: 500;
383
328
  color: var(--vp-c-brand-1);
384
329
  }
385
330
  }
331
+
386
332
  .works-container {
387
333
  display: flex;
388
334
  justify-content: center;
389
335
  }
336
+
390
337
  .work {
391
338
  max-width: 900px;
392
339
 
@@ -396,9 +343,11 @@ function handleChooseTag(tag: string) {
396
343
  line-height: 32px;
397
344
  font-size: 24px;
398
345
  border-top: 1px solid var(--vp-c-divider);
346
+
399
347
  a {
400
348
  color: inherit;
401
349
  }
350
+
402
351
  &:hover {
403
352
  a {
404
353
  &::before {
@@ -406,8 +355,10 @@ function handleChooseTag(tag: string) {
406
355
  }
407
356
  }
408
357
  }
358
+
409
359
  a {
410
360
  position: relative;
361
+
411
362
  &::before {
412
363
  position: absolute;
413
364
  left: -16px;
@@ -416,37 +367,44 @@ function handleChooseTag(tag: string) {
416
367
  }
417
368
  }
418
369
  }
370
+
419
371
  h3 {
420
372
  margin: 32px 0 0;
421
373
  line-height: 28px;
422
374
  font-size: 20px;
423
375
  position: relative;
424
- &.title > a.pin {
376
+
377
+ &.title>a.pin {
425
378
  position: absolute;
426
379
  left: -16px;
380
+
427
381
  &::before {
428
382
  left: -16px;
429
383
  opacity: 0;
430
384
  content: var(--vp-header-anchor-symbol);
431
385
  }
432
386
  }
433
- &:hover > a.pin {
387
+
388
+ &:hover>a.pin {
434
389
  &::before {
435
390
  opacity: 1;
436
391
  }
437
392
  }
438
393
  }
394
+
439
395
  .info {
440
396
  display: flex;
441
397
  font-size: 14px;
442
398
  margin-top: 10px;
443
399
  flex-wrap: wrap;
444
400
  }
401
+
445
402
  .links,
446
403
  .times,
447
404
  .tags {
448
405
  display: flex;
449
406
  align-items: center;
407
+
450
408
  .icon {
451
409
  color: var(--vp-c-text-1);
452
410
  display: block;
@@ -455,34 +413,42 @@ function handleChooseTag(tag: string) {
455
413
  margin-right: 6px;
456
414
  }
457
415
  }
416
+
458
417
  .times {
459
418
  margin-right: 18px;
460
419
  }
420
+
461
421
  .links {
462
422
  a {
463
423
  display: flex;
464
424
  align-items: center;
465
425
  }
426
+
466
427
  a.github-link {
467
428
  margin-right: 10px;
468
429
  }
430
+
469
431
  a.link {
470
432
  margin-right: 0;
433
+
471
434
  &::after {
472
435
  content: ',';
473
436
  color: var(--vp-c-text-1);
474
437
  margin-right: 6px;
475
438
  margin-left: 2px;
476
439
  }
440
+
477
441
  &:last-child::after {
478
442
  content: '';
479
443
  }
480
444
  }
481
445
  }
446
+
482
447
  .tags {
483
448
  span.tag {
484
449
  cursor: pointer;
485
450
  }
451
+
486
452
  span.tag:not(:last-child) {
487
453
  &::after {
488
454
  content: '·';
@@ -492,6 +458,21 @@ function handleChooseTag(tag: string) {
492
458
  }
493
459
  }
494
460
  }
461
+ .works {
462
+ flex: 1;
463
+ }
464
+ @media (min-width: 1440px) {
465
+ .works {
466
+ max-width: 784px;
467
+ }
468
+ }
469
+
470
+ @media (min-width: 960px) {
471
+ .works {
472
+ max-width: 752px;
473
+ }
474
+ }
475
+
495
476
  .aside-container {
496
477
  display: none;
497
478
  flex: 1;
@@ -499,18 +480,18 @@ function handleChooseTag(tag: string) {
499
480
  width: 100%;
500
481
  max-width: 256px;
501
482
  }
483
+
502
484
  @media screen and (min-width: 960px) {
503
485
  .aside-container {
504
486
  display: block;
505
487
  }
506
488
  }
489
+
507
490
  .aside-outline-container {
508
491
  position: sticky;
509
- top: calc(
510
- var(--vp-nav-height) + var(--vp-layout-top-height, 0px) +
511
- var(--vp-doc-top-height, 0px) + 32px
512
- );
492
+ top: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 32px);
513
493
  }
494
+
514
495
  .lastupdate {
515
496
  color: var(--vp-c-text-1);
516
497
  }
@@ -522,6 +503,7 @@ function handleChooseTag(tag: string) {
522
503
  display: flex;
523
504
  flex-wrap: wrap;
524
505
  justify-content: center;
506
+
525
507
  .el-image {
526
508
  :deep(img) {
527
509
  object-fit: contain;
@@ -532,6 +514,7 @@ function handleChooseTag(tag: string) {
532
514
 
533
515
  .swiper-mode {
534
516
  margin-top: 16px;
517
+
535
518
  .el-image {
536
519
  :deep(img) {
537
520
  object-fit: contain;
@@ -539,6 +522,7 @@ function handleChooseTag(tag: string) {
539
522
  }
540
523
  }
541
524
  }
525
+
542
526
  .split {
543
527
  display: inline-block;
544
528
  width: 1px;
@@ -186,6 +186,10 @@ export function useBlogThemeMode() {
186
186
  return inject(configSymbol)!.value?.blog?.blog ?? true
187
187
  }
188
188
 
189
+ export function useBlogInfoCollapsible() {
190
+ return inject(configSymbol)!.value?.blog?.home?.blogInfoCollapsible ?? false
191
+ }
192
+
189
193
  export function useArticles() {
190
194
  const blogConfig = useConfig()
191
195
  const { localeIndex, site } = useData()
@@ -357,7 +361,7 @@ export function useHomeAnalysis() {
357
361
  }
358
362
 
359
363
  export function useAnalyzeTitles(wordCount: Ref<number>, readTime: ComputedRef<number>) {
360
- const article = computed(() => useConfig()?.value.blog?.article)
364
+ const article = useArticleConfig()
361
365
 
362
366
  const topWordCount = computed(() =>
363
367
  replaceValue(article.value?.analyzeTitles?.topWordCount || '字数:{{value}} 个字', wordCount.value)
@@ -186,6 +186,11 @@ export namespace Theme {
186
186
  * 首页数据分析卡片
187
187
  */
188
188
  analysis?: HomeAnalysis
189
+ /**
190
+ * 首页博客信息卡片是否在移动端折叠展示
191
+ * @default false
192
+ */
193
+ blogInfoCollapsible?: boolean
189
194
  }
190
195
 
191
196
  export interface ArticleConfig {
@@ -450,7 +455,7 @@ export namespace Theme {
450
455
 
451
456
  /**
452
457
  * oh-my-live2d 的 loadOml2d 方法的配置选项
453
- * 详见 https://oml2d.com/options/Options.html
458
+ * 详见 https://oml2d.hacxy.cn/api/interfaces/Options.html
454
459
  */
455
460
  oml2d?: Oml2dOptions
456
461
  homeTags?: boolean | HomeTagsConfig
@@ -467,7 +472,7 @@ export namespace Theme {
467
472
  imageStyle?: ImageStyleConfig
468
473
  groupIcon?: {
469
474
  customIcon: Record<string, string>
470
- }
475
+ } | false
471
476
  }
472
477
 
473
478
  export type FormatShowDate = {
package/src/index.ts CHANGED
@@ -35,8 +35,8 @@ import UserWorksPage from './components/UserWorks.vue'
35
35
  // 内置一些特殊的主题色
36
36
  import './styles/theme/inline-theme.var.css'
37
37
 
38
- // 导入group icons
39
- import 'virtual:group-icons.css'
38
+ // 导入group icons,改由自定义插件导入
39
+ // import 'virtual:group-icons.css'
40
40
 
41
41
  export const BlogTheme: Theme = {
42
42
  ...DefaultTheme,
@@ -32,7 +32,9 @@ export function getMarkdownPlugins(cfg?: Partial<Theme.BlogConfig>) {
32
32
  markdownPlugin.push(timeline)
33
33
  }
34
34
 
35
- markdownPlugin.push(groupIconMdPlugin)
35
+ if (cfg?.groupIcon !== false) {
36
+ markdownPlugin.push(groupIconMdPlugin)
37
+ }
36
38
 
37
39
  return markdownPlugin
38
40
  }
@@ -47,7 +47,7 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
47
47
  || getFileLastModifyTime(filepath)
48
48
  )
49
49
  // 无法获取时兜底当前时间
50
- meta.date = formatDate(date || new Date())
50
+ meta.date = formatDate(date || new Date(), 'yyyy/MM/dd hh:mm:ss')
51
51
 
52
52
  // 处理tags和categories,兼容历史文章
53
53
  meta.categories
@@ -56,12 +56,29 @@ export function getVitePlugins(cfg: Partial<Theme.BlogConfig> = {}) {
56
56
  }
57
57
 
58
58
  // 内置支持 group icon
59
-
60
- plugins.push(groupIconVitePlugin(cfg?.groupIcon))
59
+ if (cfg?.groupIcon !== false) {
60
+ plugins.push(patchGroupIconPlugin())
61
+ plugins.push(groupIconVitePlugin(cfg?.groupIcon))
62
+ }
61
63
 
62
64
  return plugins
63
65
  }
64
66
 
67
+ export function patchGroupIconPlugin() {
68
+ return {
69
+ name: '@sugarat/theme-plugin-patch-group-icon',
70
+ enforce: 'pre',
71
+ transform(code: string, id: string) {
72
+ // 匹配 theme/index.ts 或 theme/index.js 文件
73
+ if (id.match(/[\/\\]theme[\/\\]index\.(ts|js)$/)) {
74
+ // 在文件顶部插入 import 语句
75
+ return `import 'virtual:group-icons.css'\n${code}`
76
+ }
77
+ return code
78
+ }
79
+ }
80
+ }
81
+
65
82
  export function registerVitePlugins(vpCfg: any, plugins: any[]) {
66
83
  vpCfg.vite = {
67
84
  plugins,