@sugarat/theme 0.1.27 → 0.1.29
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 +6 -0
- package/node.js +179 -4
- package/package.json +4 -3
- package/src/composables/config/index.ts +5 -0
- package/src/node.ts +21 -4
package/node.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DefaultTheme, UserConfig } from 'vitepress';
|
|
2
2
|
import { ElButton } from 'element-plus';
|
|
3
|
+
export { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
|
|
3
4
|
|
|
4
5
|
declare namespace BlogPopover {
|
|
5
6
|
interface Title {
|
|
@@ -180,6 +181,11 @@ declare namespace Theme {
|
|
|
180
181
|
popover?: Popover;
|
|
181
182
|
friend?: FriendLink[];
|
|
182
183
|
authorList?: Omit<FriendLink, 'avatar'>[];
|
|
184
|
+
/**
|
|
185
|
+
* 启用 [vitepress-plugin-tabs](https://www.npmjs.com/package/vitepress-plugin-tabs)
|
|
186
|
+
* @default false
|
|
187
|
+
*/
|
|
188
|
+
tabs: boolean;
|
|
183
189
|
}
|
|
184
190
|
interface Config extends DefaultTheme.Config {
|
|
185
191
|
blog?: BlogConfig;
|
package/node.js
CHANGED
|
@@ -31,7 +31,8 @@ __export(node_exports, {
|
|
|
31
31
|
getDefaultTitle: () => getDefaultTitle,
|
|
32
32
|
getFileBirthTime: () => getFileBirthTime,
|
|
33
33
|
getGitTimestamp: () => getGitTimestamp,
|
|
34
|
-
getThemeConfig: () => getThemeConfig
|
|
34
|
+
getThemeConfig: () => getThemeConfig,
|
|
35
|
+
tabsMarkdownPlugin: () => tabsPlugin
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(node_exports);
|
|
37
38
|
var import_fast_glob = __toESM(require("fast-glob"));
|
|
@@ -40,6 +41,170 @@ var import_fs = __toESM(require("fs"));
|
|
|
40
41
|
var import_child_process = require("child_process");
|
|
41
42
|
var import_path = __toESM(require("path"));
|
|
42
43
|
|
|
44
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.0-alpha.75_vue@3.2.45/node_modules/vitepress-plugin-tabs/dist/index.js
|
|
45
|
+
var tabsMarker = "=tabs";
|
|
46
|
+
var tabsMarkerLen = tabsMarker.length;
|
|
47
|
+
var ruleBlockTabs = (state, startLine, endLine, silent) => {
|
|
48
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
52
|
+
let max = state.eMarks[startLine];
|
|
53
|
+
if (pos + 3 > max) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const marker = state.src.charCodeAt(pos);
|
|
57
|
+
if (marker !== 58) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const mem = pos;
|
|
61
|
+
pos = state.skipChars(pos, marker);
|
|
62
|
+
let len = pos - mem;
|
|
63
|
+
if (len < 3) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (state.src.slice(pos, pos + tabsMarkerLen) !== tabsMarker) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
pos += tabsMarkerLen;
|
|
70
|
+
if (silent) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const markup = state.src.slice(mem, pos);
|
|
74
|
+
const params = state.src.slice(pos, max);
|
|
75
|
+
let nextLine = startLine;
|
|
76
|
+
let haveEndMarker = false;
|
|
77
|
+
for (; ; ) {
|
|
78
|
+
nextLine++;
|
|
79
|
+
if (nextLine >= endLine) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
pos = state.bMarks[nextLine] + state.tShift[nextLine];
|
|
83
|
+
const mem2 = pos;
|
|
84
|
+
max = state.eMarks[nextLine];
|
|
85
|
+
if (pos < max && state.sCount[nextLine] < state.blkIndent) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
if (state.src.charCodeAt(pos) !== marker) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (state.sCount[nextLine] - state.blkIndent >= 4) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
pos = state.skipChars(pos, marker);
|
|
95
|
+
if (pos - mem2 < len) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
pos = state.skipSpaces(pos);
|
|
99
|
+
if (pos < max) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
haveEndMarker = true;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
len = state.sCount[startLine];
|
|
106
|
+
state.line = nextLine + (haveEndMarker ? 1 : 0);
|
|
107
|
+
const token = state.push("tabs", "div", 0);
|
|
108
|
+
token.info = params;
|
|
109
|
+
token.content = state.getLines(startLine + 1, nextLine, len, true);
|
|
110
|
+
token.markup = markup;
|
|
111
|
+
token.map = [startLine, state.line];
|
|
112
|
+
return true;
|
|
113
|
+
};
|
|
114
|
+
var tabBreakRE = /^\s*::(.+)$/;
|
|
115
|
+
var forbiddenCharsInSlotNames = /[ '"]/;
|
|
116
|
+
var parseTabBreakLine = (line) => {
|
|
117
|
+
const m = line.match(tabBreakRE);
|
|
118
|
+
if (!m)
|
|
119
|
+
return null;
|
|
120
|
+
const trimmed = m[1].trim();
|
|
121
|
+
if (forbiddenCharsInSlotNames.test(trimmed)) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`contains forbidden chars in slot names (space and quotes) (${JSON.stringify(
|
|
124
|
+
line
|
|
125
|
+
)})`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return trimmed;
|
|
129
|
+
};
|
|
130
|
+
var lastLineBreakRE = /\n$/;
|
|
131
|
+
var parseTabsContent = (content) => {
|
|
132
|
+
const lines = content.replace(lastLineBreakRE, "").split("\n");
|
|
133
|
+
const tabInfos = [];
|
|
134
|
+
const tabLabels = /* @__PURE__ */ new Set();
|
|
135
|
+
let currentTab = null;
|
|
136
|
+
const createTabInfo = (label) => {
|
|
137
|
+
if (tabLabels.has(label)) {
|
|
138
|
+
throw new Error(`a tab labelled ${JSON.stringify(label)} already exists`);
|
|
139
|
+
}
|
|
140
|
+
const newTab = { label, content: [] };
|
|
141
|
+
tabInfos.push(newTab);
|
|
142
|
+
tabLabels.add(label);
|
|
143
|
+
return newTab;
|
|
144
|
+
};
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
const tabLabel = parseTabBreakLine(line);
|
|
147
|
+
if (currentTab === null) {
|
|
148
|
+
if (tabLabel === null) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`tabs should start with \`::\${tabLabel}\` (e.g. "::foo"). (received: ${JSON.stringify(
|
|
151
|
+
line
|
|
152
|
+
)})`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
currentTab = createTabInfo(tabLabel);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (tabLabel === null) {
|
|
159
|
+
currentTab.content.push(line);
|
|
160
|
+
} else {
|
|
161
|
+
currentTab = createTabInfo(tabLabel);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (tabInfos.length < 0) {
|
|
165
|
+
throw new Error("tabs should include at least one tab");
|
|
166
|
+
}
|
|
167
|
+
return tabInfos.map((info) => ({
|
|
168
|
+
label: info.label,
|
|
169
|
+
content: info.content.join("\n").replace(lastLineBreakRE, "")
|
|
170
|
+
}));
|
|
171
|
+
};
|
|
172
|
+
var parseParams = (input) => {
|
|
173
|
+
if (!input.startsWith("=")) {
|
|
174
|
+
return {
|
|
175
|
+
shareStateKey: void 0
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const splitted = input.split("=");
|
|
179
|
+
return {
|
|
180
|
+
shareStateKey: splitted[1]
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
var tabsPlugin = (md) => {
|
|
184
|
+
md.block.ruler.before("fence", "=tabs", ruleBlockTabs, {
|
|
185
|
+
alt: ["paragraph", "reference", "blockquote", "list"]
|
|
186
|
+
});
|
|
187
|
+
md.renderer.rules.tabs = (tokens, index, _options, env) => {
|
|
188
|
+
const token = tokens[index];
|
|
189
|
+
const tabs = parseTabsContent(token.content);
|
|
190
|
+
const renderedTabs = tabs.map((tab) => ({
|
|
191
|
+
label: tab.label,
|
|
192
|
+
content: md.render(tab.content, env)
|
|
193
|
+
}));
|
|
194
|
+
const params = parseParams(token.info);
|
|
195
|
+
const tabLabelsProp = `:tabLabels="${md.utils.escapeHtml(
|
|
196
|
+
JSON.stringify(tabs.map((tab) => tab.label))
|
|
197
|
+
)}"`;
|
|
198
|
+
const shareStateKeyProp = params.shareStateKey ? `sharedStateKey="${md.utils.escapeHtml(params.shareStateKey)}"` : "";
|
|
199
|
+
const slots = renderedTabs.map(
|
|
200
|
+
(tab) => `<template #${tab.label}>${tab.content}</template>`
|
|
201
|
+
);
|
|
202
|
+
return `<PluginTabs ${tabLabelsProp} ${shareStateKeyProp}>${slots.join(
|
|
203
|
+
""
|
|
204
|
+
)}</PluginTabs>`;
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
43
208
|
// src/utils/index.ts
|
|
44
209
|
function formatDate(d, fmt = "yyyy-MM-dd hh:mm:ss") {
|
|
45
210
|
if (!(d instanceof Date)) {
|
|
@@ -106,7 +271,9 @@ function getThemeConfig(cfg) {
|
|
|
106
271
|
new Date(`${new Date(meta.date).toUTCString()}+8`)
|
|
107
272
|
);
|
|
108
273
|
}
|
|
109
|
-
meta.
|
|
274
|
+
meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
|
|
275
|
+
meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
|
|
276
|
+
meta.tag = [meta.tag || []].flat().concat([
|
|
110
277
|
.../* @__PURE__ */ new Set([...meta.categories || [], ...meta.tags || []])
|
|
111
278
|
]);
|
|
112
279
|
const wordCount = 100;
|
|
@@ -172,6 +339,13 @@ function getThemeConfig(cfg) {
|
|
|
172
339
|
]
|
|
173
340
|
};
|
|
174
341
|
}
|
|
342
|
+
if (cfg?.tabs) {
|
|
343
|
+
extraConfig.markdown = {
|
|
344
|
+
config(md) {
|
|
345
|
+
tabsPlugin(md);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
175
349
|
return {
|
|
176
350
|
themeConfig: {
|
|
177
351
|
blog: {
|
|
@@ -193,7 +367,7 @@ function getThemeConfig(cfg) {
|
|
|
193
367
|
function getDefaultTitle(content) {
|
|
194
368
|
const title = clearMatterContent(content).split("\n")?.find((str) => {
|
|
195
369
|
return str.startsWith("# ");
|
|
196
|
-
})?.slice(2).replace(
|
|
370
|
+
})?.slice(2).replace(/^\s+|\s+$/g, "") || "";
|
|
197
371
|
return title;
|
|
198
372
|
}
|
|
199
373
|
function clearMatterContent(content) {
|
|
@@ -264,5 +438,6 @@ function defineConfig(config) {
|
|
|
264
438
|
getDefaultTitle,
|
|
265
439
|
getFileBirthTime,
|
|
266
440
|
getGitTimestamp,
|
|
267
|
-
getThemeConfig
|
|
441
|
+
getThemeConfig,
|
|
442
|
+
tabsMarkdownPlugin
|
|
268
443
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -46,8 +46,9 @@
|
|
|
46
46
|
"sass": "^1.56.1",
|
|
47
47
|
"tsup": " ^6.5.0",
|
|
48
48
|
"typescript": "^4.8.2",
|
|
49
|
-
"vitepress": "1.0.0-alpha.
|
|
50
|
-
"vue": "^3.2.45"
|
|
49
|
+
"vitepress": "1.0.0-alpha.75",
|
|
50
|
+
"vue": "^3.2.45",
|
|
51
|
+
"vitepress-plugin-tabs": "^0.2.0"
|
|
51
52
|
},
|
|
52
53
|
"scripts": {
|
|
53
54
|
"dev": "npm run build:node && npm run dev:docs",
|
|
@@ -196,6 +196,11 @@ export namespace Theme {
|
|
|
196
196
|
popover?: Popover
|
|
197
197
|
friend?: FriendLink[]
|
|
198
198
|
authorList?: Omit<FriendLink, 'avatar'>[]
|
|
199
|
+
/**
|
|
200
|
+
* 启用 [vitepress-plugin-tabs](https://www.npmjs.com/package/vitepress-plugin-tabs)
|
|
201
|
+
* @default false
|
|
202
|
+
*/
|
|
203
|
+
tabs: boolean
|
|
199
204
|
}
|
|
200
205
|
|
|
201
206
|
export interface Config extends DefaultTheme.Config {
|
package/src/node.ts
CHANGED
|
@@ -5,6 +5,7 @@ import fs from 'fs'
|
|
|
5
5
|
import { execSync, spawn, spawnSync } from 'child_process'
|
|
6
6
|
import path from 'path'
|
|
7
7
|
import type { SiteConfig, UserConfig } from 'vitepress'
|
|
8
|
+
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
|
|
8
9
|
import { formatDate } from './utils/index'
|
|
9
10
|
import type { Theme } from './composables/config/index'
|
|
10
11
|
|
|
@@ -63,9 +64,16 @@ export function getThemeConfig(cfg?: Partial<Theme.BlogConfig>) {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// 处理tags和categories,兼容历史文章
|
|
66
|
-
meta.
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
meta.categories =
|
|
68
|
+
typeof meta.categories === 'string'
|
|
69
|
+
? [meta.categories]
|
|
70
|
+
: meta.categories
|
|
71
|
+
meta.tags = typeof meta.tags === 'string' ? [meta.tags] : meta.tags
|
|
72
|
+
meta.tag = [meta.tag || []]
|
|
73
|
+
.flat()
|
|
74
|
+
.concat([
|
|
75
|
+
...new Set([...(meta.categories || []), ...(meta.tags || [])])
|
|
76
|
+
])
|
|
69
77
|
|
|
70
78
|
// 获取摘要信息
|
|
71
79
|
const wordCount = 100
|
|
@@ -154,6 +162,13 @@ export function getThemeConfig(cfg?: Partial<Theme.BlogConfig>) {
|
|
|
154
162
|
]
|
|
155
163
|
}
|
|
156
164
|
}
|
|
165
|
+
if (cfg?.tabs) {
|
|
166
|
+
extraConfig.markdown = {
|
|
167
|
+
config(md: any) {
|
|
168
|
+
tabsMarkdownPlugin(md)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
157
172
|
return {
|
|
158
173
|
themeConfig: {
|
|
159
174
|
blog: {
|
|
@@ -183,7 +198,7 @@ export function getDefaultTitle(content: string) {
|
|
|
183
198
|
return str.startsWith('# ')
|
|
184
199
|
})
|
|
185
200
|
?.slice(2)
|
|
186
|
-
.replace(
|
|
201
|
+
.replace(/^\s+|\s+$/g, '') || ''
|
|
187
202
|
return title
|
|
188
203
|
}
|
|
189
204
|
|
|
@@ -288,3 +303,5 @@ export function defineConfig(config: UserConfig<Theme.Config>) {
|
|
|
288
303
|
}
|
|
289
304
|
return config
|
|
290
305
|
}
|
|
306
|
+
|
|
307
|
+
export { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'
|