@sugarat/theme 0.4.13 → 0.5.1
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 +13 -1
- package/node.js +147 -52
- package/node.mjs +755 -0
- package/package.json +13 -10
- package/src/components/BlogAlert.vue +10 -9
- package/src/components/BlogArticleAnalyze.vue +8 -9
- package/src/components/BlogAuthor.vue +6 -5
- package/src/components/BlogBackToTop.vue +8 -10
- package/src/components/BlogButtonAfterArticle.vue +5 -14
- package/src/components/BlogCommentWrapper.vue +11 -28
- package/src/components/BlogDocCover.vue +3 -3
- package/src/components/BlogFooter.vue +3 -1
- package/src/components/BlogFriendLink.vue +4 -3
- package/src/components/BlogHomeBanner.vue +7 -6
- package/src/components/BlogHomeHeaderAvatar.vue +3 -3
- package/src/components/BlogHomeOverview.vue +4 -4
- package/src/components/BlogHomeTags.vue +5 -5
- package/src/components/BlogHotArticle.vue +4 -7
- package/src/components/BlogItem.vue +4 -3
- package/src/components/BlogList.vue +7 -6
- package/src/components/BlogRecommendArticle.vue +11 -14
- package/src/components/BlogSidebar.vue +9 -15
- package/src/components/CommentArtalk.vue +7 -5
- package/src/components/CommentGiscus.vue +7 -8
- package/src/components/Icon.vue +33 -0
- package/src/composables/config/blog.ts +207 -89
- package/src/composables/config/index.ts +9 -0
- package/src/hooks/useOml2d.ts +15 -8
- package/src/index.ts +3 -0
- package/src/node.ts +5 -1
- package/src/styles/index.scss +6 -6
- package/src/utils/node/hot-reload-plugin.ts +31 -1
- package/src/utils/node/index.ts +0 -2
- package/src/utils/node/mdPlugins.ts +4 -0
- package/src/utils/node/theme.ts +15 -18
- package/src/utils/node/vitePlugins.ts +120 -34
package/node.mjs
ADDED
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/utils/node/mdPlugins.ts
|
|
10
|
+
import { createRequire } from "module";
|
|
11
|
+
|
|
12
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.4.1_@algolia+client-search@4.19.1_@types+node@20.6.3__4q6ku3o3anoir4jnhobsqtwjza/node_modules/vitepress-plugin-tabs/dist/index.js
|
|
13
|
+
var tabsMarker = "=tabs";
|
|
14
|
+
var tabsMarkerLen = tabsMarker.length;
|
|
15
|
+
var ruleBlockTabs = (state, startLine, endLine, silent) => {
|
|
16
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
20
|
+
let max = state.eMarks[startLine];
|
|
21
|
+
if (pos + 3 > max) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const marker = state.src.charCodeAt(pos);
|
|
25
|
+
if (marker !== 58) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const mem = pos;
|
|
29
|
+
pos = state.skipChars(pos, marker);
|
|
30
|
+
let len = pos - mem;
|
|
31
|
+
if (len < 3) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (state.src.slice(pos, pos + tabsMarkerLen) !== tabsMarker) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
pos += tabsMarkerLen;
|
|
38
|
+
if (silent) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const markup = state.src.slice(mem, pos);
|
|
42
|
+
const params = state.src.slice(pos, max);
|
|
43
|
+
let nextLine = startLine;
|
|
44
|
+
let haveEndMarker = false;
|
|
45
|
+
for (; ; ) {
|
|
46
|
+
nextLine++;
|
|
47
|
+
if (nextLine >= endLine) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
pos = state.bMarks[nextLine] + state.tShift[nextLine];
|
|
51
|
+
const mem2 = pos;
|
|
52
|
+
max = state.eMarks[nextLine];
|
|
53
|
+
if (pos < max && state.sCount[nextLine] < state.blkIndent) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
if (state.src.charCodeAt(pos) !== marker) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (state.sCount[nextLine] - state.blkIndent >= 4) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
pos = state.skipChars(pos, marker);
|
|
63
|
+
if (pos - mem2 < len) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
pos = state.skipSpaces(pos);
|
|
67
|
+
if (pos < max) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
haveEndMarker = true;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
len = state.sCount[startLine];
|
|
74
|
+
state.line = nextLine + (haveEndMarker ? 1 : 0);
|
|
75
|
+
const token = state.push("tabs", "div", 0);
|
|
76
|
+
token.info = params;
|
|
77
|
+
token.content = state.getLines(startLine + 1, nextLine, len, true);
|
|
78
|
+
token.markup = markup;
|
|
79
|
+
token.map = [startLine, state.line];
|
|
80
|
+
return true;
|
|
81
|
+
};
|
|
82
|
+
var tabBreakRE = /^\s*::(.+)$/;
|
|
83
|
+
var forbiddenCharsInSlotNames = /[ '"]/;
|
|
84
|
+
var parseTabBreakLine = (line) => {
|
|
85
|
+
const m = line.match(tabBreakRE);
|
|
86
|
+
if (!m)
|
|
87
|
+
return null;
|
|
88
|
+
const trimmed = m[1].trim();
|
|
89
|
+
if (forbiddenCharsInSlotNames.test(trimmed)) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`contains forbidden chars in slot names (space and quotes) (${JSON.stringify(
|
|
92
|
+
line
|
|
93
|
+
)})`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return trimmed;
|
|
97
|
+
};
|
|
98
|
+
var lastLineBreakRE = /\n$/;
|
|
99
|
+
var parseTabsContent = (content) => {
|
|
100
|
+
const lines = content.replace(lastLineBreakRE, "").split("\n");
|
|
101
|
+
const tabInfos = [];
|
|
102
|
+
const tabLabels = /* @__PURE__ */ new Set();
|
|
103
|
+
let currentTab = null;
|
|
104
|
+
const createTabInfo = (label) => {
|
|
105
|
+
if (tabLabels.has(label)) {
|
|
106
|
+
throw new Error(`a tab labelled ${JSON.stringify(label)} already exists`);
|
|
107
|
+
}
|
|
108
|
+
const newTab = { label, content: [] };
|
|
109
|
+
tabInfos.push(newTab);
|
|
110
|
+
tabLabels.add(label);
|
|
111
|
+
return newTab;
|
|
112
|
+
};
|
|
113
|
+
for (const line of lines) {
|
|
114
|
+
const tabLabel = parseTabBreakLine(line);
|
|
115
|
+
if (currentTab === null) {
|
|
116
|
+
if (tabLabel === null) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`tabs should start with \`::\${tabLabel}\` (e.g. "::foo"). (received: ${JSON.stringify(
|
|
119
|
+
line
|
|
120
|
+
)})`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
currentTab = createTabInfo(tabLabel);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (tabLabel === null) {
|
|
127
|
+
currentTab.content.push(line);
|
|
128
|
+
} else {
|
|
129
|
+
currentTab = createTabInfo(tabLabel);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (tabInfos.length < 0) {
|
|
133
|
+
throw new Error("tabs should include at least one tab");
|
|
134
|
+
}
|
|
135
|
+
return tabInfos.map((info) => ({
|
|
136
|
+
label: info.label,
|
|
137
|
+
content: info.content.join("\n").replace(lastLineBreakRE, "")
|
|
138
|
+
}));
|
|
139
|
+
};
|
|
140
|
+
var parseParams = (input) => {
|
|
141
|
+
if (!input.startsWith("=")) {
|
|
142
|
+
return {
|
|
143
|
+
shareStateKey: void 0
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const splitted = input.split("=");
|
|
147
|
+
return {
|
|
148
|
+
shareStateKey: splitted[1]
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
var tabsPlugin = (md) => {
|
|
152
|
+
md.block.ruler.before("fence", "=tabs", ruleBlockTabs, {
|
|
153
|
+
alt: ["paragraph", "reference", "blockquote", "list"]
|
|
154
|
+
});
|
|
155
|
+
md.renderer.rules.tabs = (tokens, index, _options, env) => {
|
|
156
|
+
const token = tokens[index];
|
|
157
|
+
const tabs = parseTabsContent(token.content);
|
|
158
|
+
const renderedTabs = tabs.map((tab) => ({
|
|
159
|
+
label: tab.label,
|
|
160
|
+
content: md.render(tab.content, env)
|
|
161
|
+
}));
|
|
162
|
+
const params = parseParams(token.info);
|
|
163
|
+
const tabLabelsProp = `:tabLabels="${md.utils.escapeHtml(
|
|
164
|
+
JSON.stringify(tabs.map((tab) => tab.label))
|
|
165
|
+
)}"`;
|
|
166
|
+
const shareStateKeyProp = params.shareStateKey ? `sharedStateKey="${md.utils.escapeHtml(params.shareStateKey)}"` : "";
|
|
167
|
+
const slots = renderedTabs.map(
|
|
168
|
+
(tab) => `<template #${tab.label}>${tab.content}</template>`
|
|
169
|
+
);
|
|
170
|
+
return `<PluginTabs ${tabLabelsProp} ${shareStateKeyProp}>${slots.join(
|
|
171
|
+
""
|
|
172
|
+
)}</PluginTabs>`;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/utils/node/mdPlugins.ts
|
|
177
|
+
import timeline from "vitepress-markdown-timeline";
|
|
178
|
+
import { groupIconMdPlugin } from "vitepress-plugin-group-icons";
|
|
179
|
+
|
|
180
|
+
// src/utils/node/index.ts
|
|
181
|
+
import path from "node:path";
|
|
182
|
+
import { joinPath } from "@sugarat/theme-shared";
|
|
183
|
+
function aliasObjectToArray(obj) {
|
|
184
|
+
return Object.entries(obj).map(([find, replacement]) => ({
|
|
185
|
+
find,
|
|
186
|
+
replacement
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
function isBase64ImageURL(url) {
|
|
190
|
+
const regex = /^data:image\/[a-z]+;base64,/;
|
|
191
|
+
return regex.test(url);
|
|
192
|
+
}
|
|
193
|
+
var imageRegex = /!\[.*?\]\((.*?)\s*(".*?")?\)/;
|
|
194
|
+
function getFirstImagURLFromMD(content, route) {
|
|
195
|
+
const url = content.match(imageRegex)?.[1];
|
|
196
|
+
const isHTTPSource = url && url.startsWith("http");
|
|
197
|
+
if (!url) {
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
if (isHTTPSource || isBase64ImageURL(url)) {
|
|
201
|
+
return url;
|
|
202
|
+
}
|
|
203
|
+
const paths = joinPath("/", route).split("/");
|
|
204
|
+
paths.splice(paths.length - 1, 1);
|
|
205
|
+
const relativePath = url.startsWith("/") ? url : path.join(paths.join("/") || "", url);
|
|
206
|
+
return joinPath("/", relativePath);
|
|
207
|
+
}
|
|
208
|
+
function debounce(func, delay = 1e3) {
|
|
209
|
+
let timeoutId;
|
|
210
|
+
return (...rest) => {
|
|
211
|
+
clearTimeout(timeoutId);
|
|
212
|
+
timeoutId = setTimeout(() => {
|
|
213
|
+
func(...rest);
|
|
214
|
+
}, delay);
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function isEqual(obj1, obj2, excludeKeys = []) {
|
|
218
|
+
const keys1 = Object.keys(obj1).filter((key) => !excludeKeys.includes(key));
|
|
219
|
+
const keys2 = Object.keys(obj2).filter((key) => !excludeKeys.includes(key));
|
|
220
|
+
if (keys1.length !== keys2.length) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
for (const key of keys1) {
|
|
224
|
+
if (!keys2.includes(key)) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const val1 = obj1[key];
|
|
228
|
+
const val2 = obj2[key];
|
|
229
|
+
const areObjects = isObject(val1) && isObject(val2);
|
|
230
|
+
if (areObjects && !isEqual(val1, val2, excludeKeys) || !areObjects && val1 !== val2) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
function isObject(obj) {
|
|
237
|
+
return obj != null && typeof obj === "object";
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/utils/node/mdPlugins.ts
|
|
241
|
+
function _require(module) {
|
|
242
|
+
return (typeof import.meta?.url !== "undefined" ? createRequire(import.meta.url) : __require)(module);
|
|
243
|
+
}
|
|
244
|
+
function getMarkdownPlugins(cfg) {
|
|
245
|
+
const markdownPlugin = [];
|
|
246
|
+
if (cfg?.tabs !== false) {
|
|
247
|
+
markdownPlugin.push(tabsPlugin);
|
|
248
|
+
}
|
|
249
|
+
if (cfg?.mermaid !== false) {
|
|
250
|
+
const { MermaidMarkdown } = _require("vitepress-plugin-mermaid");
|
|
251
|
+
markdownPlugin.push(MermaidMarkdown);
|
|
252
|
+
}
|
|
253
|
+
if (cfg?.taskCheckbox !== false) {
|
|
254
|
+
markdownPlugin.push(taskCheckboxPlugin(typeof cfg?.taskCheckbox === "boolean" ? {} : cfg?.taskCheckbox));
|
|
255
|
+
}
|
|
256
|
+
if (cfg?.timeline !== false) {
|
|
257
|
+
markdownPlugin.push(timeline);
|
|
258
|
+
}
|
|
259
|
+
markdownPlugin.push(groupIconMdPlugin);
|
|
260
|
+
return markdownPlugin;
|
|
261
|
+
}
|
|
262
|
+
function taskCheckboxPlugin(ops) {
|
|
263
|
+
return (md) => {
|
|
264
|
+
md.use(_require("markdown-it-task-checkbox"), ops);
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function registerMdPlugins(vpCfg, plugins) {
|
|
268
|
+
if (plugins.length) {
|
|
269
|
+
vpCfg.markdown = {
|
|
270
|
+
config(...rest) {
|
|
271
|
+
plugins.forEach((plugin) => {
|
|
272
|
+
plugin?.(...rest);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function patchMermaidPluginCfg(config) {
|
|
279
|
+
if (!config.vite.resolve)
|
|
280
|
+
config.vite.resolve = {};
|
|
281
|
+
if (!config.vite.resolve.alias)
|
|
282
|
+
config.vite.resolve.alias = {};
|
|
283
|
+
config.vite.resolve.alias = [
|
|
284
|
+
...aliasObjectToArray({
|
|
285
|
+
...config.vite.resolve.alias,
|
|
286
|
+
"cytoscape/dist/cytoscape.umd.js": "cytoscape/dist/cytoscape.esm.js",
|
|
287
|
+
"mermaid": "mermaid/dist/mermaid.esm.mjs"
|
|
288
|
+
}),
|
|
289
|
+
{ find: /^dayjs\/(.*).js/, replacement: "dayjs/esm/$1" }
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
function patchOptimizeDeps(config) {
|
|
293
|
+
if (!config.vite.optimizeDeps) {
|
|
294
|
+
config.vite.optimizeDeps = {};
|
|
295
|
+
}
|
|
296
|
+
config.vite.optimizeDeps.exclude = ["vitepress-plugin-tabs", "@sugarat/theme"];
|
|
297
|
+
config.vite.optimizeDeps.include = ["element-plus"];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/utils/node/theme.ts
|
|
301
|
+
import fs from "node:fs";
|
|
302
|
+
import { getDefaultTitle, getFileLastModifyTime, getTextSummary, getVitePressPages, grayMatter, normalizePath, renderDynamicMarkdown } from "@sugarat/theme-shared";
|
|
303
|
+
|
|
304
|
+
// src/utils/client/index.ts
|
|
305
|
+
function formatDate(d, fmt = "yyyy-MM-dd hh:mm:ss") {
|
|
306
|
+
if (!(d instanceof Date)) {
|
|
307
|
+
d = new Date(d);
|
|
308
|
+
}
|
|
309
|
+
const o = {
|
|
310
|
+
"M+": d.getMonth() + 1,
|
|
311
|
+
// 月份
|
|
312
|
+
"d+": d.getDate(),
|
|
313
|
+
// 日
|
|
314
|
+
"h+": d.getHours(),
|
|
315
|
+
// 小时
|
|
316
|
+
"m+": d.getMinutes(),
|
|
317
|
+
// 分
|
|
318
|
+
"s+": d.getSeconds(),
|
|
319
|
+
// 秒
|
|
320
|
+
"q+": Math.floor((d.getMonth() + 3) / 3),
|
|
321
|
+
// 季度
|
|
322
|
+
"S": d.getMilliseconds()
|
|
323
|
+
// 毫秒
|
|
324
|
+
};
|
|
325
|
+
if (/(y+)/.test(fmt)) {
|
|
326
|
+
fmt = fmt.replace(
|
|
327
|
+
RegExp.$1,
|
|
328
|
+
`${d.getFullYear()}`.substr(4 - RegExp.$1.length)
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
for (const k in o) {
|
|
332
|
+
if (new RegExp(`(${k})`).test(fmt))
|
|
333
|
+
fmt = fmt.replace(
|
|
334
|
+
RegExp.$1,
|
|
335
|
+
RegExp.$1.length === 1 ? o[k] : `00${o[k]}`.substr(`${o[k]}`.length)
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
return fmt;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/utils/node/theme.ts
|
|
342
|
+
function patchDefaultThemeSideBar(cfg) {
|
|
343
|
+
return cfg?.blog !== false && cfg?.recommend !== false ? {
|
|
344
|
+
sidebar: [
|
|
345
|
+
{
|
|
346
|
+
text: "",
|
|
347
|
+
items: []
|
|
348
|
+
}
|
|
349
|
+
]
|
|
350
|
+
} : void 0;
|
|
351
|
+
}
|
|
352
|
+
var defaultTimeZoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset() / -60;
|
|
353
|
+
async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset, baseContent) {
|
|
354
|
+
const fileContent = baseContent || await fs.promises.readFile(filepath, "utf-8");
|
|
355
|
+
const { data: frontmatter, excerpt, content } = grayMatter(fileContent, {
|
|
356
|
+
excerpt: true
|
|
357
|
+
});
|
|
358
|
+
const meta = {
|
|
359
|
+
...frontmatter
|
|
360
|
+
};
|
|
361
|
+
if (!meta.title) {
|
|
362
|
+
meta.title = getDefaultTitle(content);
|
|
363
|
+
}
|
|
364
|
+
const utcValue = timeZone >= 0 ? `+${timeZone}` : `${timeZone}`;
|
|
365
|
+
const date = await (meta.date && /* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}${utcValue}`) || getFileLastModifyTime(filepath));
|
|
366
|
+
meta.date = formatDate(date || /* @__PURE__ */ new Date());
|
|
367
|
+
meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
|
|
368
|
+
meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
|
|
369
|
+
meta.tag = [meta.tag || []].flat().concat([
|
|
370
|
+
.../* @__PURE__ */ new Set([...meta.categories || [], ...meta.tags || []])
|
|
371
|
+
]);
|
|
372
|
+
meta.description = meta.description || getTextSummary(content, 100) || excerpt;
|
|
373
|
+
meta.cover = meta.cover ?? getFirstImagURLFromMD(fileContent, route);
|
|
374
|
+
if (meta.publish === false) {
|
|
375
|
+
meta.hidden = true;
|
|
376
|
+
meta.recommend = false;
|
|
377
|
+
}
|
|
378
|
+
return meta;
|
|
379
|
+
}
|
|
380
|
+
async function getArticles(cfg, vpConfig) {
|
|
381
|
+
const pages = getVitePressPages(vpConfig);
|
|
382
|
+
const metaResults = pages.reduce((prev, value) => {
|
|
383
|
+
const { page, route, originRoute, filepath, isDynamic, dynamicRoute } = value;
|
|
384
|
+
const metaPromise = isDynamic && dynamicRoute ? getArticleMeta(filepath, originRoute, cfg?.timeZone, renderDynamicMarkdown(filepath, dynamicRoute.params, dynamicRoute.content)) : getArticleMeta(filepath, originRoute, cfg?.timeZone);
|
|
385
|
+
prev[page] = {
|
|
386
|
+
route,
|
|
387
|
+
metaPromise
|
|
388
|
+
};
|
|
389
|
+
return prev;
|
|
390
|
+
}, {});
|
|
391
|
+
const pageData = [];
|
|
392
|
+
for (const page of pages) {
|
|
393
|
+
const { route, metaPromise } = metaResults[page.page];
|
|
394
|
+
const meta = await metaPromise;
|
|
395
|
+
if (meta.layout === "home") {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
pageData.push({
|
|
399
|
+
route,
|
|
400
|
+
meta
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return pageData;
|
|
404
|
+
}
|
|
405
|
+
function patchVPConfig(vpConfig, cfg) {
|
|
406
|
+
vpConfig.head = vpConfig.head || [];
|
|
407
|
+
if (cfg?.comment && "type" in cfg.comment && cfg?.comment?.type === "artalk") {
|
|
408
|
+
const server = cfg.comment?.options?.server;
|
|
409
|
+
if (server) {
|
|
410
|
+
vpConfig.head.push(["link", { href: `${server} /dist/Artalk.css`, rel: "stylesheet" }]);
|
|
411
|
+
vpConfig.head.push(["script", { src: `${server} /dist/Artalk.js`, id: "artalk-script" }]);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function patchVPThemeConfig(cfg, vpThemeConfig = {}) {
|
|
416
|
+
vpThemeConfig.sidebar = patchDefaultThemeSideBar(cfg)?.sidebar;
|
|
417
|
+
return vpThemeConfig;
|
|
418
|
+
}
|
|
419
|
+
function checkConfig(cfg) {
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/utils/node/vitePlugins.ts
|
|
423
|
+
import {
|
|
424
|
+
pagefindPlugin
|
|
425
|
+
} from "vitepress-plugin-pagefind";
|
|
426
|
+
import { RssPlugin } from "vitepress-plugin-rss";
|
|
427
|
+
import { joinPath as joinPath2 } from "@sugarat/theme-shared";
|
|
428
|
+
import { AnnouncementPlugin } from "vitepress-plugin-announcement";
|
|
429
|
+
import { groupIconVitePlugin } from "vitepress-plugin-group-icons";
|
|
430
|
+
|
|
431
|
+
// src/utils/node/hot-reload-plugin.ts
|
|
432
|
+
import fs2 from "fs";
|
|
433
|
+
import { grayMatter as grayMatter2 } from "@sugarat/theme-shared";
|
|
434
|
+
function themeReloadPlugin() {
|
|
435
|
+
let blogConfig;
|
|
436
|
+
let vitepressConfig;
|
|
437
|
+
let docsDir;
|
|
438
|
+
const generateRoute = (filepath) => {
|
|
439
|
+
return filepath.replace(docsDir, "").replace(".md", "");
|
|
440
|
+
};
|
|
441
|
+
return {
|
|
442
|
+
name: "@sugarat/theme-reload",
|
|
443
|
+
apply: "serve",
|
|
444
|
+
configureServer(server) {
|
|
445
|
+
const restart = debounce(() => {
|
|
446
|
+
server.restart();
|
|
447
|
+
}, 500);
|
|
448
|
+
server.watcher.on("add", async (path2) => {
|
|
449
|
+
const route = generateRoute(path2);
|
|
450
|
+
const meta = await getArticleMeta(path2, route, blogConfig?.timeZone);
|
|
451
|
+
blogConfig.pagesData.push({
|
|
452
|
+
route,
|
|
453
|
+
meta
|
|
454
|
+
});
|
|
455
|
+
restart();
|
|
456
|
+
});
|
|
457
|
+
server.watcher.on("change", async (path2) => {
|
|
458
|
+
const route = generateRoute(path2);
|
|
459
|
+
const fileContent = await fs2.promises.readFile(path2, "utf-8");
|
|
460
|
+
const { data: frontmatter } = grayMatter2(fileContent, {
|
|
461
|
+
excerpt: true
|
|
462
|
+
});
|
|
463
|
+
const meta = await getArticleMeta(path2, route, blogConfig?.timeZone);
|
|
464
|
+
const matched = blogConfig.pagesData.find((v) => v.route === route);
|
|
465
|
+
const excludeKeys = ["date", "description"].filter((key) => !frontmatter[key]);
|
|
466
|
+
const inlineKeys = [
|
|
467
|
+
// vitepress 默认主题 https://vitepress.dev/zh/reference/frontmatter-config
|
|
468
|
+
"lang",
|
|
469
|
+
"outline",
|
|
470
|
+
"head",
|
|
471
|
+
"layout",
|
|
472
|
+
"hero",
|
|
473
|
+
"features",
|
|
474
|
+
"navbar",
|
|
475
|
+
"sidebar",
|
|
476
|
+
"aside",
|
|
477
|
+
"lastUpdated",
|
|
478
|
+
"editLink",
|
|
479
|
+
"footer",
|
|
480
|
+
"pageClass",
|
|
481
|
+
// 本主题扩展 https://theme.sugarat.top/config/frontmatter.html
|
|
482
|
+
"hiddenCover",
|
|
483
|
+
"readingTime",
|
|
484
|
+
"buttonAfterArticle"
|
|
485
|
+
];
|
|
486
|
+
if (matched && !isEqual(matched.meta, meta, inlineKeys.concat(excludeKeys))) {
|
|
487
|
+
matched.meta = meta;
|
|
488
|
+
restart();
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
server.watcher.on("unlink", (path2) => {
|
|
492
|
+
const route = generateRoute(path2);
|
|
493
|
+
const idx = blogConfig.pagesData.findIndex((v) => v.route === route);
|
|
494
|
+
if (idx >= 0) {
|
|
495
|
+
blogConfig.pagesData.splice(idx, 1);
|
|
496
|
+
restart();
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
},
|
|
500
|
+
configResolved(config) {
|
|
501
|
+
vitepressConfig = config.vitepress;
|
|
502
|
+
docsDir = vitepressConfig.srcDir;
|
|
503
|
+
blogConfig = config.vitepress.site.themeConfig.blog;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/utils/node/vitePlugins.ts
|
|
509
|
+
function getVitePlugins(cfg = {}) {
|
|
510
|
+
const plugins = [];
|
|
511
|
+
plugins.push(coverImgTransform());
|
|
512
|
+
if (cfg.themeColor) {
|
|
513
|
+
plugins.push(setThemeScript(cfg.themeColor));
|
|
514
|
+
}
|
|
515
|
+
plugins.push(themeReloadPlugin());
|
|
516
|
+
plugins.push(providePageData(cfg));
|
|
517
|
+
if (cfg && cfg.search !== false) {
|
|
518
|
+
const ops = cfg.search instanceof Object ? cfg.search : {};
|
|
519
|
+
plugins.push(
|
|
520
|
+
pagefindPlugin({
|
|
521
|
+
...ops
|
|
522
|
+
})
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
if (cfg?.mermaid !== false) {
|
|
526
|
+
const { MermaidPlugin } = _require("vitepress-plugin-mermaid");
|
|
527
|
+
plugins.push(inlineInjectMermaidClient());
|
|
528
|
+
plugins.push(MermaidPlugin(cfg?.mermaid === true ? {} : cfg?.mermaid ?? {}));
|
|
529
|
+
}
|
|
530
|
+
if (cfg?.RSS) {
|
|
531
|
+
;
|
|
532
|
+
[cfg?.RSS].flat().forEach((rssConfig) => plugins.push(RssPlugin(rssConfig)));
|
|
533
|
+
}
|
|
534
|
+
if (cfg?.popover) {
|
|
535
|
+
plugins.push(AnnouncementPlugin(cfg.popover));
|
|
536
|
+
}
|
|
537
|
+
plugins.push(groupIconVitePlugin(cfg?.groupIcon));
|
|
538
|
+
return plugins;
|
|
539
|
+
}
|
|
540
|
+
function registerVitePlugins(vpCfg, plugins) {
|
|
541
|
+
vpCfg.vite = {
|
|
542
|
+
plugins
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function inlineInjectMermaidClient() {
|
|
546
|
+
return {
|
|
547
|
+
name: "@sugarat/theme-plugin-inline-inject-mermaid-client",
|
|
548
|
+
enforce: "pre",
|
|
549
|
+
transform(code, id) {
|
|
550
|
+
if (id.endsWith("src/index.ts") && code.startsWith("// @sugarat/theme index")) {
|
|
551
|
+
return code.replace("// replace-mermaid-import-code", "import Mermaid from 'vitepress-plugin-mermaid/Mermaid.vue'").replace("// replace-mermaid-mounted-code", "if (!ctx.app.component('Mermaid')) { ctx.app.component('Mermaid', Mermaid as any) }");
|
|
552
|
+
}
|
|
553
|
+
return code;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function coverImgTransform() {
|
|
558
|
+
let blogConfig;
|
|
559
|
+
let vitepressConfig;
|
|
560
|
+
let assetsDir;
|
|
561
|
+
const relativeMetaName = ["cover"];
|
|
562
|
+
const relativeMeta = [];
|
|
563
|
+
const relativeMetaMap = {};
|
|
564
|
+
const viteAssetsMap = {};
|
|
565
|
+
const relativePathMap = {};
|
|
566
|
+
return {
|
|
567
|
+
name: "@sugarat/theme-plugin-cover-transform",
|
|
568
|
+
apply: "build",
|
|
569
|
+
// enforce: 'pre',
|
|
570
|
+
configResolved(config) {
|
|
571
|
+
vitepressConfig = config.vitepress;
|
|
572
|
+
assetsDir = vitepressConfig.assetsDir;
|
|
573
|
+
blogConfig = config.vitepress.site.themeConfig.blog;
|
|
574
|
+
const pagesData = [...blogConfig.pagesData];
|
|
575
|
+
if (vitepressConfig.site.locales && Object.keys(vitepressConfig.site.locales).length > 1 && blogConfig?.locales) {
|
|
576
|
+
Object.values(blogConfig?.locales).map((v) => v.pagesData).filter((v) => !!v).forEach((v) => pagesData.push(...v));
|
|
577
|
+
}
|
|
578
|
+
pagesData.forEach((v) => {
|
|
579
|
+
relativeMetaName.forEach((k) => {
|
|
580
|
+
const value = v.meta[k];
|
|
581
|
+
if (value && typeof value === "string" && value.startsWith("/")) {
|
|
582
|
+
const absolutePath = `${vitepressConfig.srcDir}${value}`;
|
|
583
|
+
if (relativeMetaMap[absolutePath]) {
|
|
584
|
+
Object.assign(v.meta, { [k]: relativeMetaMap[absolutePath][k] });
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
relativePathMap[value] = absolutePath;
|
|
588
|
+
relativePathMap[absolutePath] = value;
|
|
589
|
+
relativeMeta.push(v.meta);
|
|
590
|
+
relativeMetaMap[absolutePath] = v.meta;
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
},
|
|
595
|
+
moduleParsed(info) {
|
|
596
|
+
if (!relativePathMap[info.id]) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const asset = info.code?.match(/export default "(.*)"/)?.[1];
|
|
600
|
+
if (!asset) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
viteAssetsMap[info.id] = asset;
|
|
604
|
+
viteAssetsMap[asset] = info.id;
|
|
605
|
+
relativeMeta.forEach((meta) => {
|
|
606
|
+
relativeMetaName.forEach((k) => {
|
|
607
|
+
const value = meta[k];
|
|
608
|
+
if (!value || !relativePathMap[value]) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const viteAsset = viteAssetsMap[relativePathMap[value]];
|
|
612
|
+
if (viteAsset) {
|
|
613
|
+
Object.assign(meta, { [k]: viteAsset });
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
},
|
|
618
|
+
generateBundle(_, bundle) {
|
|
619
|
+
const assetsMap = Object.entries(bundle).filter(([key]) => {
|
|
620
|
+
return key.startsWith(assetsDir);
|
|
621
|
+
}).map(([_2, value]) => {
|
|
622
|
+
return value;
|
|
623
|
+
}).filter((v) => v.type === "asset");
|
|
624
|
+
if (!assetsMap.length) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
relativeMeta.forEach((meta) => {
|
|
628
|
+
relativeMetaName.forEach((k) => {
|
|
629
|
+
const value = meta[k];
|
|
630
|
+
if (!value || !viteAssetsMap[value]) {
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const absolutePath = viteAssetsMap[value];
|
|
634
|
+
const matchAsset = assetsMap.find((v) => joinPath2(`${vitepressConfig.srcDir}/`, v.originalFileName) === absolutePath);
|
|
635
|
+
if (matchAsset) {
|
|
636
|
+
Object.assign(meta, { [k]: joinPath2("/", matchAsset.fileName) });
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function providePageData(cfg) {
|
|
644
|
+
return {
|
|
645
|
+
name: "@sugarat/theme-plugin-provide-page-data",
|
|
646
|
+
async config(config, env) {
|
|
647
|
+
const vitepressConfig = config.vitepress;
|
|
648
|
+
const pagesData = await getArticles(cfg, vitepressConfig);
|
|
649
|
+
if (vitepressConfig.site.locales && Object.keys(vitepressConfig.site.locales).length > 1) {
|
|
650
|
+
if (!vitepressConfig.site.themeConfig.blog.locales) {
|
|
651
|
+
vitepressConfig.site.themeConfig.blog.locales = {};
|
|
652
|
+
}
|
|
653
|
+
const localeKeys = Object.keys(vitepressConfig.site.locales);
|
|
654
|
+
localeKeys.forEach((localeKey) => {
|
|
655
|
+
if (!vitepressConfig.site.themeConfig.blog.locales[localeKey]) {
|
|
656
|
+
vitepressConfig.site.themeConfig.blog.locales[localeKey] = {};
|
|
657
|
+
}
|
|
658
|
+
vitepressConfig.site.themeConfig.blog.locales[localeKey].pagesData = pagesData.filter((v) => {
|
|
659
|
+
const { route } = v;
|
|
660
|
+
const isRoot = localeKey === "root";
|
|
661
|
+
if (isRoot) {
|
|
662
|
+
return !localeKeys.filter((v2) => v2 !== "root").some((k) => route.startsWith(`/${k}`));
|
|
663
|
+
}
|
|
664
|
+
return route.startsWith(`/${localeKey}`);
|
|
665
|
+
});
|
|
666
|
+
});
|
|
667
|
+
if (env.mode === "production") {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
vitepressConfig.site.themeConfig.blog.pagesData = pagesData;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function setThemeScript(themeColor) {
|
|
676
|
+
let resolveConfig;
|
|
677
|
+
const pluginOps = {
|
|
678
|
+
name: "@sugarat/theme-plugin-theme-color-script",
|
|
679
|
+
enforce: "pre",
|
|
680
|
+
configResolved(config) {
|
|
681
|
+
if (resolveConfig) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
resolveConfig = config;
|
|
685
|
+
const vitepressConfig = config.vitepress;
|
|
686
|
+
if (!vitepressConfig) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const selfTransformHead = vitepressConfig.transformHead;
|
|
690
|
+
vitepressConfig.transformHead = async (ctx) => {
|
|
691
|
+
const selfHead = await Promise.resolve(selfTransformHead?.(ctx)) || [];
|
|
692
|
+
return selfHead.concat([
|
|
693
|
+
["script", { type: "text/javascript" }, `;(function() {
|
|
694
|
+
document.documentElement.setAttribute("theme", "${themeColor}");
|
|
695
|
+
})()`]
|
|
696
|
+
]);
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
return pluginOps;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// src/node.ts
|
|
704
|
+
function getThemeConfig(cfg = {}) {
|
|
705
|
+
checkConfig(cfg);
|
|
706
|
+
cfg.mermaid = cfg.mermaid ?? false;
|
|
707
|
+
const pagesData = [];
|
|
708
|
+
const extraVPConfig = {
|
|
709
|
+
vite: {}
|
|
710
|
+
};
|
|
711
|
+
const vitePlugins = getVitePlugins(cfg);
|
|
712
|
+
registerVitePlugins(extraVPConfig, vitePlugins);
|
|
713
|
+
const markdownPlugin = getMarkdownPlugins(cfg);
|
|
714
|
+
registerMdPlugins(extraVPConfig, markdownPlugin);
|
|
715
|
+
if (cfg?.mermaid !== false) {
|
|
716
|
+
patchMermaidPluginCfg(extraVPConfig);
|
|
717
|
+
}
|
|
718
|
+
patchOptimizeDeps(extraVPConfig);
|
|
719
|
+
patchVPConfig(extraVPConfig, cfg);
|
|
720
|
+
return {
|
|
721
|
+
themeConfig: {
|
|
722
|
+
blog: {
|
|
723
|
+
pagesData,
|
|
724
|
+
// 插件里补全
|
|
725
|
+
...cfg
|
|
726
|
+
},
|
|
727
|
+
// 补充一些额外的配置用于继承
|
|
728
|
+
...patchVPThemeConfig(cfg)
|
|
729
|
+
},
|
|
730
|
+
...extraVPConfig
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function defineConfig(config) {
|
|
734
|
+
return config;
|
|
735
|
+
}
|
|
736
|
+
function defineLocaleConfig(cfg) {
|
|
737
|
+
return cfg;
|
|
738
|
+
}
|
|
739
|
+
function footerHTML(footerData) {
|
|
740
|
+
const data = [footerData || []].flat();
|
|
741
|
+
return data.map((d) => {
|
|
742
|
+
const { icon, text, link } = d;
|
|
743
|
+
return `<span class="footer-item">
|
|
744
|
+
${icon ? `<i>${icon}</i>` : ""}
|
|
745
|
+
${link ? `<a href="${link}" target="_blank" rel="noopener noreferrer">${text}</a>` : `<span>${text}</span>`}
|
|
746
|
+
</span>`;
|
|
747
|
+
}).join("");
|
|
748
|
+
}
|
|
749
|
+
export {
|
|
750
|
+
defineConfig,
|
|
751
|
+
defineLocaleConfig,
|
|
752
|
+
footerHTML,
|
|
753
|
+
getThemeConfig,
|
|
754
|
+
tabsPlugin as tabsMarkdownPlugin
|
|
755
|
+
};
|