@xingwangzhe/stalux 1.7.8 → 1.8.0
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/package.json
CHANGED
|
@@ -59,9 +59,9 @@ const mdSourceUrl = exportMd
|
|
|
59
59
|
)
|
|
60
60
|
}
|
|
61
61
|
</div>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{(props.readingTime || props.readingMinutes) && (
|
|
62
|
+
{
|
|
63
|
+
<div class={style.pageStats}>
|
|
64
|
+
{(Boolean(props.readingTime) || (props.readingMinutes ?? 0) > 0) && (
|
|
65
65
|
<span class={style.readingTime}>
|
|
66
66
|
{t("post.readingTime")}{props.readingMinutes && props.readingMinutes > 0
|
|
67
67
|
? (props.readingMinutes < 1
|
|
@@ -70,7 +70,7 @@ const mdSourceUrl = exportMd
|
|
|
70
70
|
: props.readingTime}
|
|
71
71
|
</span>
|
|
72
72
|
)}
|
|
73
|
-
{props.wordCount
|
|
73
|
+
{(props.wordCount ?? 0) > 0 && (
|
|
74
74
|
<span class={style.wordCount}>
|
|
75
75
|
{t("post.wordCount")}{props.wordCount}
|
|
76
76
|
</span>
|
package/src/i18n/en.json
CHANGED
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"author": "xingwangzhe",
|
|
137
137
|
"copyright": "© xingwangzhe. All rights reserved.",
|
|
138
138
|
"certNumber": "Software Copyright No. 16914672",
|
|
139
|
-
"certUrl": "
|
|
139
|
+
"certUrl": "/软著证明.pdf",
|
|
140
140
|
"regDate": "2025-11-24",
|
|
141
141
|
"labelVersion": "📦 Version: ",
|
|
142
142
|
"labelAuthor": "👤 Author: ",
|
package/src/i18n/zh-CN.json
CHANGED
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"author": "王兴家 (xingwangzhe)",
|
|
137
137
|
"copyright": "© 王兴家. All rights reserved.",
|
|
138
138
|
"certNumber": "软著登字第16914672号",
|
|
139
|
-
"certUrl": "
|
|
139
|
+
"certUrl": "/软著证明.pdf",
|
|
140
140
|
"regDate": "2025年11月24日",
|
|
141
141
|
"labelVersion": "📦 版本:",
|
|
142
142
|
"labelAuthor": "👤 著作权人:",
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 基于 Astro 7.1.3 Integration API(astro:config:setup / injectRoute / injectScript)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { existsSync, readdirSync } from "node:fs";
|
|
11
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { resolve } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
@@ -21,6 +21,8 @@ import { createIndex as pagefindCreateIndex } from "pagefind";
|
|
|
21
21
|
import type { StaluxOptions } from "./config";
|
|
22
22
|
import { staluxComponentsAlias } from "./internal/components-plugin";
|
|
23
23
|
import { runFontSubsetting } from "./internal/font-subset";
|
|
24
|
+
import { featureFlagsHast, featureFlagsMdast } from "./plugins/feature-flags";
|
|
25
|
+
import { temml } from "./plugins/satteri-temml";
|
|
24
26
|
|
|
25
27
|
// ---------------------------------------------------------------------------
|
|
26
28
|
// 页面条目定义
|
|
@@ -143,7 +145,7 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
|
|
|
143
145
|
injectScript,
|
|
144
146
|
updateConfig,
|
|
145
147
|
addDevToolbarApp,
|
|
146
|
-
|
|
148
|
+
config,
|
|
147
149
|
logger,
|
|
148
150
|
}) => {
|
|
149
151
|
const srcDir = fileURLToPath(new URL(".", import.meta.url));
|
|
@@ -191,7 +193,81 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
|
|
|
191
193
|
|
|
192
194
|
logger.info(`Stalux initialized (contentDir: ${opt.contentDir})`);
|
|
193
195
|
|
|
194
|
-
// 5.
|
|
196
|
+
// 5. 注入 satteri 插件(字数统计/特性标记/数学公式),按插件 name 去重
|
|
197
|
+
// 源码模式下 astro.config 会显式注册同款插件,插件模式则由集成补齐,
|
|
198
|
+
// 保证两种模式行为一致(wordCount/readingMinutes/hasImage 由构建期插件写入)。
|
|
199
|
+
// 去重是必须的:重复注册 featureFlagsMdast 会导致字数统计翻倍。
|
|
200
|
+
try {
|
|
201
|
+
const processor = (config.markdown?.processor ?? undefined) as
|
|
202
|
+
| { name?: string; options?: { mdastPlugins?: any[]; hastPlugins?: any[] } }
|
|
203
|
+
| undefined;
|
|
204
|
+
if (processor?.name === "satteri") {
|
|
205
|
+
const mdastPlugins = processor.options?.mdastPlugins ?? [];
|
|
206
|
+
const hastPlugins = processor.options?.hastPlugins ?? [];
|
|
207
|
+
const seen = new Set<string>();
|
|
208
|
+
for (const p of [...mdastPlugins, ...hastPlugins]) {
|
|
209
|
+
if (p?.name) seen.add(p.name);
|
|
210
|
+
}
|
|
211
|
+
const pushUnique = (list: any[], plugin: any) => {
|
|
212
|
+
if (plugin?.name) {
|
|
213
|
+
if (seen.has(plugin.name)) return;
|
|
214
|
+
seen.add(plugin.name);
|
|
215
|
+
}
|
|
216
|
+
list.push(plugin);
|
|
217
|
+
};
|
|
218
|
+
pushUnique(mdastPlugins, temml());
|
|
219
|
+
pushUnique(mdastPlugins, featureFlagsMdast);
|
|
220
|
+
pushUnique(hastPlugins, featureFlagsHast);
|
|
221
|
+
logger.debug("Stalux: injected satteri plugins (temml/feature-flags)");
|
|
222
|
+
} else {
|
|
223
|
+
logger.warn(
|
|
224
|
+
"Stalux: markdown.processor 不是 satteri,无法注入字数统计/数学公式插件。" +
|
|
225
|
+
"请在 astro.config 中配置 `processor: satteri({...})`。",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
} catch (error) {
|
|
229
|
+
logger.warn(`Stalux: 注入 markdown 插件失败: ${String(error)}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// 6. 站点 URL 单源化:以 stalux/config/site.yml 的 url 为准
|
|
233
|
+
// sitemap 与 context.site 都派生自 astro.config 的 site 字段,
|
|
234
|
+
// 这里在构建前将其与主题配置对齐,避免输出与配置不一致的 URL
|
|
235
|
+
// (例如 README 里的 https://example.com 占位、或用户只改了 site.yml 忘了改 astro.config)。
|
|
236
|
+
try {
|
|
237
|
+
const contentDir = opt.contentDir ?? "stalux";
|
|
238
|
+
const siteYamlPath = path.resolve(
|
|
239
|
+
process.cwd(),
|
|
240
|
+
contentDir,
|
|
241
|
+
"config",
|
|
242
|
+
"site.yml",
|
|
243
|
+
);
|
|
244
|
+
const siteYaml = readFileSync(siteYamlPath, "utf-8");
|
|
245
|
+
const urlMatch = siteYaml.match(/^url\s*:\s*(.+)$/m);
|
|
246
|
+
const yamlUrl = urlMatch?.[1]
|
|
247
|
+
.trim()
|
|
248
|
+
.replace(/^["']|["']$/g, "")
|
|
249
|
+
.replace(/\/+$/, "");
|
|
250
|
+
if (yamlUrl) {
|
|
251
|
+
const configuredSite = config.site?.replace(/\/+$/, "");
|
|
252
|
+
if (!configuredSite || configuredSite === "https://example.com") {
|
|
253
|
+
// 未配置或为占位符 → 直接以 site.yml 为准
|
|
254
|
+
updateConfig({ site: yamlUrl });
|
|
255
|
+
logger.info(
|
|
256
|
+
`Stalux: site set to ${yamlUrl} (from ${contentDir}/config/site.yml)`,
|
|
257
|
+
);
|
|
258
|
+
} else if (configuredSite !== yamlUrl) {
|
|
259
|
+
// 用户显式配置了不同的域名 → 保留用户配置,但提示差异
|
|
260
|
+
logger.warn(
|
|
261
|
+
`Stalux: astro.config site (${configuredSite}) 与 ${contentDir}/config/site.yml 的 url (${yamlUrl}) 不一致。` +
|
|
262
|
+
"sitemap 将使用 astro.config 的 site,llms.txt / *.md 导出将使用 site.yml 的 url,请统一二者。",
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
} catch {
|
|
267
|
+
logger.debug("Stalux: site.yml not found, skip site sync");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 7. 字体裁剪(在 config:setup 阶段执行,保证 dev/build 都能生成)
|
|
195
271
|
try {
|
|
196
272
|
const projectRoot = process.cwd();
|
|
197
273
|
await runFontSubsetting(projectRoot, logger, true);
|
|
@@ -201,7 +277,7 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
|
|
|
201
277
|
},
|
|
202
278
|
|
|
203
279
|
"astro:build:start": async ({ logger }) => {
|
|
204
|
-
//
|
|
280
|
+
// 8. 字体裁剪(构建时,生成全部路由子集)
|
|
205
281
|
try {
|
|
206
282
|
const projectRoot = process.cwd();
|
|
207
283
|
await runFontSubsetting(projectRoot, logger);
|
|
@@ -211,7 +287,7 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
|
|
|
211
287
|
},
|
|
212
288
|
|
|
213
289
|
"astro:server:setup": async ({ server, logger }) => {
|
|
214
|
-
//
|
|
290
|
+
// 9. 字体裁剪(开发模式,生成 common 子集 + 按需路由切片)
|
|
215
291
|
try {
|
|
216
292
|
const projectRoot = process.cwd();
|
|
217
293
|
// 清除旧的字体缓存
|
|
@@ -49,10 +49,16 @@ function getSiteConfig(config: ConfigMap): Record<string, unknown> {
|
|
|
49
49
|
return config.get("site") ?? {};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* 解析站点根 URL。
|
|
54
|
+
*
|
|
55
|
+
* 唯一真源是 stalux/config/site.yml 的 url;context.site(astro.config.mjs 的 site)
|
|
56
|
+
* 仅作为 site.yml 缺失时的兜底,避免 llms.txt / *.md 导出与 sitemap / canonical 输出不一致。
|
|
57
|
+
*/
|
|
53
58
|
export function getSite(config: ConfigMap, contextSite?: string): string {
|
|
54
59
|
const siteData = getSiteConfig(config);
|
|
55
|
-
|
|
60
|
+
const configUrl = siteData.url as string | undefined;
|
|
61
|
+
return (configUrl || contextSite || "").replace(/\/$/, "");
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/** 将任意空白压缩为单行 */
|