@xingwangzhe/stalux 1.23.2 → 1.24.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/README.md CHANGED
@@ -23,34 +23,35 @@ bun add @xingwangzhe/stalux # Install theme (all dependencies included)
23
23
  bunx stalux init # Generate stalux/ content directory
24
24
  ```
25
25
 
26
- Then configure `astro.config.mjs`:
26
+ Then configure `astro.config.mjs`. All plugins are bundled into the Stalux integration by default — **no manual configuration is needed**:
27
+
28
+ - **Markdown**: Mermaid (MDAST detection + HAST/SVG rendering), math formulas (Temml → MathML), word count / feature flags, and PhotoSwipe image lightbox are injected into the default `satteri()` processor automatically (math / frontmatter / gfm / smart punctuation are enabled by default).
29
+ - **Sitemap**: `@astrojs/sitemap` is bundled (`.md` source endpoints are filtered out by default).
30
+ - **Expressive Code**: bundled with line numbers enabled by default.
27
31
 
28
32
  ```ts
29
33
  import { defineConfig } from "astro/config";
30
- import { satteri } from "@astrojs/markdown-satteri";
31
- import sitemap from "@astrojs/sitemap";
32
- import expressiveCode from "astro-expressive-code";
33
34
  import stalux from "@xingwangzhe/stalux";
34
- import { mermaidHast } from "@xingwangzhe/satteri-mermaid";
35
- import { photoswipe } from "@xingwangzhe/satteri-photoswipe";
36
35
 
37
36
  export default defineConfig({
38
37
  output: "static",
39
38
  site: "https://example.com",
40
- integrations: [
41
- stalux({ contentDir: "stalux" }),
42
- sitemap(),
43
- expressiveCode({ themes: ["dark-plus", "github-light"] }),
44
- ],
45
- markdown: {
46
- processor: satteri({
47
- features: { math: true, smartPunctuation: true, gfm: true, frontmatter: true },
48
- hastPlugins: [photoswipe(), mermaidHast({ responsive: true, theme: "dark" })],
49
- }),
50
- },
39
+ integrations: [stalux({ contentDir: "stalux" })],
51
40
  });
52
41
  ```
53
42
 
43
+ To customize the bundled integrations, pass options (or disable them with `false`):
44
+
45
+ ```ts
46
+ integrations: [
47
+ stalux({
48
+ contentDir: "stalux",
49
+ sitemap: { filter: (page) => page.startsWith("https://example.com/posts/") },
50
+ expressiveCode: { themes: ["dark-plus", "github-light"] },
51
+ }),
52
+ ];
53
+ ```
54
+
54
55
  Create `src/content.config.ts`:
55
56
 
56
57
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.23.2",
3
+ "version": "1.24.0",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
package/src/config.ts CHANGED
@@ -4,6 +4,9 @@
4
4
  * 用户在 astro.config.mjs 中传入这些选项来自定义主题行为。
5
5
  */
6
6
 
7
+ import type { SitemapOptions } from "@astrojs/sitemap";
8
+
9
+ import type { ExpressiveCodeOptions } from "./expressive-code";
7
10
  import type { StaluxComponentKey } from "./internal/override";
8
11
 
9
12
  /** 用户可覆盖的组件映射 */
@@ -55,4 +58,16 @@ export interface StaluxOptions {
55
58
 
56
59
  /** 站点 URL(默认从 astro.config 读取) */
57
60
  site?: string;
61
+
62
+ /**
63
+ * 是否自动打包 @astrojs/sitemap(默认 true)。
64
+ * 传 false 关闭;传对象自定义选项(filter 会与默认的 .md 源码端点过滤叠加)。
65
+ */
66
+ sitemap?: boolean | SitemapOptions;
67
+
68
+ /**
69
+ * 是否自动打包 Expressive Code(默认 true,带代码块行号插件)。
70
+ * 传 false 关闭;传对象自定义主题/样式等选项。
71
+ */
72
+ expressiveCode?: boolean | ExpressiveCodeOptions;
58
73
  }
@@ -17,7 +17,7 @@
17
17
  import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
18
18
  import expressiveCodeBase from "astro-expressive-code";
19
19
 
20
- type ExpressiveCodeOptions = NonNullable<Parameters<typeof expressiveCodeBase>[0]>;
20
+ export type ExpressiveCodeOptions = NonNullable<Parameters<typeof expressiveCodeBase>[0]>;
21
21
 
22
22
  /**
23
23
  * 创建带默认行号插件的 Expressive Code 集成。
package/src/index.ts CHANGED
@@ -12,6 +12,9 @@ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from "
12
12
  import path from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
15
+ import sitemap from "@astrojs/sitemap";
16
+ import { mermaidMdast, mermaidHast } from "@xingwangzhe/satteri-mermaid";
17
+ import { photoswipe } from "@xingwangzhe/satteri-photoswipe";
15
18
  import type { AstroIntegration } from "astro";
16
19
  import { fontProviders } from "astro/config";
17
20
  // pagefind 是 ESM-only 包,需要在模块顶层导入
@@ -19,6 +22,7 @@ import { fontProviders } from "astro/config";
19
22
  import { createIndex as pagefindCreateIndex } from "pagefind";
20
23
 
21
24
  import type { StaluxOptions } from "./config";
25
+ import { expressiveCode } from "./expressive-code";
22
26
  import { staluxComponentsAlias } from "./internal/components-plugin";
23
27
  import { runFontSlicing, type FontSlice } from "./internal/font-slices";
24
28
  import { featureFlagsHast, featureFlagsMdast } from "./plugins/feature-flags";
@@ -212,11 +216,13 @@ function getViteAliases(srcDir: string) {
212
216
  * });
213
217
  * ```
214
218
  */
215
- export function stalux(options: StaluxOptions = {}): AstroIntegration {
219
+ export function stalux(options: StaluxOptions = {}): AstroIntegration[] {
216
220
  const opt: StaluxOptions = {
217
221
  contentDir: options.contentDir ?? "stalux",
218
222
  pagefind: options.pagefind ?? true,
219
223
  devToolbar: options.devToolbar ?? true,
224
+ sitemap: options.sitemap ?? true,
225
+ expressiveCode: options.expressiveCode ?? true,
220
226
  ...options,
221
227
  };
222
228
 
@@ -224,7 +230,7 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
224
230
  // 安装在 node_modules 中时,页面的文件路由不可用,需要通过 injectRoute 注入
225
231
  const isPluginMode = import.meta.url.includes("node_modules");
226
232
 
227
- return {
233
+ const coreIntegration: AstroIntegration = {
228
234
  name: "stalux",
229
235
  hooks: {
230
236
  "astro:config:setup": async ({
@@ -296,17 +302,33 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
296
302
 
297
303
  logger.info(`Stalux initialized (contentDir: ${opt.contentDir})`);
298
304
 
299
- // 5. 注入 satteri 插件(字数统计/特性标记/数学公式),按插件 name 去重
300
- // 源码模式下 astro.config 会显式注册同款插件,插件模式则由集成补齐,
301
- // 保证两种模式行为一致(wordCount/readingMinutes/hasImage 由构建期插件写入)。
302
- // 去重是必须的:重复注册 featureFlagsMdast 会导致字数统计翻倍。
305
+ // 5. 注入 satteri 插件(Mermaid/字数统计/特性标记/数学公式/PhotoSwipe),按插件 name 去重
306
+ // 两种模式都由集成补齐默认插件。Astro 7 的 markdown.processor 默认为 satteri(),
307
+ // 消费方即使完全不配置 processor,这里也会对默认 processor 的 options 做幂等合并:
308
+ // - features:默认开启 math / frontmatter / gfm / smartPunctuation(用户显式 false 则尊重)
309
+ // - mdastPlugins:mermaidMdast + temml(数学公式)+ featureFlagsMdast(字数统计)
310
+ // - hastPlugins:photoswipe(图片灯箱)+ mermaidHast + featureFlagsHast
311
+ // 去重是必须的:重复注册 Mermaid 或 featureFlagsMdast 会导致渲染异常或字数统计翻倍。
303
312
  try {
304
313
  const processor = (config.markdown?.processor ?? undefined) as
305
- | { name?: string; options?: { mdastPlugins?: any[]; hastPlugins?: any[] } }
314
+ | {
315
+ name?: string;
316
+ options?: {
317
+ mdastPlugins?: any[];
318
+ hastPlugins?: any[];
319
+ features?: Record<string, unknown>;
320
+ };
321
+ }
306
322
  | undefined;
307
323
  if (processor?.name === "satteri") {
308
- const mdastPlugins = processor.options?.mdastPlugins ?? [];
309
- const hastPlugins = processor.options?.hastPlugins ?? [];
324
+ const options = processor.options ?? {};
325
+ const mdastPlugins = (options.mdastPlugins ??= []);
326
+ const hastPlugins = (options.hastPlugins ??= []);
327
+ const features = (options.features ??= {});
328
+ // 默认开启 math / frontmatter / gfm / smartPunctuation
329
+ for (const key of ["math", "frontmatter", "gfm", "smartPunctuation"]) {
330
+ if (features[key] !== false) features[key] = true;
331
+ }
310
332
  const seen = new Set<string>();
311
333
  for (const p of [...mdastPlugins, ...hastPlugins]) {
312
334
  if (p?.name) seen.add(p.name);
@@ -318,13 +340,25 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
318
340
  }
319
341
  list.push(plugin);
320
342
  };
343
+ pushUnique(mdastPlugins, mermaidMdast());
321
344
  pushUnique(mdastPlugins, temml());
322
345
  pushUnique(mdastPlugins, featureFlagsMdast);
346
+ pushUnique(
347
+ hastPlugins,
348
+ mermaidHast({
349
+ responsive: true,
350
+ theme: "dark",
351
+ themeOverrides: { clusterBorder: "#cccccc" },
352
+ }),
353
+ );
354
+ pushUnique(hastPlugins, photoswipe());
323
355
  pushUnique(hastPlugins, featureFlagsHast);
324
- logger.debug("Stalux: injected satteri plugins (temml/feature-flags)");
356
+ logger.debug(
357
+ "Stalux: injected satteri plugins (mermaid/temml/photoswipe/feature-flags)",
358
+ );
325
359
  } else {
326
360
  logger.warn(
327
- "Stalux: markdown.processor 不是 satteri,无法注入字数统计/数学公式插件。" +
361
+ "Stalux: markdown.processor 不是 satteri,无法注入字数统计/数学公式/PhotoSwipe 插件。" +
328
362
  "请在 astro.config 中配置 `processor: satteri({...})`。",
329
363
  );
330
364
  }
@@ -436,6 +470,33 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration {
436
470
  },
437
471
  },
438
472
  };
473
+
474
+ // 打包内置集成:Astro 的 integrations 配置支持嵌套数组并自动展平(schema 里 val.flat(Infinity)),
475
+ // 因此这里返回 [coreIntegration, sitemap, expressiveCode],让消费方一行 `integrations: [stalux()]` 即可完成配置。
476
+ const bundled: AstroIntegration[] = [coreIntegration];
477
+
478
+ if (opt.sitemap !== false) {
479
+ const userSitemap = opt.sitemap === true ? undefined : opt.sitemap;
480
+ // 默认过滤:不把 Markdown 源码端点(/posts/*.md)写入 sitemap;用户自定义 filter 与之叠加
481
+ const defaultFilter = (page: string) => !page.endsWith(".md");
482
+ const userFilter = userSitemap?.filter;
483
+ const filter = userFilter
484
+ ? (page: string) => defaultFilter(page) && userFilter(page)
485
+ : defaultFilter;
486
+ bundled.push(
487
+ sitemap({
488
+ ...userSitemap,
489
+ filter,
490
+ }),
491
+ );
492
+ }
493
+
494
+ if (opt.expressiveCode !== false) {
495
+ const ecOptions = opt.expressiveCode === true ? undefined : opt.expressiveCode;
496
+ bundled.push(expressiveCode(ecOptions));
497
+ }
498
+
499
+ return bundled;
439
500
  }
440
501
 
441
502
  export default stalux;