@xingwangzhe/stalux 1.5.2 → 1.5.4

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "A powerful, modern Astro blog theme \u2014 use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -204,6 +204,21 @@ function collectCommonChars(projectRoot: string): string {
204
204
  }
205
205
  }
206
206
 
207
+ // Also scan post frontmatter for tags, categories so those pages' chars are covered
208
+ const postsDir = resolve(projectRoot, CONTENT_ROOT, "posts");
209
+ if (existsSync(postsDir)) {
210
+ for (const f of readdirSync(postsDir)) {
211
+ if (!f.endsWith(".md") && !f.endsWith(".mdx")) continue;
212
+ if (f.startsWith("_")) continue;
213
+ try {
214
+ const content = readFileSync(join(postsDir, f), "utf-8");
215
+ for (const ch of content) chars.add(ch);
216
+ } catch {
217
+ /* skip */
218
+ }
219
+ }
220
+ }
221
+
207
222
  return [...chars].sort().join("");
208
223
  }
209
224
 
@@ -342,79 +357,64 @@ export async function runFontSubsetting(
342
357
  const postMap: Record<string, string> = {};
343
358
 
344
359
  let subsetCount = 0;
345
- const cssGenerated = new Set<string>();
346
-
347
- if (!skipPerRoute) {
348
- for (const [hash, routes] of groups) {
349
- const filename = `subset-${hash}.ttf`;
350
- const outPath = join(outDir, filename);
351
- if (!existsSync(outPath)) {
352
- const route = routeSets.find((r) => r.hash === hash);
353
- const chars = route?.chars ?? "";
354
- const uniqueChars = chars
355
- .split("")
356
- .filter((ch) => !commonChars.includes(ch))
357
- .join("");
358
- if (uniqueChars.length > 0) {
359
- const glyphs = get_glyph_ids(uniqueChars, "stalux", "normal", 400);
360
- if (glyphs.length > 0) {
361
- const result = subset_font_full("stalux", "normal", 400, 0, glyphs);
362
- writeFileSync(outPath, result.fontBytes);
363
- subsetCount++;
364
- logger.info(
365
- ` subset ${subsetCount}: ${(result.fontBytes.length / 1024).toFixed(1)} KB → ${filename}`,
366
- );
360
+
361
+ if (!skipPerRoute) {
362
+ for (const [hash, routes] of groups) {
363
+ const filename = `subset-${hash}.ttf`;
364
+ const outPath = join(outDir, filename);
365
+ if (!existsSync(outPath)) {
366
+ const route = routeSets.find((r) => r.hash === hash);
367
+ const chars = route?.chars ?? "";
368
+ const uniqueChars = chars
369
+ .split("")
370
+ .filter((ch) => !commonChars.includes(ch))
371
+ .join("");
372
+ if (uniqueChars.length > 0) {
373
+ const glyphs = get_glyph_ids(uniqueChars, "stalux", "normal", 400);
374
+ if (glyphs.length > 0) {
375
+ const result = subset_font_full("stalux", "normal", 400, 0, glyphs);
376
+ writeFileSync(outPath, result.fontBytes);
377
+ subsetCount++;
378
+ logger.info(
379
+ ` subset ${subsetCount}: ${(result.fontBytes.length / 1024).toFixed(1)} KB → ${filename}`,
380
+ );
381
+ }
367
382
  }
368
383
  }
369
- }
370
384
 
371
- // Generate per-route CSS (one per unique hash, references all routes with this hash)
372
- if (!cssGenerated.has(hash)) {
373
- cssGenerated.add(hash);
385
+ // Generate per-route CSS (each route gets its own CSS file)
386
+ // If no unique chars, reference the common TTF as fallback
387
+ const refTtf = existsSync(outPath) ? filename : commonFilename;
374
388
  for (const route of routes) {
375
389
  const cssContent = `/* Auto-generated font subset for route: ${route} */
376
390
  @font-face {
377
391
  font-family: "LXGW WenKai Subset";
378
- src: url("/fonts/${filename}") format("truetype");
392
+ src: url("/fonts/${refTtf}") format("truetype");
379
393
  font-display: swap;
380
394
  }
381
395
  `;
382
- // Use first route's name as the CSS filename (they share the same subset)
383
- const cssName = routes.length === 1 ? route.replace("/", "-") : `group-${hash}`;
384
- const cssFilename = `subset-${cssName}.css`;
385
- writeFileSync(join(outDir, cssFilename), cssContent);
386
- routeMap[route] = cssFilename;
387
-
388
- if (route.startsWith("posts/")) {
389
- const abbrlink = route.replace("posts/", "");
390
- postMap[abbrlink] = cssFilename;
391
- }
392
- }
393
- } else {
394
- // CSS already generated, just map
395
- for (const route of routes) {
396
- const cssFilename =
397
- routes.length === 1
398
- ? `subset-${route.replace("/", "-")}.css`
399
- : `subset-group-${hash}.css`;
400
- routeMap[route] = cssFilename;
401
- if (route.startsWith("posts/")) {
402
- postMap[route.replace("posts/", "")] = cssFilename;
403
- }
396
+ const cssName = route.replace("/", "-");
397
+ const cssFilename = `subset-${cssName}.css`;
398
+ writeFileSync(join(outDir, cssFilename), cssContent);
399
+ routeMap[route] = cssFilename;
400
+
401
+ if (route.startsWith("posts/")) {
402
+ const abbrlink = route.replace("posts/", "");
403
+ postMap[abbrlink] = cssFilename;
404
404
  }
405
405
  }
406
406
  }
407
- }
408
407
 
409
- // 6. Generate manifest
410
- const manifest: FontManifest = {
411
- common: commonFilename,
412
- routes: routeMap,
413
- posts: postMap,
414
- };
415
- writeFileSync(join(outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
416
-
417
- logger.info(
418
- `Font subsetting done: ${subsetCount} route subsets + common (${(fontBuffer.length / 1024 / 1024).toFixed(1)} MB → variable)`,
419
- );
408
+ // 6. Generate manifest
409
+ const manifest: FontManifest = {
410
+ common: commonFilename,
411
+ routes: routeMap,
412
+ posts: postMap,
413
+ };
414
+ writeFileSync(join(outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
415
+
416
+ logger.info(
417
+ `Font subsetting done: ${subsetCount} route subsets + common (${(fontBuffer.length / 1024 / 1024).toFixed(1)} MB → variable)`,
418
+ );
419
+ }
420
420
  }