@jet-w/astro-blog 0.1.1 → 0.1.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/dist/chunk-MQXPSOYB.js +124 -0
- package/dist/config/index.d.ts +2 -92
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -0
- package/dist/integration.d.ts +25 -0
- package/dist/integration.js +8 -0
- package/dist/sidebar-DNdiCKBw.d.ts +92 -0
- package/dist/utils/sidebar.d.ts +98 -0
- package/dist/utils/sidebar.js +305 -0
- package/package.json +6 -3
- package/src/components/about/SocialLinks.astro +1 -1
- package/src/components/blog/Hero.astro +1 -1
- package/src/components/layout/Footer.astro +1 -2
- package/src/components/layout/Header.astro +4 -4
- package/src/components/layout/Sidebar.astro +3 -3
- package/src/components/ui/MobileMenu.vue +1 -1
- package/src/components/ui/SearchInterface.vue +1 -1
- package/src/layouts/BaseLayout.astro +3 -3
- package/src/layouts/SlidesLayout.astro +2 -2
- package/{templates/default/src → src}/pages/rss.xml.ts +1 -1
- package/templates/default/astro.config.mjs +3 -1
- package/templates/default/src/config/footer.ts +31 -0
- package/templates/default/src/config/index.ts +13 -110
- package/templates/default/src/config/sidebar.ts +33 -0
- package/templates/default/src/config/site.ts +56 -0
- package/templates/default/src/config/social.ts +15 -0
- package/src/utils/sidebar.ts +0 -492
- /package/{templates/default/src → src}/pages/[...slug].astro +0 -0
- /package/{templates/default/src → src}/pages/archives/[year]/[month]/page/[page].astro +0 -0
- /package/{templates/default/src → src}/pages/archives/[year]/[month].astro +0 -0
- /package/{templates/default/src → src}/pages/archives/index.astro +0 -0
- /package/{templates/default/src → src}/pages/categories/[category]/page/[page].astro +0 -0
- /package/{templates/default/src → src}/pages/categories/[category].astro +0 -0
- /package/{templates/default/src → src}/pages/categories/index.astro +0 -0
- /package/{templates/default/src → src}/pages/container-test.astro +0 -0
- /package/{templates/default/src → src}/pages/mermaid-direct.html +0 -0
- /package/{templates/default/src → src}/pages/posts/[...slug].astro +0 -0
- /package/{templates/default/src → src}/pages/posts/index.astro +0 -0
- /package/{templates/default/src → src}/pages/posts/page/[page].astro +0 -0
- /package/{templates/default/src → src}/pages/search-index.json.ts +0 -0
- /package/{templates/default/src → src}/pages/search.astro +0 -0
- /package/{templates/default/src → src}/pages/slides/[...slug].astro +0 -0
- /package/{templates/default/src → src}/pages/slides/index.astro +0 -0
- /package/{templates/default/src → src}/pages/tags/[tag]/page/[page].astro +0 -0
- /package/{templates/default/src → src}/pages/tags/[tag].astro +0 -0
- /package/{templates/default/src → src}/pages/tags/index.astro +0 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// src/utils/sidebar.ts
|
|
2
|
+
function buildTreeFromPosts(posts, scanPath = "", options = {}) {
|
|
3
|
+
const { maxDepth, exclude = [], include = [], sortBy = "name", sortOrder = "asc" } = options;
|
|
4
|
+
const filteredPosts = posts.filter((post) => {
|
|
5
|
+
const postPath = post.id.toLowerCase();
|
|
6
|
+
const targetPath = scanPath.toLowerCase();
|
|
7
|
+
if (targetPath && !postPath.startsWith(targetPath + "/") && postPath !== targetPath) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const pathParts = post.id.split("/");
|
|
11
|
+
for (const part of pathParts) {
|
|
12
|
+
if (exclude.some((pattern) => matchPattern(part, pattern))) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (include.length > 0) {
|
|
17
|
+
const matchesInclude = pathParts.some(
|
|
18
|
+
(part) => include.some((pattern) => matchPattern(part, pattern))
|
|
19
|
+
);
|
|
20
|
+
if (!matchesInclude) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
const folderTitles = {};
|
|
27
|
+
const folderIcons = {};
|
|
28
|
+
filteredPosts.forEach((post) => {
|
|
29
|
+
const pathParts = post.id.split("/");
|
|
30
|
+
const fileName = pathParts[pathParts.length - 1].toLowerCase();
|
|
31
|
+
if (fileName === "readme" || fileName === "readme.md") {
|
|
32
|
+
const folderPath = pathParts.slice(0, -1).join("/");
|
|
33
|
+
if (folderPath) {
|
|
34
|
+
if (post.data.title) {
|
|
35
|
+
folderTitles[folderPath] = post.data.title;
|
|
36
|
+
}
|
|
37
|
+
if (post.data.icon) {
|
|
38
|
+
folderIcons[folderPath] = post.data.icon;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const tree = [];
|
|
44
|
+
filteredPosts.forEach((post) => {
|
|
45
|
+
let relativePath = post.id;
|
|
46
|
+
if (scanPath) {
|
|
47
|
+
const scanPathLower = scanPath.toLowerCase();
|
|
48
|
+
const postIdLower = post.id.toLowerCase();
|
|
49
|
+
if (postIdLower.startsWith(scanPathLower + "/")) {
|
|
50
|
+
relativePath = post.id.slice(scanPath.length + 1);
|
|
51
|
+
} else if (postIdLower === scanPathLower) {
|
|
52
|
+
relativePath = post.id.split("/").pop() || post.id;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const pathParts = relativePath.split("/");
|
|
56
|
+
if (maxDepth !== void 0 && pathParts.length > maxDepth) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let currentLevel = tree;
|
|
60
|
+
let currentPath = scanPath;
|
|
61
|
+
pathParts.forEach((part, index) => {
|
|
62
|
+
const isLast = index === pathParts.length - 1;
|
|
63
|
+
const existing = currentLevel.find((n) => n.name.toLowerCase() === part.toLowerCase());
|
|
64
|
+
currentPath = currentPath ? `${currentPath}/${part}` : part;
|
|
65
|
+
const isReadme = isLast && (part.toLowerCase() === "readme" || part.toLowerCase() === "readme.md");
|
|
66
|
+
if (existing) {
|
|
67
|
+
if (isLast) {
|
|
68
|
+
existing.slug = post.id;
|
|
69
|
+
existing.title = post.data.title;
|
|
70
|
+
existing.icon = post.data.icon;
|
|
71
|
+
existing.isReadme = isReadme;
|
|
72
|
+
} else {
|
|
73
|
+
const folderPath = scanPath ? `${scanPath}/${pathParts.slice(0, index + 1).join("/")}` : pathParts.slice(0, index + 1).join("/");
|
|
74
|
+
if (folderTitles[folderPath]) {
|
|
75
|
+
existing.displayName = folderTitles[folderPath];
|
|
76
|
+
}
|
|
77
|
+
if (folderIcons[folderPath]) {
|
|
78
|
+
existing.icon = folderIcons[folderPath];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
currentLevel = existing.children;
|
|
82
|
+
} else {
|
|
83
|
+
const folderPath = scanPath ? `${scanPath}/${pathParts.slice(0, index + 1).join("/")}` : pathParts.slice(0, index + 1).join("/");
|
|
84
|
+
const newNode = {
|
|
85
|
+
name: part,
|
|
86
|
+
slug: isLast ? post.id : void 0,
|
|
87
|
+
title: isLast ? post.data.title : void 0,
|
|
88
|
+
displayName: isLast ? post.data.title : folderTitles[folderPath],
|
|
89
|
+
icon: isLast ? post.data.icon : folderIcons[folderPath],
|
|
90
|
+
children: [],
|
|
91
|
+
isFolder: !isLast,
|
|
92
|
+
isReadme
|
|
93
|
+
};
|
|
94
|
+
currentLevel.push(newNode);
|
|
95
|
+
currentLevel = newNode.children;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
return sortTree(tree, sortBy, sortOrder);
|
|
100
|
+
}
|
|
101
|
+
function sortTree(nodes, sortBy = "name", sortOrder = "asc") {
|
|
102
|
+
const filtered = nodes.filter((node) => !node.isReadme);
|
|
103
|
+
const sorted = filtered.sort((a, b) => {
|
|
104
|
+
if (a.isFolder && !b.isFolder) return -1;
|
|
105
|
+
if (!a.isFolder && b.isFolder) return 1;
|
|
106
|
+
let comparison = 0;
|
|
107
|
+
switch (sortBy) {
|
|
108
|
+
case "title":
|
|
109
|
+
comparison = (a.displayName || a.title || a.name).localeCompare(
|
|
110
|
+
b.displayName || b.title || b.name,
|
|
111
|
+
"zh-CN"
|
|
112
|
+
);
|
|
113
|
+
break;
|
|
114
|
+
case "name":
|
|
115
|
+
default:
|
|
116
|
+
comparison = a.name.localeCompare(b.name, "zh-CN", { numeric: true });
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
return sortOrder === "desc" ? -comparison : comparison;
|
|
120
|
+
});
|
|
121
|
+
return sorted.map((node) => ({
|
|
122
|
+
...node,
|
|
123
|
+
children: sortTree(node.children, sortBy, sortOrder)
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
function matchPattern(str, pattern) {
|
|
127
|
+
if (pattern === "*") return true;
|
|
128
|
+
if (pattern.includes("*")) {
|
|
129
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$", "i");
|
|
130
|
+
return regex.test(str);
|
|
131
|
+
}
|
|
132
|
+
return str.toLowerCase() === pattern.toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
function matchPathPattern(currentPath, pattern) {
|
|
135
|
+
const normalizedPath = currentPath.replace(/\/$/, "").toLowerCase();
|
|
136
|
+
const normalizedPattern = pattern.replace(/\/$/, "").toLowerCase();
|
|
137
|
+
if (normalizedPattern.endsWith("/**")) {
|
|
138
|
+
const basePath = normalizedPattern.slice(0, -3);
|
|
139
|
+
return normalizedPath === basePath || normalizedPath.startsWith(basePath + "/");
|
|
140
|
+
}
|
|
141
|
+
if (normalizedPattern.endsWith("/*")) {
|
|
142
|
+
const basePath = normalizedPattern.slice(0, -2);
|
|
143
|
+
if (normalizedPath === basePath) return true;
|
|
144
|
+
if (normalizedPath.startsWith(basePath + "/")) {
|
|
145
|
+
const remaining = normalizedPath.slice(basePath.length + 1);
|
|
146
|
+
return !remaining.includes("/");
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return normalizedPath === normalizedPattern;
|
|
151
|
+
}
|
|
152
|
+
function shouldShowGroup(group, currentPath) {
|
|
153
|
+
if (!group.showForPaths && !group.hideForPaths) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
if (group.hideForPaths && group.hideForPaths.length > 0) {
|
|
157
|
+
for (const pattern of group.hideForPaths) {
|
|
158
|
+
if (matchPathPattern(currentPath, pattern)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (group.showForPaths && group.showForPaths.length > 0) {
|
|
164
|
+
for (const pattern of group.showForPaths) {
|
|
165
|
+
if (matchPathPattern(currentPath, pattern)) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
function filterGroupsByPath(groups, currentPath) {
|
|
174
|
+
return groups.filter((group) => shouldShowGroup(group, currentPath));
|
|
175
|
+
}
|
|
176
|
+
function manualItemsToTree(items) {
|
|
177
|
+
return items.map((item) => ({
|
|
178
|
+
name: item.title,
|
|
179
|
+
slug: item.slug,
|
|
180
|
+
title: item.title,
|
|
181
|
+
displayName: item.title,
|
|
182
|
+
icon: item.icon,
|
|
183
|
+
badge: item.badge,
|
|
184
|
+
badgeType: item.badgeType,
|
|
185
|
+
link: item.link,
|
|
186
|
+
children: item.children ? manualItemsToTree(item.children) : [],
|
|
187
|
+
isFolder: !!(item.children && item.children.length > 0),
|
|
188
|
+
collapsed: item.collapsed
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
async function processSidebarConfig(config, posts) {
|
|
192
|
+
const processedGroups = [];
|
|
193
|
+
for (const group of config.groups) {
|
|
194
|
+
const processed = await processGroup(group, posts);
|
|
195
|
+
if (processed) {
|
|
196
|
+
processedGroups.push(processed);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return processedGroups;
|
|
200
|
+
}
|
|
201
|
+
async function processGroup(group, posts) {
|
|
202
|
+
switch (group.type) {
|
|
203
|
+
case "scan": {
|
|
204
|
+
const scanConfig = group;
|
|
205
|
+
const tree = buildTreeFromPosts(posts, scanConfig.scanPath, {
|
|
206
|
+
maxDepth: scanConfig.maxDepth,
|
|
207
|
+
exclude: scanConfig.exclude,
|
|
208
|
+
include: scanConfig.include,
|
|
209
|
+
sortBy: scanConfig.sortBy,
|
|
210
|
+
sortOrder: scanConfig.sortOrder
|
|
211
|
+
});
|
|
212
|
+
return {
|
|
213
|
+
type: "tree",
|
|
214
|
+
title: scanConfig.title,
|
|
215
|
+
icon: scanConfig.icon,
|
|
216
|
+
collapsed: scanConfig.collapsed,
|
|
217
|
+
tree
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
case "manual": {
|
|
221
|
+
const manualConfig = group;
|
|
222
|
+
const tree = manualItemsToTree(manualConfig.items);
|
|
223
|
+
return {
|
|
224
|
+
type: "tree",
|
|
225
|
+
title: manualConfig.title,
|
|
226
|
+
icon: manualConfig.icon,
|
|
227
|
+
collapsed: manualConfig.collapsed,
|
|
228
|
+
tree
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
case "mixed": {
|
|
232
|
+
const mixedConfig = group;
|
|
233
|
+
const combinedTree = [];
|
|
234
|
+
for (const section of mixedConfig.sections) {
|
|
235
|
+
const processed = await processGroup(section, posts);
|
|
236
|
+
if (processed && processed.tree) {
|
|
237
|
+
combinedTree.push({
|
|
238
|
+
name: section.title,
|
|
239
|
+
displayName: section.title,
|
|
240
|
+
icon: section.icon,
|
|
241
|
+
children: processed.tree,
|
|
242
|
+
isFolder: true,
|
|
243
|
+
collapsed: section.collapsed
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
type: "tree",
|
|
249
|
+
title: mixedConfig.title,
|
|
250
|
+
icon: mixedConfig.icon,
|
|
251
|
+
collapsed: mixedConfig.collapsed,
|
|
252
|
+
tree: combinedTree
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
case "divider": {
|
|
256
|
+
return {
|
|
257
|
+
type: "divider",
|
|
258
|
+
title: group.title || ""
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
default:
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function getRecentPosts(posts, count = 5) {
|
|
266
|
+
return posts.filter((p) => p.data.pubDate).sort((a, b) => (b.data.pubDate?.getTime() ?? 0) - (a.data.pubDate?.getTime() ?? 0)).slice(0, count);
|
|
267
|
+
}
|
|
268
|
+
function getPopularTags(posts, count = 8) {
|
|
269
|
+
const tagCounts = {};
|
|
270
|
+
posts.forEach((post) => {
|
|
271
|
+
(post.data.tags || []).forEach((tag) => {
|
|
272
|
+
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
return Object.entries(tagCounts).sort((a, b) => b[1] - a[1]).slice(0, count).map(([name, count2]) => ({
|
|
276
|
+
name,
|
|
277
|
+
count: count2,
|
|
278
|
+
slug: name.toLowerCase().replace(/\s+/g, "-")
|
|
279
|
+
}));
|
|
280
|
+
}
|
|
281
|
+
function getArchives(posts, count = 6) {
|
|
282
|
+
const archiveMap = {};
|
|
283
|
+
posts.forEach((post) => {
|
|
284
|
+
if (post.data.pubDate) {
|
|
285
|
+
const date = new Date(post.data.pubDate);
|
|
286
|
+
const key = `${date.getFullYear()}-${date.getMonth() + 1}`;
|
|
287
|
+
archiveMap[key] = (archiveMap[key] || 0) + 1;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
return Object.entries(archiveMap).sort((a, b) => b[0].localeCompare(a[0])).slice(0, count).map(([key, count2]) => {
|
|
291
|
+
const [year, month] = key.split("-").map(Number);
|
|
292
|
+
return { year, month, count: count2 };
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
export {
|
|
296
|
+
buildTreeFromPosts,
|
|
297
|
+
filterGroupsByPath,
|
|
298
|
+
getArchives,
|
|
299
|
+
getPopularTags,
|
|
300
|
+
getRecentPosts,
|
|
301
|
+
manualItemsToTree,
|
|
302
|
+
matchPathPattern,
|
|
303
|
+
processSidebarConfig,
|
|
304
|
+
shouldShowGroup
|
|
305
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jet-w/astro-blog",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A modern Astro blog theme with Vue and Tailwind CSS support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
"./styles/*": "./src/styles/*",
|
|
21
21
|
"./components/*": "./src/components/*",
|
|
22
22
|
"./layouts/*": "./src/layouts/*",
|
|
23
|
-
"./utils
|
|
23
|
+
"./utils/sidebar": {
|
|
24
|
+
"types": "./dist/utils/sidebar.d.ts",
|
|
25
|
+
"import": "./dist/utils/sidebar.js"
|
|
26
|
+
}
|
|
24
27
|
},
|
|
25
28
|
"files": [
|
|
26
29
|
"dist",
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
"src/styles",
|
|
29
32
|
"src/components",
|
|
30
33
|
"src/layouts",
|
|
31
|
-
"src/
|
|
34
|
+
"src/pages",
|
|
32
35
|
"templates"
|
|
33
36
|
],
|
|
34
37
|
"scripts": {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { siteConfig } from '
|
|
3
|
-
import ThemeToggle from '
|
|
4
|
-
import SearchBox from '
|
|
5
|
-
import MobileMenu from '
|
|
2
|
+
import { siteConfig } from '@jet-w/astro-blog/config';
|
|
3
|
+
import ThemeToggle from '../ui/ThemeToggle.vue';
|
|
4
|
+
import SearchBox from '../ui/SearchBox.vue';
|
|
5
|
+
import MobileMenu from '../ui/MobileMenu.vue';
|
|
6
6
|
|
|
7
7
|
const currentPath = Astro.url.pathname;
|
|
8
8
|
---
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getCollection } from 'astro:content';
|
|
3
|
-
import Icon from '
|
|
4
|
-
import { sidebarConfig } from '
|
|
3
|
+
import Icon from '../ui/Icon.astro';
|
|
4
|
+
import { sidebarConfig } from '@jet-w/astro-blog/config';
|
|
5
5
|
import {
|
|
6
6
|
processSidebarConfig,
|
|
7
7
|
getRecentPosts,
|
|
8
8
|
getPopularTags,
|
|
9
9
|
getArchives,
|
|
10
10
|
filterGroupsByPath,
|
|
11
|
-
} from '
|
|
11
|
+
} from '@jet-w/astro-blog/utils/sidebar';
|
|
12
12
|
|
|
13
13
|
interface Props {
|
|
14
14
|
currentPath?: string;
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
|
|
100
100
|
<script setup lang="ts">
|
|
101
101
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
102
|
-
import type { NavigationItem } from '
|
|
102
|
+
import type { NavigationItem } from '@jet-w/astro-blog/types'
|
|
103
103
|
import SearchBox from './SearchBox.vue'
|
|
104
104
|
import ThemeToggle from './ThemeToggle.vue'
|
|
105
105
|
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
|
|
197
197
|
<script setup lang="ts">
|
|
198
198
|
import { ref, computed, onMounted } from 'vue'
|
|
199
|
-
import type { SearchResult } from '
|
|
199
|
+
import type { SearchResult } from '@jet-w/astro-blog/types'
|
|
200
200
|
|
|
201
201
|
const searchQuery = ref('')
|
|
202
202
|
const selectedTag = ref('')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { SEOProps } from '
|
|
3
|
-
import { siteConfig, defaultSEO } from '
|
|
4
|
-
import '
|
|
2
|
+
import type { SEOProps } from '@jet-w/astro-blog/types';
|
|
3
|
+
import { siteConfig, defaultSEO } from '@jet-w/astro-blog/config';
|
|
4
|
+
import '@jet-w/astro-blog/styles/global.css';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import rss from '@astrojs/rss';
|
|
2
2
|
import { getCollection } from 'astro:content';
|
|
3
|
-
import { siteConfig } from '
|
|
3
|
+
import { siteConfig } from '@jet-w/astro-blog/config';
|
|
4
4
|
|
|
5
5
|
export async function GET(context: { site: URL }) {
|
|
6
6
|
const posts = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -7,7 +7,8 @@ import remarkMath from 'remark-math';
|
|
|
7
7
|
import rehypeKatex from 'rehype-katex';
|
|
8
8
|
import rehypeRaw from 'rehype-raw';
|
|
9
9
|
|
|
10
|
-
// Import plugins from @jet-w/astro-blog
|
|
10
|
+
// Import plugins and integration from @jet-w/astro-blog
|
|
11
|
+
import { astroBlog } from '@jet-w/astro-blog';
|
|
11
12
|
import { remarkContainers } from '@jet-w/astro-blog/plugins/remark-containers.mjs';
|
|
12
13
|
import { remarkMermaid } from '@jet-w/astro-blog/plugins/remark-mermaid.mjs';
|
|
13
14
|
import { rehypeCleanContainers } from '@jet-w/astro-blog/plugins/rehype-clean-containers.mjs';
|
|
@@ -17,6 +18,7 @@ import { rehypeRelativeLinks } from '@jet-w/astro-blog/plugins/rehype-relative-l
|
|
|
17
18
|
// https://astro.build/config
|
|
18
19
|
export default defineConfig({
|
|
19
20
|
integrations: [
|
|
21
|
+
astroBlog(),
|
|
20
22
|
vue(),
|
|
21
23
|
mdx(),
|
|
22
24
|
tailwind({
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footer Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configure footer links, copyright, and display options
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { FooterConfig } from '@jet-w/astro-blog';
|
|
8
|
+
import { socialLinks } from './social';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Footer configuration
|
|
12
|
+
*/
|
|
13
|
+
export const footerConfig: FooterConfig = {
|
|
14
|
+
quickLinksTitle: '快速链接',
|
|
15
|
+
quickLinks: [
|
|
16
|
+
{ name: '首页', href: '/' },
|
|
17
|
+
{ name: '文章', href: '/posts' },
|
|
18
|
+
{ name: '标签', href: '/tags' },
|
|
19
|
+
{ name: '归档', href: '/archives' },
|
|
20
|
+
{ name: '关于', href: '/about' }
|
|
21
|
+
],
|
|
22
|
+
contactTitle: '联系方式',
|
|
23
|
+
socialLinks: socialLinks,
|
|
24
|
+
showRss: true,
|
|
25
|
+
rssUrl: '/rss.xml',
|
|
26
|
+
copyright: '© {year} {author}. All rights reserved.',
|
|
27
|
+
poweredBy: {
|
|
28
|
+
text: 'Astro',
|
|
29
|
+
url: 'https://astro.build'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -1,114 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Blog
|
|
2
|
+
* Blog Configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Site configuration
|
|
12
|
-
*/
|
|
13
|
-
export const siteConfig: SiteConfig = {
|
|
14
|
-
title: 'My Astro Blog',
|
|
15
|
-
description: '基于 Astro + Vue + Tailwind 构建的个人技术博客',
|
|
16
|
-
author: 'Author',
|
|
17
|
-
email: 'email@example.com',
|
|
18
|
-
avatar: '/images/avatar.svg',
|
|
19
|
-
social: {
|
|
20
|
-
github: 'https://github.com/username',
|
|
21
|
-
twitter: '',
|
|
22
|
-
linkedin: '',
|
|
23
|
-
email: 'mailto:email@example.com'
|
|
24
|
-
},
|
|
25
|
-
menu: [
|
|
26
|
-
{
|
|
27
|
-
name: '首页',
|
|
28
|
-
href: '/',
|
|
29
|
-
icon: 'home'
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: '博客教学',
|
|
33
|
-
href: '/posts/blog_docs',
|
|
34
|
-
icon: 'posts'
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: '演示',
|
|
38
|
-
href: '/slides',
|
|
39
|
-
icon: 'slides'
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: '关于',
|
|
43
|
-
href: '/about',
|
|
44
|
-
icon: 'about'
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Default SEO settings
|
|
51
|
-
*/
|
|
52
|
-
export const defaultSEO = {
|
|
53
|
-
title: siteConfig.title,
|
|
54
|
-
description: siteConfig.description,
|
|
55
|
-
image: '/images/og-image.jpg',
|
|
56
|
-
type: 'website' as const
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Sidebar configuration
|
|
61
|
-
*/
|
|
62
|
-
export const sidebarConfig: SidebarConfig = {
|
|
63
|
-
enabled: true,
|
|
64
|
-
showSearch: true,
|
|
65
|
-
showRecentPosts: true,
|
|
66
|
-
recentPostsCount: 5,
|
|
67
|
-
showPopularTags: true,
|
|
68
|
-
popularTagsCount: 8,
|
|
69
|
-
showArchives: true,
|
|
70
|
-
archivesCount: 6,
|
|
71
|
-
showFriendLinks: false,
|
|
72
|
-
friendLinks: [],
|
|
73
|
-
groups: [
|
|
74
|
-
{
|
|
75
|
-
type: 'scan',
|
|
76
|
-
title: '博客指南',
|
|
77
|
-
icon: 'ri:book-open-line',
|
|
78
|
-
scanPath: 'blog_docs',
|
|
79
|
-
collapsed: true,
|
|
80
|
-
showForPaths: ['/posts/blog_docs/**']
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Social links
|
|
4
|
+
* This file re-exports all configuration modules for easy access.
|
|
5
|
+
* Each configuration is in its own file for better organization:
|
|
6
|
+
*
|
|
7
|
+
* - site.ts : Site title, description, author, menu
|
|
8
|
+
* - sidebar.ts : Sidebar display options and groups
|
|
9
|
+
* - social.ts : Social media links
|
|
10
|
+
* - footer.ts : Footer links and copyright
|
|
87
11
|
*/
|
|
88
|
-
export const socialLinks: SocialLink[] = [
|
|
89
|
-
{ type: 'github', url: 'https://github.com/username', label: 'GitHub' },
|
|
90
|
-
{ type: 'email', url: 'mailto:email@example.com', label: 'Email' }
|
|
91
|
-
];
|
|
92
12
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
export
|
|
97
|
-
|
|
98
|
-
quickLinks: [
|
|
99
|
-
{ name: '首页', href: '/' },
|
|
100
|
-
{ name: '文章', href: '/posts' },
|
|
101
|
-
{ name: '标签', href: '/tags' },
|
|
102
|
-
{ name: '归档', href: '/archives' },
|
|
103
|
-
{ name: '关于', href: '/about' }
|
|
104
|
-
],
|
|
105
|
-
contactTitle: '联系方式',
|
|
106
|
-
socialLinks: socialLinks,
|
|
107
|
-
showRss: true,
|
|
108
|
-
rssUrl: '/rss.xml',
|
|
109
|
-
copyright: '© {year} {author}. All rights reserved.',
|
|
110
|
-
poweredBy: {
|
|
111
|
-
text: 'Astro',
|
|
112
|
-
url: 'https://astro.build'
|
|
113
|
-
}
|
|
114
|
-
};
|
|
13
|
+
// Re-export all configurations
|
|
14
|
+
export { siteConfig, defaultSEO } from './site';
|
|
15
|
+
export { sidebarConfig } from './sidebar';
|
|
16
|
+
export { socialLinks } from './social';
|
|
17
|
+
export { footerConfig } from './footer';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configure sidebar display options, groups, and widgets
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { SidebarConfig } from '@jet-w/astro-blog';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sidebar configuration
|
|
11
|
+
*/
|
|
12
|
+
export const sidebarConfig: SidebarConfig = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
showSearch: true,
|
|
15
|
+
showRecentPosts: true,
|
|
16
|
+
recentPostsCount: 5,
|
|
17
|
+
showPopularTags: true,
|
|
18
|
+
popularTagsCount: 8,
|
|
19
|
+
showArchives: true,
|
|
20
|
+
archivesCount: 6,
|
|
21
|
+
showFriendLinks: false,
|
|
22
|
+
friendLinks: [],
|
|
23
|
+
groups: [
|
|
24
|
+
{
|
|
25
|
+
type: 'scan',
|
|
26
|
+
title: '博客指南',
|
|
27
|
+
icon: 'ri:book-open-line',
|
|
28
|
+
scanPath: 'blog_docs',
|
|
29
|
+
collapsed: true,
|
|
30
|
+
showForPaths: ['/posts/blog_docs/**']
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
};
|