@xingwangzhe/stalux 1.35.1 → 1.35.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.
Files changed (29) hide show
  1. package/README.md +4 -0
  2. package/package.json +23 -23
  3. package/src/components/stalux/archives/archivesList.astro +58 -50
  4. package/src/components/stalux/categories/categoriesList.astro +4 -4
  5. package/src/components/stalux/layout/footer.astro +8 -4
  6. package/src/components/stalux/layout/head.astro +3 -3
  7. package/src/components/stalux/layout/navs.astro +15 -15
  8. package/src/components/stalux/links/linkList.astro +4 -4
  9. package/src/components/stalux/links/socialMedia.astro +35 -35
  10. package/src/components/stalux/posts/PostTaxonomy.astro +14 -10
  11. package/src/components/stalux/posts/postCC.astro +7 -7
  12. package/src/components/stalux/posts/postCard.astro +47 -41
  13. package/src/components/stalux/posts/postContent.astro +49 -49
  14. package/src/components/stalux/posts/postList.astro +4 -4
  15. package/src/components/stalux/posts/postToc.astro +16 -16
  16. package/src/components/stalux/tags/tagsCloud.astro +20 -20
  17. package/src/components/stalux/words/wordCard.astro +28 -28
  18. package/src/components/stalux/words/wordList.astro +17 -17
  19. package/src/index.ts +98 -20
  20. package/src/internal/font-slices.ts +56 -6
  21. package/src/internal/html-images.ts +23 -2
  22. package/src/internal/image-dimensions.ts +60 -33
  23. package/src/internal/page-output-cache.ts +78 -0
  24. package/src/layouts/PostLayout.astro +9 -7
  25. package/src/layouts/Stalux.astro +4 -4
  26. package/src/pages/about.astro +6 -6
  27. package/src/pages/categories/[category].astro +4 -4
  28. package/src/pages/tags/[tag].astro +5 -1
  29. package/src/plugins/feature-flags.ts +5 -17
package/README.md CHANGED
@@ -116,6 +116,10 @@ The subset CSS uses an exact per-character `unicode-range` and `font-display: sw
116
116
 
117
117
  The persistent BLAKE3 cache key includes font bytes, face index, normalized character set, and algorithm version. Cache files live under `node_modules/.astro/` and are reused across pages and incremental builds. Font inputs are read locally; builds do not fetch fonts from the network.
118
118
 
119
+ Multi-page builds reuse prepared font data and hashing state through `FontSubsetter`, with up to four native worker tasks for cold subsets. Font containers are decoded/extracted to SFNT before reusable HarfBuzz preprocessing preserves original outlines; Google Brotli encodes WOFF2 at quality 8. Image dimensions, image loading hints, linked CSS text, and font character extraction share one HTML parse. Shared image dimensions and CSS-generated text are also reused within each build, and image-tag edits are assembled in a single pass.
120
+
121
+ Processed pages are cached under `node_modules/.astro/stalux-page-output/`. The cache checks source HTML and page paths, referenced local CSS/image content, font inputs, and processing code. Changed inputs, missing font files, and corrupt records trigger reprocessing. Unchanged pages restore their processed output; Pagefind still rebuilds the full search index on every build. Preserve `node_modules/.astro/` to reuse caches across builds; removing it safely rebuilds them.
122
+
119
123
  ### Visibility-aware loading and updates
120
124
 
121
125
  The desktop tag cloud loads dynamically near the viewport. Switching to mobile, leaving the viewport or hiding the document destroys it and stops animation scheduling; becoming visible recreates it. Tag clicks use Astro client navigation. Clocks and the footer runtime update only while visible, and the date changes only on a new day. Comments load within half a viewport (capped at 400px). Tag groups, archive months and category cards retain static HTML while deferring offscreen rendering.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.35.1",
3
+ "version": "1.35.3",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -95,47 +95,47 @@
95
95
  "styles:watch": "node scripts/build-styles.ts --watch"
96
96
  },
97
97
  "dependencies": {
98
- "@astrojs/compiler": "2.13.1",
99
- "@astrojs/markdown-satteri": "0.4.2",
100
- "@astrojs/partytown": "2.1.8",
98
+ "@astrojs/compiler": "^4.0.0",
99
+ "@astrojs/markdown-satteri": "^0.4.3",
100
+ "@astrojs/partytown": "^2.1.8",
101
101
  "@astrojs/rss": "^4.0.19",
102
102
  "@astrojs/sitemap": "^3.7.4",
103
- "@babel/parser": "7.29.9",
103
+ "@babel/parser": "^8.0.6",
104
104
  "@expressive-code/plugin-line-numbers": "^0.44.2",
105
- "@lucide/astro": "^1.47.0",
105
+ "@lucide/astro": "^1.52.0",
106
106
  "@mcp-b/webmcp-polyfill": "^5.1.0",
107
107
  "@pagefind/component-ui": "^1.5.2",
108
- "@waline/client": "3.16.0",
109
- "@xingwangzhe/cjk-font-split-native": "0.2.0",
110
- "@xingwangzhe/satteri-mermaid": "0.8.1",
111
- "@xingwangzhe/satteri-photoswipe": "^0.2.5",
112
- "@xingwangzhe/tags-cloud": "^1.2.8",
108
+ "@waline/client": "^3.16.0",
109
+ "@xingwangzhe/cjk-font-split-native": "^0.4.2",
110
+ "@xingwangzhe/satteri-mermaid": "^0.8.1",
111
+ "@xingwangzhe/satteri-photoswipe": "^0.2.6",
112
+ "@xingwangzhe/tags-cloud": "^1.2.9",
113
113
  "astro-expressive-code": "^0.44.2",
114
114
  "astro-seo": "^1.2.0",
115
115
  "badge-maker": "^6.0.0",
116
- "css-tree": "3.2.1",
117
- "magic-string": "0.30.21",
116
+ "css-tree": "^3.2.1",
117
+ "magic-string": "^1.4.3",
118
118
  "pagefind": "^1.5.2",
119
- "parse5": "8.0.1",
119
+ "parse5": "^8.0.1",
120
120
  "photoswipe": "^5.4.4",
121
121
  "satteri": "^0.10.5",
122
- "simple-icons": "^16.32.0",
122
+ "simple-icons": "^16.34.0",
123
123
  "temml": "^0.13.5",
124
124
  "yaml": "^2.9.1"
125
125
  },
126
126
  "devDependencies": {
127
- "@astrojs/check": "0.9.10",
128
- "@biomejs/biome": "2.5.14",
127
+ "@astrojs/check": "^0.9.10",
128
+ "@biomejs/biome": "^2.5.15",
129
129
  "@types/css-tree": "^3.2.0",
130
- "@types/node": "^26.6.2",
130
+ "@types/node": "^26.6.4",
131
131
  "@unocss/astro": "^66.10.5",
132
- "@vitest/coverage-v8": "5.0.1",
133
- "astro": "^7.3.5",
134
- "knip": "^6.37.0",
132
+ "@vitest/coverage-v8": "^5.0.3",
133
+ "astro": "^7.3.6",
134
+ "knip": "^6.40.0",
135
135
  "typescript": "npm:@typescript/typescript6@6.0.2",
136
136
  "unocss": "^66.10.5",
137
- "vite": "8.3.0",
138
- "vitest": "5.0.1"
137
+ "vite": "^8.3.3",
138
+ "vitest": "^5.0.3"
139
139
  },
140
140
  "peerDependencies": {
141
141
  "astro": "^7.3.5"
@@ -57,57 +57,65 @@ const archiveYears = [...archivesByYearMonth.entries()]
57
57
  <div class="stalux-archive-page-header">
58
58
  <div class="stalux-archive-timeline-container">
59
59
  {archiveYears.length > 0 ? (
60
- archiveYears.map((archiveYear) => (
61
- <div class="stalux-archive-year-section" data-year={String(archiveYear.year)}>
62
- <div class="stalux-archive-year-header">
63
- <h2 class="stalux-archive-year-title">{archiveYear.year}</h2>
64
- <div class="stalux-archive-year-count">
65
- {t("archives.postCount", { n: archiveYear.count })}
66
- </div>
67
- </div>
68
- {archiveYear.months.map(({ month, posts: monthPosts }) => (
69
- <div
70
- class="stalux-archive-month-section"
71
- data-archive-month
72
- style={{
73
- "--archive-estimate": `${Math.ceil(monthPosts.length / 12) * 12 * 48 + 40}px`,
74
- }}
75
- >
76
- <h3 class="stalux-archive-month-title">{t("archives.month", { n: month })}</h3>
77
- {Array.from({ length: Math.ceil(monthPosts.length / 12) }, (_, index) =>
78
- monthPosts.slice(index * 12, (index + 1) * 12),
79
- ).map((group) => (
80
- <ul
81
- class="stalux-archive-post-list"
82
- style={{ "--archive-group-estimate": `${group.length * 48}px` }}
83
- >
84
- {group.map((post) => (
85
- <li class="stalux-archive-post-item">
86
- <time
87
- class="stalux-archive-post-date"
88
- datetime={post.data.date}
60
+ archiveYears.map((archiveYear) => (
61
+ <div class="stalux-archive-year-section" data-year={String(archiveYear.year)}>
62
+ <div class="stalux-archive-year-header">
63
+ <h2 class="stalux-archive-year-title">{archiveYear.year}</h2>
64
+ <div class="stalux-archive-year-count">
65
+ {t("archives.postCount", { n: archiveYear.count })}
66
+ </div>
67
+ </div>
68
+ {archiveYear.months.map(({ month, posts: monthPosts }) => (
69
+ <div
70
+ class="stalux-archive-month-section"
71
+ data-archive-month
72
+ style={{
73
+ "--archive-estimate": `${Math.ceil(monthPosts.length / 12) * 12 * 48 + 40}px`,
74
+ }}
75
+ >
76
+ <h3 class="stalux-archive-month-title">
77
+ {t("archives.month", { n: month })}
78
+ </h3>
79
+ {Array.from(
80
+ { length: Math.ceil(monthPosts.length / 12) },
81
+ (_, index) => monthPosts.slice(index * 12, (index + 1) * 12),
82
+ ).map((group) => (
83
+ <ul
84
+ class="stalux-archive-post-list"
85
+ style={{
86
+ "--archive-group-estimate": `${group.length * 48}px`,
87
+ }}
89
88
  >
90
- {format(parseDate(post.data.date), "yyyy-MM-dd")}
91
- </time>
92
- <a
93
- href={`/posts/${post.data.abbrlink}/`}
94
- class="stalux-archive-post-link"
95
- data-archive-description={post.data.desc || ""}
96
- data-astro-prefetch="viewport"
97
- >
98
- {post.data.title}
99
- </a>
100
- </li>
101
- ))}
102
- </ul>
103
- ))}
104
- </div>
105
- ))}
106
- </div>
107
- ))
108
- ) : (
109
- <div class="stalux-archive-no-posts">{t("archives.noPosts")}</div>
110
- )}
89
+ {group.map((post) => (
90
+ <li class="stalux-archive-post-item">
91
+ <time
92
+ class="stalux-archive-post-date"
93
+ datetime={post.data.date}
94
+ >
95
+ {format(
96
+ parseDate(post.data.date),
97
+ "yyyy-MM-dd",
98
+ )}
99
+ </time>
100
+ <a
101
+ href={`/posts/${post.data.abbrlink}/`}
102
+ class="stalux-archive-post-link"
103
+ data-archive-description={post.data.desc || ""}
104
+ data-astro-prefetch="viewport"
105
+ >
106
+ {post.data.title}
107
+ </a>
108
+ </li>
109
+ ))}
110
+ </ul>
111
+ ))}
112
+ </div>
113
+ ))}
114
+ </div>
115
+ ))
116
+ ) : (
117
+ <div class="stalux-archive-no-posts">{t("archives.noPosts")}</div>
118
+ )}
111
119
  </div>
112
120
 
113
121
  <slot name="main" />
@@ -9,8 +9,8 @@ const categoryList = await getCategoryCountList(Astro.logger);
9
9
 
10
10
  <ul class="stalux-categories">
11
11
  {categoryList.map((category) => (
12
- <li>
13
- <CategoriesCard category={category} />
14
- </li>
15
- ))}
12
+ <li>
13
+ <CategoriesCard category={category} />
14
+ </li>
15
+ ))}
16
16
  </ul>
@@ -55,8 +55,8 @@ const formattedWordCount = formatWordCount(totalWordCount, siteConfig.lang || "z
55
55
  <div class="stalux-footer-content stalux-u-flex stalux-u-flex-col">
56
56
  <!-- 版权信息 -->
57
57
  {footerConfig?.copyright?.enabled && (
58
- <FooterCopyright author={author} startYear={footerConfig?.copyright?.startYear} />
59
- )}
58
+ <FooterCopyright author={author} startYear={footerConfig?.copyright?.startYear} />
59
+ )}
60
60
 
61
61
  <!-- 徽章展示 -->
62
62
  <FooterBadges badges={badges} />
@@ -64,8 +64,12 @@ const formattedWordCount = formatWordCount(totalWordCount, siteConfig.lang || "z
64
64
  <!-- 备案信息 -->
65
65
  <FooterBeian
66
66
  icp={footerConfig?.beian?.icp?.enabled ? footerConfig?.beian?.icp?.number : undefined}
67
- pubsec={footerConfig?.beian?.security?.enabled ? footerConfig?.beian?.security?.text : undefined}
68
- pubsecNumber={footerConfig?.beian?.security?.enabled ? footerConfig?.beian?.security?.number : undefined}
67
+ pubsec={footerConfig?.beian?.security?.enabled
68
+ ? footerConfig?.beian?.security?.text
69
+ : undefined}
70
+ pubsecNumber={footerConfig?.beian?.security?.enabled
71
+ ? footerConfig?.beian?.security?.number
72
+ : undefined}
69
73
  />
70
74
 
71
75
  <!-- 主题信息 -->
@@ -52,9 +52,9 @@ const ldJson = JSON.stringify(seo.schema).replace(/<\//g, "<\\/");
52
52
  openGraph={seo.openGraph}
53
53
  twitter={seo.twitter}
54
54
  extend={{
55
- link: seo.links,
56
- meta: seo.meta,
57
- }}
55
+ link: seo.links,
56
+ meta: seo.meta,
57
+ }}
58
58
  />
59
59
  <!-- 代码字体由 Astro Fonts API 注入;正文按页面生成 native CJK 子集。 -->
60
60
  <Font cssVariable="--font-code" />
@@ -48,21 +48,21 @@ const navs = navsConfig?.items ?? [];
48
48
  class="stalux-nav-list stalux-u-flex stalux-u-items-center stalux-u-justify-center stalux-u-flex-wrap stalux-u-w-full stalux-u-min-w-0"
49
49
  >
50
50
  {navs.map((item) => {
51
- const NavIcon = item.icon ? getLucideIcon(item.icon, Astro.logger) : null;
52
- return (
53
- <li class="stalux-nav-item stalux-u-flex stalux-u-items-center">
54
- <a
55
- href={item.link}
56
- class="stalux-nav-link"
57
- data-ref="stalux-nav-link"
58
- data-astro-prefetch
59
- >
60
- {NavIcon && <NavIcon size={20} stroke-width={2} class="nav-icon" />}
61
- <span class="stalux-nav-text">{item.title}</span>
62
- </a>
63
- </li>
64
- );
65
- })}
51
+ const NavIcon = item.icon ? getLucideIcon(item.icon, Astro.logger) : null;
52
+ return (
53
+ <li class="stalux-nav-item stalux-u-flex stalux-u-items-center">
54
+ <a
55
+ href={item.link}
56
+ class="stalux-nav-link"
57
+ data-ref="stalux-nav-link"
58
+ data-astro-prefetch
59
+ >
60
+ {NavIcon && <NavIcon size={20} stroke-width={2} class="nav-icon" />}
61
+ <span class="stalux-nav-text">{item.title}</span>
62
+ </a>
63
+ </li>
64
+ );
65
+ })}
66
66
  <li class="stalux-nav-item stalux-u-flex stalux-u-items-center">
67
67
  <a
68
68
  href="#search"
@@ -12,8 +12,8 @@ const links = linksConfig?.sites ?? [];
12
12
 
13
13
  <ul class="stalux-links">
14
14
  {links.map((link) => (
15
- <li class="stalux-link-list-item">
16
- <LinkCard link={link} />
17
- </li>
18
- ))}
15
+ <li class="stalux-link-list-item">
16
+ <LinkCard link={link} />
17
+ </li>
18
+ ))}
19
19
  </ul>
@@ -42,40 +42,40 @@ function getIconByTitle(iconName: string): SimpleIcon | undefined {
42
42
  >
43
43
  <ul>
44
44
  {mediaLinks.map((item) => {
45
- const icon = item.icon ? getIconByTitle(item.icon) : undefined;
46
- return (
47
- <li class="social_icon">
48
- <a
49
- href={item.link}
50
- target="_blank"
51
- aria-label={item.icon}
52
- rel="noopener noreferrer"
53
- title={item.icon}
54
- class="a-none"
55
- >
56
- {icon ? (
57
- <div class="icon-container">
58
- <svg
59
- role="img"
60
- viewBox="0 0 24 24"
61
- xmlns="http://www.w3.org/2000/svg"
62
- width="24"
63
- height="24"
64
- fill="currentColor"
65
- aria-hidden="true"
66
- >
67
- <title>{icon.title}</title>
68
- <path d={icon.path} />
69
- </svg>
70
- </div>
71
- ) : (
72
- <span class="custom-icon">
73
- {item.icon ? item.icon.charAt(0).toUpperCase() : ""}
74
- </span>
75
- )}
76
- </a>
77
- </li>
78
- );
79
- })}
45
+ const icon = item.icon ? getIconByTitle(item.icon) : undefined;
46
+ return (
47
+ <li class="social_icon">
48
+ <a
49
+ href={item.link}
50
+ target="_blank"
51
+ aria-label={item.icon}
52
+ rel="noopener noreferrer"
53
+ title={item.icon}
54
+ class="a-none"
55
+ >
56
+ {icon ? (
57
+ <div class="icon-container">
58
+ <svg
59
+ role="img"
60
+ viewBox="0 0 24 24"
61
+ xmlns="http://www.w3.org/2000/svg"
62
+ width="24"
63
+ height="24"
64
+ fill="currentColor"
65
+ aria-hidden="true"
66
+ >
67
+ <title>{icon.title}</title>
68
+ <path d={icon.path} />
69
+ </svg>
70
+ </div>
71
+ ) : (
72
+ <span class="custom-icon">
73
+ {item.icon ? item.icon.charAt(0).toUpperCase() : ""}
74
+ </span>
75
+ )}
76
+ </a>
77
+ </li>
78
+ );
79
+ })}
80
80
  </ul>
81
81
  </nav>
@@ -50,14 +50,18 @@ const cfg = {
50
50
  >
51
51
  {items.length > 0 && <h3 class="stalux-post-taxonomy-title">{title ?? cfg.heading}</h3>}
52
52
  {items.length > 0 ? (
53
- <div class={cfg.listClass} transition:name={cfg.contentName}>
54
- {items.map((item) => (
55
- <a href={`${cfg.prefix}${item}/`} class={`${cfg.itemClass} a-none`} data-astro-prefetch>
56
- {item}
57
- </a>
58
- ))}
59
- </div>
60
- ) : (
61
- <div class="stalux-post-taxonomy-empty">{cfg.empty}</div>
62
- )}
53
+ <div class={cfg.listClass} transition:name={cfg.contentName}>
54
+ {items.map((item) => (
55
+ <a
56
+ href={`${cfg.prefix}${item}/`}
57
+ class={`${cfg.itemClass} a-none`}
58
+ data-astro-prefetch
59
+ >
60
+ {item}
61
+ </a>
62
+ ))}
63
+ </div>
64
+ ) : (
65
+ <div class="stalux-post-taxonomy-empty">{cfg.empty}</div>
66
+ )}
63
67
  </nav>
@@ -30,13 +30,13 @@ const licenseName = buildCCName(cc, t);
30
30
  <p class="stalux-license-title">{title}</p>
31
31
  <p class="stalux-license-author">{t("post.author")}{author}</p>
32
32
  {url && (
33
- <p class="stalux-license-url">
34
- {t("post.articleLink")}
35
- <a href={url} target="_blank" rel="noopener noreferrer">
36
- {url}
37
- </a>
38
- </p>
39
- )}
33
+ <p class="stalux-license-url">
34
+ {t("post.articleLink")}
35
+ <a href={url} target="_blank" rel="noopener noreferrer">
36
+ {url}
37
+ </a>
38
+ </p>
39
+ )}
40
40
  <p class="stalux-license-license">
41
41
  {t("post.licensedUnder")}
42
42
  <a href={licenseLink} target="_blank" rel="noopener noreferrer">
@@ -23,25 +23,25 @@ const description = post.data.desc || "";
23
23
  <article class="stalux-post-card-shell block h-full text-inherit no-underline">
24
24
  <div class="stalux-post-card stalux-u-flex stalux-u-flex-col stalux-u-w-full stalux-u-min-w-0">
25
25
  {post.data.cover && (
26
- <a
27
- href={`/posts/${post.data.abbrlink}/`}
28
- class="a-none"
29
- data-astro-prefetch="viewport"
30
- aria-label={post.data.title}
31
- >
32
- <div class="stalux-card-post-cover stalux-u-w-full stalux-u-min-w-0">
33
- <img
34
- src={post.data.cover}
35
- alt={post.data.title}
36
- loading={priority ? "eager" : "lazy"}
37
- decoding="async"
38
- fetchpriority={priority ? "high" : "auto"}
39
- width="640"
40
- height="360"
41
- />
42
- </div>
43
- </a>
44
- )}
26
+ <a
27
+ href={`/posts/${post.data.abbrlink}/`}
28
+ class="a-none"
29
+ data-astro-prefetch="viewport"
30
+ aria-label={post.data.title}
31
+ >
32
+ <div class="stalux-card-post-cover stalux-u-w-full stalux-u-min-w-0">
33
+ <img
34
+ src={post.data.cover}
35
+ alt={post.data.title}
36
+ loading={priority ? "eager" : "lazy"}
37
+ decoding="async"
38
+ fetchpriority={priority ? "high" : "auto"}
39
+ width="640"
40
+ height="360"
41
+ />
42
+ </div>
43
+ </a>
44
+ )}
45
45
  <h2
46
46
  class="stalux-card-post-title"
47
47
  transition:name={priority ? getPostTitleTransitionName(post.data.abbrlink) : undefined}
@@ -52,21 +52,27 @@ const description = post.data.desc || "";
52
52
  </h2>
53
53
  <div class="stalux-card-time stalux-u-items-center stalux-u-flex-wrap">
54
54
  {post.data.date && (
55
- <time
56
- class="stalux-card-post-date"
57
- datetime={timezone ? toMachineDateTime(post.data.date, timezone) : post.data.date}
58
- >
59
- {post.data.date}
60
- </time>
61
- )}
55
+ <time
56
+ class="stalux-card-post-date"
57
+ datetime={
58
+ timezone ? toMachineDateTime(post.data.date, timezone) : post.data.date
59
+ }
60
+ >
61
+ {post.data.date}
62
+ </time>
63
+ )}
62
64
  {post.data.updated && (
63
- <time
64
- class="stalux-card-post-updated"
65
- datetime={timezone ? toMachineDateTime(post.data.updated, timezone) : post.data.updated}
66
- >
67
- {post.data.updated}
68
- </time>
69
- )}
65
+ <time
66
+ class="stalux-card-post-updated"
67
+ datetime={
68
+ timezone
69
+ ? toMachineDateTime(post.data.updated, timezone)
70
+ : post.data.updated
71
+ }
72
+ >
73
+ {post.data.updated}
74
+ </time>
75
+ )}
70
76
  </div>
71
77
  <div class="stalux-card-post-description stalux-u-min-w-0">{description}</div>
72
78
  <div class="stalux-card-post-meta stalux-u-flex stalux-u-flex-col">
@@ -74,19 +80,19 @@ const description = post.data.desc || "";
74
80
  class="stalux-card-post-tags stalux-u-flex stalux-u-items-center stalux-u-flex-wrap"
75
81
  >
76
82
  {post.data.tags?.map((tag) => (
77
- <a class="a-none" href={`/tags/${tag}`} data-astro-prefetch>
78
- <span class="stalux-card-post-tag">{tag}</span>
79
- </a>
80
- ))}
83
+ <a class="a-none" href={`/tags/${tag}`} data-astro-prefetch>
84
+ <span class="stalux-card-post-tag">{tag}</span>
85
+ </a>
86
+ ))}
81
87
  </div>
82
88
  <div
83
89
  class="stalux-card-post-categories stalux-u-flex stalux-u-items-center stalux-u-flex-wrap"
84
90
  >
85
91
  {post.data.categories?.map((category) => (
86
- <a class="a-none" href={`/categories/${category}`} data-astro-prefetch>
87
- <span class="stalux-card-post-category">{category}</span>
88
- </a>
89
- ))}
92
+ <a class="a-none" href={`/categories/${category}`} data-astro-prefetch>
93
+ <span class="stalux-card-post-category">{category}</span>
94
+ </a>
95
+ ))}
90
96
  </div>
91
97
  </div>
92
98
  <a