@sugarat/theme 0.4.1 → 0.4.3
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 +9 -0
- package/node.js +25 -12
- package/package.json +1 -1
- package/src/components/BlogArticleAnalyze.vue +6 -2
- package/src/components/BlogHomeOverview.vue +7 -4
- package/src/composables/config/blog.ts +4 -0
- package/src/composables/config/index.ts +10 -0
- package/src/utils/node/index.ts +24 -6
- package/src/utils/node/theme.ts +2 -3
package/node.d.ts
CHANGED
|
@@ -175,6 +175,11 @@ declare namespace Theme {
|
|
|
175
175
|
*/
|
|
176
176
|
style?: 'card' | 'sidebar';
|
|
177
177
|
}
|
|
178
|
+
interface HomeAnalysis {
|
|
179
|
+
articles?: {
|
|
180
|
+
title?: string[];
|
|
181
|
+
};
|
|
182
|
+
}
|
|
178
183
|
interface HomeBlog {
|
|
179
184
|
name?: string;
|
|
180
185
|
motto?: string;
|
|
@@ -187,6 +192,10 @@ declare namespace Theme {
|
|
|
187
192
|
* @default 'card'
|
|
188
193
|
*/
|
|
189
194
|
avatarMode?: 'card' | 'split';
|
|
195
|
+
/**
|
|
196
|
+
* 首页数据分析卡片
|
|
197
|
+
*/
|
|
198
|
+
analysis?: HomeAnalysis;
|
|
190
199
|
}
|
|
191
200
|
interface ArticleConfig {
|
|
192
201
|
readingTime?: boolean;
|
package/node.js
CHANGED
|
@@ -210,6 +210,7 @@ var import_vitepress_markdown_timeline = __toESM(require("vitepress-markdown-tim
|
|
|
210
210
|
// src/utils/node/index.ts
|
|
211
211
|
var import_node_child_process = require("child_process");
|
|
212
212
|
var import_node_path = __toESM(require("path"));
|
|
213
|
+
var import_node_fs = __toESM(require("fs"));
|
|
213
214
|
function getDefaultTitle(content) {
|
|
214
215
|
const match = content.match(/^(#+)\s+(.+)/m);
|
|
215
216
|
return match?.[2] || "";
|
|
@@ -224,16 +225,30 @@ function getFileBirthTime(url) {
|
|
|
224
225
|
const child = (0, import_node_child_process.spawn)("git", ["log", "-1", '--pretty="%ai"', url]);
|
|
225
226
|
let output = "";
|
|
226
227
|
child.stdout.on("data", (d) => output += String(d));
|
|
227
|
-
child.on("close", () => {
|
|
228
|
-
|
|
228
|
+
child.on("close", async () => {
|
|
229
|
+
let date;
|
|
230
|
+
if (output.trim()) {
|
|
231
|
+
date = new Date(output);
|
|
232
|
+
} else {
|
|
233
|
+
date = await getFileBirthTimeByFs(url);
|
|
234
|
+
}
|
|
229
235
|
cache.set(url, date);
|
|
230
236
|
resolve(date);
|
|
231
237
|
});
|
|
232
|
-
child.on("error", () => {
|
|
233
|
-
|
|
238
|
+
child.on("error", async () => {
|
|
239
|
+
const fsDate = await getFileBirthTimeByFs(url);
|
|
240
|
+
resolve(fsDate);
|
|
234
241
|
});
|
|
235
242
|
});
|
|
236
243
|
}
|
|
244
|
+
async function getFileBirthTimeByFs(url) {
|
|
245
|
+
try {
|
|
246
|
+
const fsStat = await import_node_fs.default.promises.stat(url);
|
|
247
|
+
return fsStat.birthtime;
|
|
248
|
+
} catch {
|
|
249
|
+
return void 0;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
237
252
|
function getTextSummary(text, count = 100) {
|
|
238
253
|
return text?.replace(/^#+\s+.*/, "")?.replace(/#/g, "")?.replace(/!\[.*?\]\(.*?\)/g, "")?.replace(/\[(.*?)\]\(.*?\)/g, "$1")?.replace(/\*\*(.*?)\*\*/g, "$1")?.split("\n")?.filter((v) => !!v)?.join("\n")?.replace(/>(.*)/, "")?.replace(/</g, "<").replace(/>/g, ">")?.trim()?.slice(0, count);
|
|
239
254
|
}
|
|
@@ -358,7 +373,7 @@ function patchOptimizeDeps(config) {
|
|
|
358
373
|
}
|
|
359
374
|
|
|
360
375
|
// src/utils/node/theme.ts
|
|
361
|
-
var
|
|
376
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
362
377
|
var import_node_path2 = __toESM(require("path"));
|
|
363
378
|
var import_node_process = __toESM(require("process"));
|
|
364
379
|
var import_node_os = __toESM(require("os"));
|
|
@@ -537,7 +552,7 @@ function getPageRoute(filepath, srcDir) {
|
|
|
537
552
|
}
|
|
538
553
|
var defaultTimeZoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset() / -60;
|
|
539
554
|
async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset) {
|
|
540
|
-
const fileContent = await
|
|
555
|
+
const fileContent = await import_node_fs2.default.promises.readFile(filepath, "utf-8");
|
|
541
556
|
const { data: frontmatter, excerpt, content } = (0, import_gray_matter.default)(fileContent, {
|
|
542
557
|
excerpt: true
|
|
543
558
|
});
|
|
@@ -548,9 +563,7 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset)
|
|
|
548
563
|
meta.title = getDefaultTitle(content);
|
|
549
564
|
}
|
|
550
565
|
const date = await (meta.date && /* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}+${timeZone}`) || getFileBirthTime(filepath));
|
|
551
|
-
|
|
552
|
-
meta.date = formatDate(date);
|
|
553
|
-
}
|
|
566
|
+
meta.date = formatDate(date || /* @__PURE__ */ new Date());
|
|
554
567
|
meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
|
|
555
568
|
meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
|
|
556
569
|
meta.tag = [meta.tag || []].flat().concat([
|
|
@@ -610,7 +623,7 @@ function checkConfig(cfg) {
|
|
|
610
623
|
|
|
611
624
|
// src/utils/node/vitePlugins.ts
|
|
612
625
|
var import_node_path3 = __toESM(require("path"));
|
|
613
|
-
var
|
|
626
|
+
var import_node_fs3 = require("fs");
|
|
614
627
|
var import_node_buffer = require("buffer");
|
|
615
628
|
var import_vitepress_plugin_pagefind = require("vitepress-plugin-pagefind");
|
|
616
629
|
var import_vitepress_plugin_rss = require("vitepress-plugin-rss");
|
|
@@ -736,10 +749,10 @@ function coverImgTransform() {
|
|
|
736
749
|
}
|
|
737
750
|
try {
|
|
738
751
|
const realPath = import_node_path3.default.join(vitepressConfig.root, cover);
|
|
739
|
-
if (!(0,
|
|
752
|
+
if (!(0, import_node_fs3.existsSync)(realPath)) {
|
|
740
753
|
continue;
|
|
741
754
|
}
|
|
742
|
-
const fileBuffer = (0,
|
|
755
|
+
const fileBuffer = (0, import_node_fs3.readFileSync)(realPath);
|
|
743
756
|
const matchAsset = assetsMap.find((v) => import_node_buffer.Buffer.compare(fileBuffer, v.source) === 0);
|
|
744
757
|
if (matchAsset) {
|
|
745
758
|
page.meta.cover = joinPath("/", matchAsset.fileName);
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
UserFilled
|
|
13
13
|
} from '@element-plus/icons-vue'
|
|
14
14
|
import { useBlogConfig, useCurrentArticle, useDocMetaInsertPosition, useDocMetaInsertSelector } from '../composables/config/blog'
|
|
15
|
-
import countWord, { formatShowDate } from '../utils/client'
|
|
15
|
+
import countWord, { formatDate, formatShowDate } from '../utils/client'
|
|
16
16
|
import type { Theme } from '../composables/config'
|
|
17
17
|
import BlogDocCover from './BlogDocCover.vue'
|
|
18
18
|
|
|
@@ -108,6 +108,10 @@ const publishDate = computed(() => {
|
|
|
108
108
|
return formatShowDate(currentArticle.value?.meta?.date || '')
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
+
const hoverDate = computed(() => {
|
|
112
|
+
return currentArticle.value?.meta?.date ? `: ${formatDate(currentArticle.value?.meta?.date)}` : ''
|
|
113
|
+
})
|
|
114
|
+
|
|
111
115
|
const timeTitle = computed(() =>
|
|
112
116
|
frontmatter.value.date ? '发布时间' : '最近修改时间'
|
|
113
117
|
)
|
|
@@ -164,7 +168,7 @@ watch(
|
|
|
164
168
|
{{ author }}
|
|
165
169
|
</template>
|
|
166
170
|
</span>
|
|
167
|
-
<span v-if="publishDate && !hiddenTime" class="publishDate" :title="timeTitle">
|
|
171
|
+
<span v-if="publishDate && !hiddenTime" class="publishDate" :title="timeTitle + hoverDate">
|
|
168
172
|
<ElIcon><Clock /></ElIcon>
|
|
169
173
|
{{ publishDate }}
|
|
170
174
|
</span>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useData } from 'vitepress'
|
|
4
4
|
import { isCurrentWeek } from '../utils/client'
|
|
5
|
-
import { useArticles, useBlogConfig } from '../composables/config/blog'
|
|
5
|
+
import { useArticles, useBlogConfig, useHomeAnalysis } from '../composables/config/blog'
|
|
6
6
|
import BlogAuthor from './BlogAuthor.vue'
|
|
7
7
|
|
|
8
8
|
const { home } = useBlogConfig()
|
|
@@ -31,6 +31,9 @@ const currentWeek = computed(() => {
|
|
|
31
31
|
return isCurrentWeek(pubDate)
|
|
32
32
|
})
|
|
33
33
|
})
|
|
34
|
+
|
|
35
|
+
const analysis = useHomeAnalysis()
|
|
36
|
+
const titles = computed(() => (frontmatter.value?.blog?.analysis?.articles?.title || analysis?.articles?.title || []))
|
|
34
37
|
</script>
|
|
35
38
|
|
|
36
39
|
<template>
|
|
@@ -41,17 +44,17 @@ const currentWeek = computed(() => {
|
|
|
41
44
|
<div class="overview-data">
|
|
42
45
|
<div class="overview-item">
|
|
43
46
|
<span class="count">{{ notHiddenArticles.length }}</span>
|
|
44
|
-
<span class="label"
|
|
47
|
+
<span class="label">{{ titles[0] || '博客文章' }}</span>
|
|
45
48
|
</div>
|
|
46
49
|
<div class="split" />
|
|
47
50
|
<div class="overview-item">
|
|
48
51
|
<span class="count">+{{ currentMonth?.length }}</span>
|
|
49
|
-
<span class="label"
|
|
52
|
+
<span class="label">{{ titles[1] || '本月更新' }}</span>
|
|
50
53
|
</div>
|
|
51
54
|
<div class="split" />
|
|
52
55
|
<div class="overview-item">
|
|
53
56
|
<span class="count">+{{ currentWeek?.length }}</span>
|
|
54
|
-
<span class="label"
|
|
57
|
+
<span class="label">{{ titles[2] || '本周更新' }}</span>
|
|
55
58
|
</div>
|
|
56
59
|
</div>
|
|
57
60
|
</div>
|
|
@@ -233,3 +233,7 @@ export function useCleanUrls() {
|
|
|
233
233
|
export function useImageStyle() {
|
|
234
234
|
return inject(configSymbol)?.value?.blog?.imageStyle || {} as Theme.ImageStyleConfig
|
|
235
235
|
}
|
|
236
|
+
|
|
237
|
+
export function useHomeAnalysis() {
|
|
238
|
+
return inject(configSymbol)?.value?.blog?.home?.analysis
|
|
239
|
+
}
|
|
@@ -185,6 +185,12 @@ export namespace Theme {
|
|
|
185
185
|
style?: 'card' | 'sidebar'
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
export interface HomeAnalysis {
|
|
189
|
+
articles?: {
|
|
190
|
+
title?: string[]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
188
194
|
export interface HomeBlog {
|
|
189
195
|
name?: string
|
|
190
196
|
motto?: string
|
|
@@ -197,6 +203,10 @@ export namespace Theme {
|
|
|
197
203
|
* @default 'card'
|
|
198
204
|
*/
|
|
199
205
|
avatarMode?: 'card' | 'split'
|
|
206
|
+
/**
|
|
207
|
+
* 首页数据分析卡片
|
|
208
|
+
*/
|
|
209
|
+
analysis?: HomeAnalysis
|
|
200
210
|
}
|
|
201
211
|
|
|
202
212
|
export interface ArticleConfig {
|
package/src/utils/node/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint-disable global-require */
|
|
2
2
|
/* eslint-disable prefer-rest-params */
|
|
3
|
-
import { spawn
|
|
3
|
+
import { spawn } from 'node:child_process'
|
|
4
4
|
import path from 'node:path'
|
|
5
|
+
import fs from 'node:fs'
|
|
5
6
|
|
|
6
7
|
export function clearMatterContent(content: string) {
|
|
7
8
|
let first___: unknown
|
|
@@ -36,7 +37,7 @@ export function getDefaultTitle(content: string) {
|
|
|
36
37
|
return match?.[2] || ''
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
const cache = new Map<string, Date>()
|
|
40
|
+
const cache = new Map<string, Date | undefined>()
|
|
40
41
|
export function getFileBirthTime(url: string): Promise<Date | undefined> | Date {
|
|
41
42
|
const cached = cache.get(url)
|
|
42
43
|
if (cached) {
|
|
@@ -48,17 +49,34 @@ export function getFileBirthTime(url: string): Promise<Date | undefined> | Date
|
|
|
48
49
|
const child = spawn('git', ['log', '-1', '--pretty="%ai"', url])
|
|
49
50
|
let output = ''
|
|
50
51
|
child.stdout.on('data', d => (output += String(d)))
|
|
51
|
-
child.on('close', () => {
|
|
52
|
-
|
|
52
|
+
child.on('close', async () => {
|
|
53
|
+
let date: Date | undefined
|
|
54
|
+
if (output.trim()) {
|
|
55
|
+
date = new Date(output)
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
date = await getFileBirthTimeByFs(url)
|
|
59
|
+
}
|
|
53
60
|
cache.set(url, date)
|
|
54
61
|
resolve(date)
|
|
55
62
|
})
|
|
56
|
-
child.on('error', () => {
|
|
57
|
-
|
|
63
|
+
child.on('error', async () => {
|
|
64
|
+
const fsDate = await getFileBirthTimeByFs(url)
|
|
65
|
+
resolve(fsDate)
|
|
58
66
|
})
|
|
59
67
|
})
|
|
60
68
|
}
|
|
61
69
|
|
|
70
|
+
export async function getFileBirthTimeByFs(url: string) {
|
|
71
|
+
try {
|
|
72
|
+
const fsStat = await fs.promises.stat(url)
|
|
73
|
+
return fsStat.birthtime
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
export function getGitTimestamp(file: string) {
|
|
63
81
|
return new Promise((resolve, reject) => {
|
|
64
82
|
const child = spawn('git', ['log', '-1', '--pretty="%ci"', file])
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -70,9 +70,8 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
|
|
|
70
70
|
&& new Date(`${new Date(meta.date).toUTCString()}+${timeZone}`))
|
|
71
71
|
|| getFileBirthTime(filepath)
|
|
72
72
|
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
73
|
+
// 无法获取时兜底当前时间
|
|
74
|
+
meta.date = formatDate(date || new Date())
|
|
76
75
|
|
|
77
76
|
// 处理tags和categories,兼容历史文章
|
|
78
77
|
meta.categories
|