@xingwangzhe/stalux 1.6.2 → 1.7.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/README.md +28 -0
- package/package.json +5 -6
- package/scripts/cli.mjs +307 -76
- package/src/components/stalux/footer/FooterBadges.astro +8 -2
- package/src/i18n/en.json +3 -1
- package/src/i18n/zh-CN.json +3 -1
- package/template/astro.config.mjs +0 -75
- package/template/package.json +0 -27
- package/template/public/robots.txt +0 -3
- package/template/src/content.config.ts +0 -11
- package/template/stalux/about/index.md +0 -14
- package/template/stalux/config/ai-discovery.yml +0 -2
- package/template/stalux/config/author.yml +0 -4
- package/template/stalux/config/comment.yml +0 -2
- package/template/stalux/config/footer.yml +0 -13
- package/template/stalux/config/head.yml +0 -7
- package/template/stalux/config/links.yml +0 -4
- package/template/stalux/config/media-links.yml +0 -8
- package/template/stalux/config/navs.yml +0 -23
- package/template/stalux/config/promote.yml +0 -2
- package/template/stalux/config/site.yml +0 -7
- package/template/stalux/config/typetexts.yml +0 -5
- package/template/stalux/posts/hello-stalux.md +0 -47
- package/template/stalux/words/_template.md +0 -13
- package/template/stalux/words/einstein-imagination.md +0 -8
- package/template/tsconfig.json +0 -9
package/README.md
CHANGED
|
@@ -141,6 +141,7 @@ stalux/
|
|
|
141
141
|
## ✨ Features
|
|
142
142
|
|
|
143
143
|
- 🌙 **Dark mode** as default, with elegant glassmorphism design
|
|
144
|
+
- 🔤 **Per-route font subsetting** — each page loads only its needed characters (25 MB full font → ~1 KB per route)
|
|
144
145
|
- 🔍 **Full-text search** via Pagefind (auto-indexed on build)
|
|
145
146
|
- 📡 **RSS & Atom feeds**
|
|
146
147
|
- 🖼️ **PhotoSwipe** image lightbox
|
|
@@ -155,6 +156,33 @@ stalux/
|
|
|
155
156
|
|
|
156
157
|
---
|
|
157
158
|
|
|
159
|
+
## 🔤 Font Optimization
|
|
160
|
+
|
|
161
|
+
Stalux ships with a 25 MB Chinese font (LXGW WenKai), but your visitors never download the full file. Instead, the build generates minimal font subsets per route:
|
|
162
|
+
|
|
163
|
+
- **Common subset** (~350 KB) — UI text, navigation, i18n, shared characters from all posts
|
|
164
|
+
- **Per-route subset** (~0.5–3 KB each) — unique characters for each individual page
|
|
165
|
+
|
|
166
|
+
Each HTML page loads only `common.css` + `subset-{route}.css`, ensuring every page gets exactly the characters it needs — nothing more.
|
|
167
|
+
|
|
168
|
+
This covers **all route types**:
|
|
169
|
+
|
|
170
|
+
| Route | Subset source |
|
|
171
|
+
| ------------------------------------ | --------------------------------------------------------- |
|
|
172
|
+
| `/` | Config YAML (site title, author, navs, typetexts, footer) |
|
|
173
|
+
| `/about` | About markdown |
|
|
174
|
+
| `/words` | All words content |
|
|
175
|
+
| `/posts/{slug}` | Single post content |
|
|
176
|
+
| `/archives` | All posts content |
|
|
177
|
+
| `/tags` / `/tags/{name}` | Tag names + matching posts |
|
|
178
|
+
| `/categories` / `/categories/{name}` | Category names + matching posts |
|
|
179
|
+
| `/links` | Links config YAML |
|
|
180
|
+
| `/404` | Covered by common subset |
|
|
181
|
+
|
|
182
|
+
The subsetting engine (`subset-font`, Harfbuzz WASM) runs at build time (`astro:build:start`) and on-demand in dev mode.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
158
186
|
## 🛠️ Development
|
|
159
187
|
|
|
160
188
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xingwangzhe/stalux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "A powerful, modern Astro blog theme — use as template or install as plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"src/scripts/**/*.ts",
|
|
40
40
|
"src/assets/**/*",
|
|
41
41
|
"scripts/cli.mjs",
|
|
42
|
-
"template/**/*",
|
|
43
42
|
"!src/content.config.ts"
|
|
44
43
|
],
|
|
45
44
|
"type": "module",
|
|
@@ -95,14 +94,14 @@
|
|
|
95
94
|
"temml": "^0.13.3"
|
|
96
95
|
},
|
|
97
96
|
"devDependencies": {
|
|
98
|
-
"@types/node": "^26.1.
|
|
97
|
+
"@types/node": "^26.1.2",
|
|
99
98
|
"knip": "^6.29.0",
|
|
100
99
|
"license-checker-rseidelsohn": "5.0.1",
|
|
101
|
-
"oxfmt": "^0.
|
|
102
|
-
"oxlint": "^1.
|
|
100
|
+
"oxfmt": "^0.61.0",
|
|
101
|
+
"oxlint": "^1.76.0",
|
|
103
102
|
"typescript": "^7.0.2"
|
|
104
103
|
},
|
|
105
104
|
"peerDependencies": {
|
|
106
|
-
"astro": "^7.
|
|
105
|
+
"astro": "^7.1.5"
|
|
107
106
|
}
|
|
108
107
|
}
|
package/scripts/cli.mjs
CHANGED
|
@@ -4,102 +4,333 @@
|
|
|
4
4
|
* Stalux CLI — 主题初始化工具
|
|
5
5
|
*
|
|
6
6
|
* 用法:
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* bunx stalux init # 在当前目录初始化内容模板
|
|
8
|
+
* bunx stalux init my-blog # 在子目录初始化项目
|
|
9
|
+
*
|
|
10
|
+
* 说明:
|
|
11
|
+
* - 只在 stalux/ 目录下生成内容配置文件和示例文章
|
|
12
|
+
* - 不会覆盖已有的 package.json、astro.config.mjs、src/content.config.ts
|
|
13
|
+
* - 静默运行,无交互式问答
|
|
14
|
+
* - 静默运行,无交互式问答
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
|
-
import { existsSync, mkdirSync,
|
|
13
|
-
import { join, resolve
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { join, resolve as pathResolve } from "node:path";
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// 默认内容模板数据
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
function getConfigYamls() {
|
|
25
|
+
const year = new Date().getFullYear();
|
|
26
|
+
const now = new Date().toISOString();
|
|
27
|
+
return {
|
|
28
|
+
"site.yml": `id: site
|
|
29
|
+
lang: en
|
|
30
|
+
title: "My Blog"
|
|
31
|
+
description: "A blog built with Stalux theme"
|
|
32
|
+
url: "https://example.com"
|
|
33
|
+
timezone: "Asia/Shanghai"
|
|
34
|
+
`,
|
|
35
|
+
"author.yml": `id: author
|
|
36
|
+
name: "Your Name"
|
|
37
|
+
avatar: "/avatar.png"
|
|
38
|
+
bio: "Blogger & Developer"
|
|
39
|
+
`,
|
|
40
|
+
"navs.yml": `id: navs
|
|
41
|
+
items:
|
|
42
|
+
- title: "Home"
|
|
43
|
+
link: "/"
|
|
44
|
+
icon: "house"
|
|
45
|
+
- title: "Archives"
|
|
46
|
+
link: "/archives"
|
|
47
|
+
icon: "archive"
|
|
48
|
+
- title: "Tags"
|
|
49
|
+
link: "/tags"
|
|
50
|
+
icon: "tag"
|
|
51
|
+
- title: "Categories"
|
|
52
|
+
link: "/categories"
|
|
53
|
+
icon: "folder"
|
|
54
|
+
- title: "Words"
|
|
55
|
+
link: "/words"
|
|
56
|
+
icon: "quote"
|
|
57
|
+
- title: "Links"
|
|
58
|
+
link: "/links"
|
|
59
|
+
icon: "link"
|
|
60
|
+
`,
|
|
61
|
+
"head.yml": `id: head
|
|
62
|
+
# googleAnalyticsId: "G-XXXXXXXXXX"
|
|
63
|
+
# clarityId: "xxxxxxxxxx"
|
|
64
|
+
# umamiWebsiteId: ""
|
|
65
|
+
# umamiSrc: ""
|
|
66
|
+
# anyhead: ""
|
|
67
|
+
`,
|
|
68
|
+
"footer.yml": `id: footer
|
|
69
|
+
buildtime: "${now}"
|
|
70
|
+
copyright:
|
|
71
|
+
enabled: true
|
|
72
|
+
startYear: ${year}
|
|
73
|
+
customText: ""
|
|
74
|
+
theme:
|
|
75
|
+
showPoweredBy: true
|
|
76
|
+
showThemeInfo: true
|
|
77
|
+
beian:
|
|
78
|
+
icp:
|
|
79
|
+
enabled: false
|
|
80
|
+
number: ""
|
|
81
|
+
security:
|
|
82
|
+
enabled: false
|
|
83
|
+
text: ""
|
|
84
|
+
number: ""
|
|
85
|
+
badges:
|
|
86
|
+
- label: "Powered by"
|
|
87
|
+
message: "Astro"
|
|
88
|
+
color: "orange"
|
|
89
|
+
style: "flat-square"
|
|
90
|
+
href: "https://astro.build/"
|
|
91
|
+
custom: |
|
|
92
|
+
<div id="custom-footer-hook"></div>
|
|
93
|
+
`,
|
|
94
|
+
"media-links.yml": `id: medialinks
|
|
95
|
+
items:
|
|
96
|
+
- icon: "github"
|
|
97
|
+
link: "https://github.com/yourname"
|
|
98
|
+
`,
|
|
99
|
+
"links.yml": `id: links
|
|
100
|
+
title: "Links"
|
|
101
|
+
description: "Friends & Resources"
|
|
102
|
+
sites:
|
|
103
|
+
- name: "Astro"
|
|
104
|
+
description: "The web framework for content-driven websites"
|
|
105
|
+
url: "https://astro.build"
|
|
106
|
+
icon: "https://astro.build/favicon.svg"
|
|
107
|
+
`,
|
|
108
|
+
"comment.yml": `id: comment
|
|
109
|
+
enabled: false
|
|
110
|
+
waline:
|
|
111
|
+
serverURL: ""
|
|
112
|
+
lang: ""
|
|
113
|
+
locale: ""
|
|
114
|
+
pageSize: 10
|
|
115
|
+
recaptchaV3Key: ""
|
|
116
|
+
`,
|
|
117
|
+
"promote.yml": `id: promote
|
|
118
|
+
export_md: false
|
|
119
|
+
# llm_promote: |
|
|
120
|
+
`,
|
|
121
|
+
"ai-discovery.yml": `id: ai-discovery
|
|
122
|
+
conformance: "none"
|
|
123
|
+
`,
|
|
124
|
+
"typetexts.yml": `id: typetexts
|
|
125
|
+
items:
|
|
126
|
+
- "Free for free, not free for charge!"
|
|
127
|
+
- "Where's the any key?"
|
|
128
|
+
- "Press F12?"
|
|
129
|
+
- "Hello World!"
|
|
130
|
+
`,
|
|
131
|
+
};
|
|
38
132
|
}
|
|
39
133
|
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
134
|
+
function getExamplePost() {
|
|
135
|
+
const date = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
136
|
+
return `---
|
|
137
|
+
title: Hello Stalux!
|
|
138
|
+
abbrlink: hello-stalux
|
|
139
|
+
date: "${date}"
|
|
140
|
+
tags: [Stalux, Getting Started]
|
|
141
|
+
categories: [Blog]
|
|
142
|
+
desc: Welcome to Stalux!
|
|
143
|
+
cc: CC-BY-NC-SA-4.0
|
|
144
|
+
---
|
|
43
145
|
|
|
44
|
-
|
|
45
|
-
stalux init [dir] Initialize Stalux content template
|
|
46
|
-
stalux --help Show this help message
|
|
146
|
+
Welcome to **Stalux**!
|
|
47
147
|
|
|
48
|
-
|
|
49
|
-
npx stalux init Init content in current directory
|
|
50
|
-
npx stalux init my-blog Init content in ./my-blog
|
|
51
|
-
npm run init Init via npm script (after install)
|
|
148
|
+
This is your first post. Edit or delete it, then start writing your own content.
|
|
52
149
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
150
|
+
## Features
|
|
151
|
+
|
|
152
|
+
- 🌙 Dark mode with elegant glassmorphism design
|
|
153
|
+
- 🔤 Per-route font subsetting — each page loads only needed characters
|
|
154
|
+
- 🔍 Full-text search (Pagefind)
|
|
155
|
+
- 📡 RSS & Atom feeds
|
|
156
|
+
- 💬 Comment system (Waline)
|
|
157
|
+
- 📊 Mermaid diagrams
|
|
158
|
+
- 📐 Math formula rendering
|
|
159
|
+
- 🖼️ PhotoSwipe lightbox
|
|
160
|
+
|
|
161
|
+
For more details, visit [Stalux documentation](https://stalux.needhelp.icu).
|
|
162
|
+
`;
|
|
56
163
|
}
|
|
57
164
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
165
|
+
function getAboutMd() {
|
|
166
|
+
return `---
|
|
167
|
+
title: About Me
|
|
168
|
+
description: About this blog and the author
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
Hello! Welcome to my blog.
|
|
172
|
+
|
|
173
|
+
This is my personal space where I share technology, life, and thoughts.
|
|
174
|
+
|
|
175
|
+
## About This Site
|
|
176
|
+
|
|
177
|
+
- Built with [Astro](https://astro.build) + [Stalux](https://stalux.needhelp.icu)
|
|
178
|
+
- Content licensed under CC-BY-NC-SA-4.0
|
|
179
|
+
- Source code hosted on GitHub
|
|
180
|
+
`;
|
|
70
181
|
}
|
|
71
182
|
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
183
|
+
function getWordsTemplate() {
|
|
184
|
+
const date = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
185
|
+
return `---
|
|
186
|
+
source: "Author Name"
|
|
187
|
+
link: ""
|
|
188
|
+
sourceDate: ""
|
|
189
|
+
date: "${date}"
|
|
190
|
+
---
|
|
75
191
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
process.exit(0);
|
|
192
|
+
> A quote or short note...
|
|
193
|
+
`;
|
|
79
194
|
}
|
|
80
195
|
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
196
|
+
function getWordsExample() {
|
|
197
|
+
const date = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
198
|
+
return `---
|
|
199
|
+
source: "Albert Einstein"
|
|
200
|
+
link: ""
|
|
201
|
+
sourceDate: ""
|
|
202
|
+
date: "${date}"
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
> Imagination is more important than knowledge.
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// 主流程
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
function main() {
|
|
214
|
+
const args = process.argv.slice(2);
|
|
215
|
+
|
|
216
|
+
if (args[0] === "--help" || args[0] === "-h" || !args[0]) {
|
|
217
|
+
printHelp();
|
|
218
|
+
process.exit(0);
|
|
219
|
+
}
|
|
84
220
|
|
|
85
|
-
if (
|
|
86
|
-
console.error(
|
|
87
|
-
|
|
88
|
-
);
|
|
221
|
+
if (args[0] !== "init") {
|
|
222
|
+
console.error(`❌ Unknown command: ${args[0]}`);
|
|
223
|
+
printHelp();
|
|
89
224
|
process.exit(1);
|
|
90
225
|
}
|
|
91
226
|
|
|
92
|
-
|
|
93
|
-
|
|
227
|
+
const targetArg = args[1] || ".";
|
|
228
|
+
const targetPath = pathResolve(process.cwd(), targetArg);
|
|
229
|
+
|
|
230
|
+
console.log(`📦 Initializing Stalux content in ${targetPath}...`);
|
|
231
|
+
console.log("");
|
|
232
|
+
|
|
233
|
+
// 创建 stalux/ 目录结构
|
|
234
|
+
const contentRoot = join(targetPath, "stalux");
|
|
235
|
+
const dirs = ["config", "posts", "about", "words"];
|
|
236
|
+
for (const dir of dirs) {
|
|
237
|
+
mkdirSync(join(contentRoot, dir), { recursive: true });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 生成 config YAML 文件(不覆盖已有)
|
|
241
|
+
const configs = getConfigYamls();
|
|
242
|
+
for (const [file, content] of Object.entries(configs)) {
|
|
243
|
+
const filePath = join(contentRoot, "config", file);
|
|
244
|
+
if (existsSync(filePath)) {
|
|
245
|
+
console.log(` ⏭ stalux/config/${file} (exists, skipped)`);
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
writeFileSync(filePath, content);
|
|
249
|
+
console.log(` ✅ stalux/config/${file}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 生成示例文章
|
|
253
|
+
const postPath = join(contentRoot, "posts", "hello-stalux.md");
|
|
254
|
+
if (!existsSync(postPath)) {
|
|
255
|
+
writeFileSync(postPath, getExamplePost());
|
|
256
|
+
console.log(` ✅ stalux/posts/hello-stalux.md`);
|
|
257
|
+
} else {
|
|
258
|
+
console.log(` ⏭ stalux/posts/hello-stalux.md (exists, skipped)`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// 生成 about 页面
|
|
262
|
+
const aboutPath = join(contentRoot, "about", "index.md");
|
|
263
|
+
if (!existsSync(aboutPath)) {
|
|
264
|
+
writeFileSync(aboutPath, getAboutMd());
|
|
265
|
+
console.log(` ✅ stalux/about/index.md`);
|
|
266
|
+
} else {
|
|
267
|
+
console.log(` ⏭ stalux/about/index.md (exists, skipped)`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 生成 words
|
|
271
|
+
const wordsDir = join(contentRoot, "words");
|
|
272
|
+
const wordsTemplatePath = join(wordsDir, "_template.md");
|
|
273
|
+
if (!existsSync(wordsTemplatePath)) {
|
|
274
|
+
writeFileSync(wordsTemplatePath, getWordsTemplate());
|
|
275
|
+
console.log(` ✅ stalux/words/_template.md`);
|
|
276
|
+
} else {
|
|
277
|
+
console.log(` ⏭ stalux/words/_template.md (exists, skipped)`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const einsteinPath = join(wordsDir, "einstein-imagination.md");
|
|
281
|
+
if (!existsSync(einsteinPath)) {
|
|
282
|
+
writeFileSync(einsteinPath, getWordsExample());
|
|
283
|
+
console.log(` ✅ stalux/words/einstein-imagination.md`);
|
|
284
|
+
} else {
|
|
285
|
+
console.log(` ⏭ stalux/words/einstein-imagination.md (exists, skipped)`);
|
|
286
|
+
}
|
|
287
|
+
|
|
94
288
|
console.log("");
|
|
289
|
+
console.log(" ✅ Done! Stalux content initialized.");
|
|
290
|
+
console.log("");
|
|
291
|
+
printNextSteps();
|
|
292
|
+
}
|
|
95
293
|
|
|
96
|
-
|
|
294
|
+
function printHelp() {
|
|
295
|
+
console.log(`
|
|
296
|
+
Stalux — Modern Astro Blog Theme
|
|
297
|
+
|
|
298
|
+
Usage:
|
|
299
|
+
stalux init Initialize Stalux content (configs, posts, pages)
|
|
300
|
+
stalux init my-blog Initialize in a subdirectory
|
|
301
|
+
|
|
302
|
+
What it does:
|
|
303
|
+
- Creates stalux/config/*.yml (all configuration files)
|
|
304
|
+
- Creates stalux/posts/hello-stalux.md (example post)
|
|
305
|
+
- Creates stalux/about/index.md (about page)
|
|
306
|
+
- Creates stalux/words/ (example quotes)
|
|
307
|
+
- Does NOT overwrite existing files
|
|
308
|
+
|
|
309
|
+
Prerequisites:
|
|
310
|
+
1. Create an Astro project: bun create astro
|
|
311
|
+
2. Install stalux: bun add @xingwangzhe/stalux
|
|
312
|
+
3. Run init: bunx stalux init
|
|
313
|
+
`);
|
|
314
|
+
}
|
|
97
315
|
|
|
98
|
-
|
|
99
|
-
|
|
316
|
+
function printNextSteps() {
|
|
317
|
+
console.log(" 📝 Next Steps:");
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log(" 1. Add stalux to your astro.config.mjs:");
|
|
320
|
+
console.log(' import stalux from "@xingwangzhe/stalux";');
|
|
321
|
+
console.log(' integrations: [stalux({ contentDir: "stalux" })],');
|
|
322
|
+
console.log("");
|
|
323
|
+
console.log(" 2. Add content collections to src/content.config.ts:");
|
|
324
|
+
console.log(
|
|
325
|
+
' import { defineCollections } from "@xingwangzhe/stalux/schemas/collections";',
|
|
326
|
+
);
|
|
327
|
+
console.log(' export const collections = defineCollections({ contentDir: "stalux" });');
|
|
328
|
+
console.log("");
|
|
329
|
+
console.log(" 3. Start writing content in stalux/posts/");
|
|
330
|
+
console.log(" 4. Run: bun run dev");
|
|
331
|
+
console.log("");
|
|
332
|
+
console.log(" 📖 Docs: https://stalux.needhelp.icu");
|
|
333
|
+
console.log("");
|
|
100
334
|
}
|
|
101
335
|
|
|
102
|
-
|
|
103
|
-
console.error(`❌ Unknown command: ${command}`);
|
|
104
|
-
console.error(` Use "stalux init" to initialize Stalux content.`);
|
|
105
|
-
process.exit(1);
|
|
336
|
+
main();
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { BadgeItem } from "@utils/badge-generator";
|
|
3
3
|
import { generateBadge, svgToDataUrl, isBadgeGroup } from "@utils/badge-generator";
|
|
4
|
+
import { createTranslator } from "@utils/i18n";
|
|
5
|
+
import { getCollection } from "astro:content";
|
|
6
|
+
import { getSiteData } from "@utils/config-utils";
|
|
4
7
|
|
|
5
8
|
interface Props {
|
|
6
9
|
badges?: BadgeItem[];
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
const { badges } = Astro.props;
|
|
13
|
+
const configEntries = await getCollection("config");
|
|
14
|
+
const siteConfig = getSiteData(configEntries);
|
|
15
|
+
const { t } = createTranslator(siteConfig.lang || "zh-CN");
|
|
10
16
|
|
|
11
17
|
function badgeImg(opts: Record<string, any>) {
|
|
12
18
|
const src = svgToDataUrl(generateBadge(opts));
|
|
@@ -29,8 +35,8 @@ function badgeImg(opts: Record<string, any>) {
|
|
|
29
35
|
<summary class="badge-group-summary">
|
|
30
36
|
<span class="badge-group-arrow">▶</span>
|
|
31
37
|
<span class="badge-group-title">{item.title}</span>
|
|
32
|
-
<span class="badge-group-hint" data-hint="expanded"
|
|
33
|
-
<span class="badge-group-hint" data-hint="collapsed"
|
|
38
|
+
<span class="badge-group-hint" data-hint="expanded">{t("footer.collapse")}</span>
|
|
39
|
+
<span class="badge-group-hint" data-hint="collapsed">{t("footer.expand")}</span>
|
|
34
40
|
</summary>
|
|
35
41
|
<div class="badge-group-items badges">
|
|
36
42
|
{item.items.map((b: any) => (
|
package/src/i18n/en.json
CHANGED
|
@@ -72,7 +72,9 @@
|
|
|
72
72
|
"runningTime": "Site running for",
|
|
73
73
|
"runtimeFormat": "{days}d {hours}h {minutes}m {seconds}s",
|
|
74
74
|
"rightsReserved": "All rights reserved.",
|
|
75
|
-
"securityIcon": "Public security filing icon"
|
|
75
|
+
"securityIcon": "Public security filing icon",
|
|
76
|
+
"collapse": "Collapse",
|
|
77
|
+
"expand": "Expand"
|
|
76
78
|
},
|
|
77
79
|
"comment": {
|
|
78
80
|
"title": "Comments",
|
package/src/i18n/zh-CN.json
CHANGED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { satteri } from "@astrojs/markdown-satteri";
|
|
2
|
-
import sitemap from "@astrojs/sitemap";
|
|
3
|
-
import { mermaidHast } from "@xingwangzhe/satteri-mermaid";
|
|
4
|
-
import { photoswipe } from "@xingwangzhe/satteri-photoswipe";
|
|
5
|
-
import stalux from "@xingwangzhe/stalux";
|
|
6
|
-
import expressiveCode from "astro-expressive-code";
|
|
7
|
-
import { defineConfig, fontProviders } from "astro/config";
|
|
8
|
-
|
|
9
|
-
// https://astro.build/config
|
|
10
|
-
export default defineConfig({
|
|
11
|
-
output: "static",
|
|
12
|
-
site: "https://example.com",
|
|
13
|
-
prefetch: {
|
|
14
|
-
prefetchAll: false,
|
|
15
|
-
defaultStrategy: "hover",
|
|
16
|
-
},
|
|
17
|
-
fonts: [
|
|
18
|
-
{
|
|
19
|
-
provider: fontProviders.local(),
|
|
20
|
-
name: "Google Sans Code",
|
|
21
|
-
cssVariable: "--font-code",
|
|
22
|
-
options: {
|
|
23
|
-
variants: [
|
|
24
|
-
{
|
|
25
|
-
weight: "100 900",
|
|
26
|
-
style: "normal",
|
|
27
|
-
src: [
|
|
28
|
-
"./node_modules/@xingwangzhe/stalux/src/assets/fonts/GoogleSansCode.woff2",
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
weight: "100 900",
|
|
33
|
-
style: "italic",
|
|
34
|
-
src: [
|
|
35
|
-
"./node_modules/@xingwangzhe/stalux/src/assets/fonts/GoogleSansCode-Italic.woff2",
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
integrations: [
|
|
43
|
-
stalux({
|
|
44
|
-
contentDir: "stalux",
|
|
45
|
-
}),
|
|
46
|
-
sitemap(),
|
|
47
|
-
expressiveCode({
|
|
48
|
-
themes: ["dark-plus", "github-light"],
|
|
49
|
-
styleOverrides: {
|
|
50
|
-
borderRadius: "0.5rem",
|
|
51
|
-
codeFontFamily:
|
|
52
|
-
'"JetBrains Mono", "Fira Code", "Consolas", "Courier New", monospace',
|
|
53
|
-
},
|
|
54
|
-
useDarkModeMediaQuery: true,
|
|
55
|
-
}),
|
|
56
|
-
],
|
|
57
|
-
markdown: {
|
|
58
|
-
processor: satteri({
|
|
59
|
-
features: {
|
|
60
|
-
math: true,
|
|
61
|
-
smartPunctuation: true,
|
|
62
|
-
gfm: true,
|
|
63
|
-
frontmatter: true,
|
|
64
|
-
},
|
|
65
|
-
mdastPlugins: [],
|
|
66
|
-
hastPlugins: [
|
|
67
|
-
photoswipe(),
|
|
68
|
-
mermaidHast({
|
|
69
|
-
responsive: true,
|
|
70
|
-
theme: "dark",
|
|
71
|
-
}),
|
|
72
|
-
],
|
|
73
|
-
}),
|
|
74
|
-
},
|
|
75
|
-
});
|
package/template/package.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "my-stalux-blog",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"type": "module",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"dev": "astro dev",
|
|
7
|
-
"build": "astro build",
|
|
8
|
-
"preview": "astro preview",
|
|
9
|
-
"astro": "astro"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@astrojs/markdown-satteri": "^1.0.0",
|
|
13
|
-
"@astrojs/sitemap": "^4.0.0",
|
|
14
|
-
"@pagefind/component-ui": "^1.5.0",
|
|
15
|
-
"@xingwangzhe/satteri-mermaid": "^0.7.0",
|
|
16
|
-
"@xingwangzhe/satteri-photoswipe": "^0.2.0",
|
|
17
|
-
"astro": "^7.0.0",
|
|
18
|
-
"astro-expressive-code": "^0.44.0",
|
|
19
|
-
"pagefind": "^1.5.0",
|
|
20
|
-
"stalux": "^2.0.0"
|
|
21
|
-
},
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"@astrojs/rss": "^4.0.0",
|
|
24
|
-
"@lucide/astro": "^1.0.0",
|
|
25
|
-
"typescript": "^7.0.0"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stalux 内容集合配置
|
|
3
|
-
*
|
|
4
|
-
* 使用 stalux 包提供的 defineCollections 快速配置。
|
|
5
|
-
* 如需自定义内容路径,修改 contentDir 参数即可。
|
|
6
|
-
*/
|
|
7
|
-
import { defineCollections } from "@xingwangzhe/stalux/schemas/collections";
|
|
8
|
-
|
|
9
|
-
export const collections = defineCollections({
|
|
10
|
-
contentDir: "stalux",
|
|
11
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: About Me
|
|
3
|
-
description: About this blog and the author
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Hello! Welcome to my blog.
|
|
7
|
-
|
|
8
|
-
This is my personal space where I share technology, life, and thoughts.
|
|
9
|
-
|
|
10
|
-
## About This Site
|
|
11
|
-
|
|
12
|
-
- Built with [Astro](https://astro.build) + [Stalux](https://stalux.needhelp.icu)
|
|
13
|
-
- Content licensed under CC-BY-NC-SA-4.0
|
|
14
|
-
- Source code hosted on GitHub
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
id: navs
|
|
2
|
-
items:
|
|
3
|
-
- icon: home
|
|
4
|
-
link: /
|
|
5
|
-
title: Home
|
|
6
|
-
- icon: archive
|
|
7
|
-
link: /archives/
|
|
8
|
-
title: Archives
|
|
9
|
-
- icon: folder
|
|
10
|
-
link: /categories/
|
|
11
|
-
title: Categories
|
|
12
|
-
- icon: tag
|
|
13
|
-
link: /tags/
|
|
14
|
-
title: Tags
|
|
15
|
-
- icon: quote
|
|
16
|
-
link: /words/
|
|
17
|
-
title: Words
|
|
18
|
-
- icon: link
|
|
19
|
-
link: /links/
|
|
20
|
-
title: Links
|
|
21
|
-
- icon: user
|
|
22
|
-
link: /about/
|
|
23
|
-
title: About
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Hello Stalux!
|
|
3
|
-
abbrlink: hello-stalux
|
|
4
|
-
date: "2026-07-27 10:00:00"
|
|
5
|
-
tags: [Stalux, Getting Started]
|
|
6
|
-
categories: [Blog]
|
|
7
|
-
desc: Welcome to Stalux! This is your first blog post.
|
|
8
|
-
cc: CC-BY-NC-SA-4.0
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
Welcome to my blog! This is the first post created with the **Stalux** theme.
|
|
12
|
-
|
|
13
|
-
## About Stalux
|
|
14
|
-
|
|
15
|
-
Stalux is a modern, high-performance Astro blog theme featuring:
|
|
16
|
-
|
|
17
|
-
- 🌙 Dark mode with elegant glassmorphism design
|
|
18
|
-
- 🔍 Full-text search (Pagefind)
|
|
19
|
-
- 📡 RSS & Atom feeds
|
|
20
|
-
- 🤖 LLM discovery files (llms.txt)
|
|
21
|
-
- 💬 Comment system (Waline)
|
|
22
|
-
- 📊 Mermaid diagrams
|
|
23
|
-
- 📐 Math formula rendering
|
|
24
|
-
- 🖼️ PhotoSwipe lightbox
|
|
25
|
-
- 📱 Fully responsive
|
|
26
|
-
|
|
27
|
-
## Markdown Examples
|
|
28
|
-
|
|
29
|
-
**Bold**, _italic_, ~~strikethrough~~, `inline code`
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
// Code block
|
|
33
|
-
function hello() {
|
|
34
|
-
console.log("Hello, Stalux!");
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
> Blockquote example
|
|
39
|
-
|
|
40
|
-
- List item 1
|
|
41
|
-
- List item 2
|
|
42
|
-
- List item 3
|
|
43
|
-
|
|
44
|
-
1. Ordered list 1
|
|
45
|
-
2. Ordered list 2
|
|
46
|
-
|
|
47
|
-
For more features, check the [Stalux documentation](https://stalux.needhelp.icu).
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
# source: "Source or Author"
|
|
3
|
-
# link: "https://source-link" # Optional; when present, source becomes clickable
|
|
4
|
-
# sourceDate: "1999" # Optional; source date
|
|
5
|
-
# date: "2026-07-27 20:45:00" # Optional; when recorded
|
|
6
|
-
# updated: "2026-07-27 21:00:00"
|
|
7
|
-
# draft: false # Optional; true hides the entry
|
|
8
|
-
# title: "Title" # Optional
|
|
9
|
-
# abbrlink: "custom-id" # Optional
|
|
10
|
-
# tags: [tag1, tag2] # Optional
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
Write the quote body here. Supports **Markdown**, `inline code`, and code blocks.
|