@xingwangzhe/stalux 1.29.7 → 1.30.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 +6 -2
- package/package.json +10 -6
- package/src/components/stalux/archives/archivesList.astro +22 -16
- package/src/components/stalux/archives/toArchive.astro +2 -2
- package/src/components/stalux/categories/categoriesCard.astro +8 -7
- package/src/components/stalux/categories/categoriesList.astro +3 -2
- package/src/components/stalux/common/author.astro +3 -3
- package/src/components/stalux/common/date.astro +3 -4
- package/src/components/stalux/common/textType.astro +2 -2
- package/src/components/stalux/footer/FooterBadges.astro +9 -97
- package/src/components/stalux/footer/FooterBeian.astro +2 -44
- package/src/components/stalux/footer/FooterCopyright.astro +1 -16
- package/src/components/stalux/footer/FooterStats.astro +4 -25
- package/src/components/stalux/footer/FooterThemeInfo.astro +1 -28
- package/src/components/stalux/layout/footer.astro +3 -3
- package/src/components/stalux/layout/listPage.astro +3 -3
- package/src/components/stalux/layout/navs.astro +13 -13
- package/src/components/stalux/links/linkCard.astro +7 -6
- package/src/components/stalux/links/linkList.astro +4 -3
- package/src/components/stalux/links/socialMedia.astro +2 -2
- package/src/components/stalux/posts/PostTaxonomy.astro +13 -8
- package/src/components/stalux/posts/postAuthor.astro +6 -5
- package/src/components/stalux/posts/postCC.astro +10 -9
- package/src/components/stalux/posts/postCard.astro +15 -15
- package/src/components/stalux/posts/postContent.astro +22 -14
- package/src/components/stalux/posts/postLeft.astro +5 -4
- package/src/components/stalux/posts/postList.astro +2 -3
- package/src/components/stalux/posts/postNavigation.astro +24 -23
- package/src/components/stalux/posts/postRight.astro +7 -6
- package/src/components/stalux/posts/postToc.astro +7 -19
- package/src/components/stalux/posts/randomPost.astro +8 -7
- package/src/components/stalux/tags/tagHeader.astro +10 -6
- package/src/components/stalux/tags/tagsCloud.astro +10 -9
- package/src/components/stalux/words/wordCard.astro +11 -10
- package/src/components/stalux/words/wordList.astro +4 -3
- package/src/index.ts +5 -4
- package/src/internal/runtime-cache-key.ts +13 -1
- package/src/layouts/PostLayout.astro +3 -4
- package/src/layouts/Stalux.astro +0 -17
- package/src/pages/404.astro +6 -77
- package/src/pages/archives.astro +3 -3
- package/src/pages/categories/index.astro +3 -3
- package/src/pages/index.astro +4 -18
- package/src/pages/tags/index.astro +3 -3
- package/src/pages/words.astro +3 -3
- package/src/scripts/analytics-runtime.ts +9 -6
- package/src/scripts/waline-client.ts +1 -1
- package/src/styles/archives.css +2 -0
- package/src/styles/article.css +2 -0
- package/src/styles/categories.css +2 -0
- package/src/styles/components/posts/waline.css +19 -23
- package/src/styles/generated-archives.css +3 -0
- package/src/styles/generated-article.css +3 -0
- package/src/styles/generated-categories.css +3 -0
- package/src/styles/generated-links.css +3 -0
- package/src/styles/generated-prose.css +2 -0
- package/src/styles/generated-tags.css +3 -0
- package/src/styles/generated-waline.css +2 -0
- package/src/styles/generated-words.css +3 -0
- package/src/styles/generated.css +3 -0
- package/src/styles/links.css +2 -0
- package/src/styles/prose.css +3 -0
- package/src/styles/tags.css +2 -0
- package/src/styles/theme/archives.css +138 -0
- package/src/styles/theme/article.css +562 -0
- package/src/styles/theme/base.css +290 -0
- package/src/styles/theme/categories.css +54 -0
- package/src/styles/theme/common.css +79 -0
- package/src/styles/theme/footer.css +26 -0
- package/src/styles/theme/inline.css +153 -0
- package/src/styles/theme/layout.css +143 -0
- package/src/styles/theme/link-cards.css +114 -0
- package/src/styles/theme/links.css +69 -0
- package/src/styles/theme/pages.css +35 -0
- package/src/styles/theme/posts.css +79 -0
- package/src/styles/theme/prose.css +478 -0
- package/src/styles/theme/tags.css +130 -0
- package/src/styles/theme/words.css +84 -0
- package/src/styles/theme.css +12 -0
- package/src/styles/words.css +2 -0
- package/src/styles/base/init.css +0 -287
- package/src/styles/components/archives/archivesList.module.css +0 -203
- package/src/styles/components/archives/toArchive.module.css +0 -3
- package/src/styles/components/categories/categoriesCard.module.css +0 -88
- package/src/styles/components/categories/categoriesList.module.css +0 -23
- package/src/styles/components/common/author.module.css +0 -72
- package/src/styles/components/common/date.module.css +0 -15
- package/src/styles/components/common/textType.module.css +0 -10
- package/src/styles/components/footer/footer.module.css +0 -44
- package/src/styles/components/layout/navs.module.css +0 -261
- package/src/styles/components/links/linkCard.module.css +0 -116
- package/src/styles/components/links/linkList.module.css +0 -54
- package/src/styles/components/links/socialLinks.module.css +0 -80
- package/src/styles/components/markdown.css +0 -523
- package/src/styles/components/posts/postAuthor.module.css +0 -31
- package/src/styles/components/posts/postCC.module.css +0 -138
- package/src/styles/components/posts/postCard.module.css +0 -167
- package/src/styles/components/posts/postContent.module.css +0 -238
- package/src/styles/components/posts/postLayout.module.css +0 -138
- package/src/styles/components/posts/postList.module.css +0 -25
- package/src/styles/components/posts/postNavigation.module.css +0 -186
- package/src/styles/components/posts/postSidebar.module.css +0 -59
- package/src/styles/components/posts/postTaxonomy.module.css +0 -87
- package/src/styles/components/posts/postToc.module.css +0 -74
- package/src/styles/components/posts/randomPost.module.css +0 -131
- package/src/styles/components/tags/tagHeader.module.css +0 -44
- package/src/styles/components/tags/tagsCloud.module.css +0 -155
- package/src/styles/components/words/wordCard.module.css +0 -136
- package/src/styles/components/words/wordList.module.css +0 -26
- package/src/styles/pages/archives.module.css +0 -22
- package/src/styles/pages/categories.module.css +0 -17
- package/src/styles/pages/home.module.css +0 -61
- package/src/styles/pages/listPage.module.css +0 -16
- package/src/styles/pages/tags.module.css +0 -16
- package/src/styles/pages/words.module.css +0 -16
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ TypeScript uses ESNext. The theme defaults `vite.build.target` to `"esnext"` to
|
|
|
119
119
|
|
|
120
120
|
### Initial CSS and search styles
|
|
121
121
|
|
|
122
|
-
The theme defaults to Astro's `build.inlineStylesheets: "
|
|
122
|
+
The theme defaults to Astro's `build.inlineStylesheets: "never"`: hashed shared CSS can be cached across routes, while component styles load on the pages that use them. Normal blocking stylesheets prevent an unstyled first paint. An explicit consumer setting of `build.inlineStylesheets: "always"` restores inline styles at the cost of larger HTML responses.
|
|
123
123
|
|
|
124
124
|
Pagefind dialog CSS is emitted as a separate hashed static file with a `prefetch` hint. Opening search activates the stylesheet and waits for it before displaying the dialog. It does not block the initial content or depend on JavaScript generating a CSS asset. A `<noscript>` stylesheet fallback is included.
|
|
125
125
|
|
|
@@ -172,7 +172,7 @@ bingClarityId: "YOUR_CLARITY_PROJECT_ID"
|
|
|
172
172
|
|
|
173
173
|
> The Partytown migration in this branch is an unpublished candidate. Representative route measurements show lower TBT, but LCP regresses on the homepage and category page, so performance validation is incomplete. The following describes the candidate implementation.
|
|
174
174
|
|
|
175
|
-
`stalux()` includes Partytown. The Google Analytics, Clarity,
|
|
175
|
+
`stalux()` includes Partytown. The Google Analytics, Clarity, and Umami scripts run in a Web Worker without an additional consumer integration. Page tracking follows `astro:page-load`; browsers with `Element.moveBefore()` preserve the worker during navigation. Vercount loads asynchronously in the main window, avoiding worker startup and DOM bridge delays for visible counters. It runs once after each `astro:page-load` to bind incoming page counters and use the current URL and first-party visitor cookie.
|
|
176
176
|
|
|
177
177
|
For Google Analytics, turn off **Page changes based on browser history events** under **Admin → Data streams → Enhanced measurement → Page views → Advanced settings**. Stalux sets `send_page_view: false` and sends the URL and title for each navigation explicitly. GA's history tracking must also be disabled in the property to prevent duplicate soft-navigation pageviews. Other enhanced measurement options can remain enabled. See [Google's pageview documentation](https://developers.google.com/analytics/devguides/collection/ga4/views).
|
|
178
178
|
|
|
@@ -281,3 +281,7 @@ In Astro 7.3, integration `logger.debug()` uses the official `DEBUG/--verbose` c
|
|
|
281
281
|
Timing is emitted only as logs, never included in generated pages or cache keys. Switching between normal and verbose builds may require one rebuild; repeated builds in the same mode remain deterministic. Consumers running `astro dev --background` can read terminal output with `astro dev logs`.
|
|
282
282
|
|
|
283
283
|
Keep the TypeScript 6 alias for `astro check`, upgrade Vitest and its coverage provider together, and run `bun run validate` before releasing.
|
|
284
|
+
|
|
285
|
+
## Style development and output
|
|
286
|
+
|
|
287
|
+
Stalux precompiles its UnoCSS styles; consuming projects need no UnoCSS dependency or configuration. Shared CSS is a cacheable external stylesheet by default. Article/math, archive, category, tag and quote styles load with their components. Explicit Astro `build.inlineStylesheets: "always"` restores inline output. New utilities in consumer override components require the consumer’s own compiler. See [STYLING.md](./docs/STYLING.md) for maintenance and watch mode.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xingwangzhe/stalux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "A powerful, modern Astro blog theme — use as template or install as plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
"./package.json": "./package.json"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
|
-
"dev": "
|
|
71
|
-
"build": "astro build && node scripts/verify-build.ts",
|
|
70
|
+
"dev": "bun run styles:build && node scripts/dev.ts",
|
|
71
|
+
"build": "bun run styles:build && astro build && node scripts/verify-build.ts",
|
|
72
72
|
"preview": "astro preview",
|
|
73
73
|
"astro": "astro",
|
|
74
74
|
"init": "node scripts/cli.ts init",
|
|
75
75
|
"node:check": "tsc6 --project tsconfig.node.json",
|
|
76
76
|
"build:cli": "bun build scripts/cli.ts --target=node --outfile .release/cli.mjs",
|
|
77
|
-
"prepack": "bun run build:cli",
|
|
77
|
+
"prepack": "bun run styles:build && bun run build:cli",
|
|
78
78
|
"check": "biome check .",
|
|
79
79
|
"check:fix": "biome check --write .",
|
|
80
80
|
"format": "biome format --write .",
|
|
@@ -87,10 +87,12 @@
|
|
|
87
87
|
"test:coverage": "vitest run --coverage",
|
|
88
88
|
"knip": "knip",
|
|
89
89
|
"verify:build": "node scripts/verify-build.ts",
|
|
90
|
-
"validate": "bun run check && bun run node:check && bun run astro:check && bun run knip && bun run test:coverage && bun run build && bun run build:cli",
|
|
90
|
+
"validate": "bun run styles:build && bun run check && bun run node:check && bun run astro:check && bun run knip && bun run test:coverage && bun run build && bun run build:cli",
|
|
91
91
|
"prepare": "git config core.hooksPath scripts/git-hooks",
|
|
92
92
|
"dev:debug": "STALUX_DEBUG=1 astro dev --verbose",
|
|
93
|
-
"build:debug": "STALUX_DEBUG=1 astro build --verbose && node scripts/verify-build.ts"
|
|
93
|
+
"build:debug": "STALUX_DEBUG=1 astro build --verbose && node scripts/verify-build.ts",
|
|
94
|
+
"styles:build": "node scripts/build-styles.ts",
|
|
95
|
+
"styles:watch": "node scripts/build-styles.ts --watch"
|
|
94
96
|
},
|
|
95
97
|
"dependencies": {
|
|
96
98
|
"@astrojs/markdown-satteri": "0.4.2",
|
|
@@ -122,10 +124,12 @@
|
|
|
122
124
|
"@astrojs/check": "0.9.10",
|
|
123
125
|
"@biomejs/biome": "2.5.14",
|
|
124
126
|
"@types/node": "^26.6.2",
|
|
127
|
+
"@unocss/astro": "^66.10.5",
|
|
125
128
|
"@vitest/coverage-v8": "5.0.1",
|
|
126
129
|
"astro": "^7.3.5",
|
|
127
130
|
"knip": "^6.37.0",
|
|
128
131
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
132
|
+
"unocss": "^66.10.5",
|
|
129
133
|
"vite": "8.3.0",
|
|
130
134
|
"vitest": "5.0.1"
|
|
131
135
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
+
import "../../../styles/generated-archives.css";
|
|
2
3
|
import { type CollectionEntry, getCollection } from "astro:content";
|
|
3
|
-
|
|
4
|
+
|
|
4
5
|
import { getSiteData } from "@utils/config-utils";
|
|
5
6
|
import { format, parseDate, toTimestamp } from "@utils/dayjs";
|
|
6
7
|
import { createTranslator } from "@utils/i18n";
|
|
@@ -52,39 +53,44 @@ const archiveYears = [...archivesByYearMonth.entries()]
|
|
|
52
53
|
}));
|
|
53
54
|
---
|
|
54
55
|
|
|
55
|
-
<section class=
|
|
56
|
-
<div class=
|
|
57
|
-
<div class=
|
|
56
|
+
<section class="stalux-archive-container">
|
|
57
|
+
<div class="stalux-archive-page-header">
|
|
58
|
+
<div class="stalux-archive-timeline-container">
|
|
58
59
|
{archiveYears.length > 0 ? (
|
|
59
60
|
archiveYears.map((archiveYear) => (
|
|
60
|
-
<div class=
|
|
61
|
-
<div class=
|
|
62
|
-
<h2 class=
|
|
63
|
-
<div class=
|
|
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">
|
|
64
65
|
{t("archives.postCount", { n: archiveYear.count })}
|
|
65
66
|
</div>
|
|
66
67
|
</div>
|
|
67
68
|
{archiveYear.months.map(({ month, posts: monthPosts }) => (
|
|
68
69
|
<div
|
|
69
|
-
class=
|
|
70
|
-
style={{
|
|
70
|
+
class="stalux-archive-month-section"
|
|
71
|
+
style={{
|
|
72
|
+
"--archive-estimate": `${Math.ceil(monthPosts.length / 12) * 12 * 48 + 40}px`,
|
|
73
|
+
}}
|
|
71
74
|
>
|
|
72
|
-
<h3 class=
|
|
75
|
+
<h3 class="stalux-archive-month-title">{t("archives.month", { n: month })}</h3>
|
|
73
76
|
{Array.from({ length: Math.ceil(monthPosts.length / 12) }, (_, index) =>
|
|
74
77
|
monthPosts.slice(index * 12, (index + 1) * 12),
|
|
75
78
|
).map((group) => (
|
|
76
79
|
<ul
|
|
77
|
-
class=
|
|
80
|
+
class="stalux-archive-post-list"
|
|
78
81
|
style={{ "--archive-group-estimate": `${group.length * 48}px` }}
|
|
79
82
|
>
|
|
80
83
|
{group.map((post) => (
|
|
81
|
-
<li class=
|
|
82
|
-
<time
|
|
84
|
+
<li class="stalux-archive-post-item">
|
|
85
|
+
<time
|
|
86
|
+
class="stalux-archive-post-date"
|
|
87
|
+
datetime={post.data.date}
|
|
88
|
+
>
|
|
83
89
|
{format(parseDate(post.data.date), "yyyy-MM-dd")}
|
|
84
90
|
</time>
|
|
85
91
|
<a
|
|
86
92
|
href={`/posts/${post.data.abbrlink}/`}
|
|
87
|
-
class=
|
|
93
|
+
class="stalux-archive-post-link"
|
|
88
94
|
data-astro-prefetch="viewport"
|
|
89
95
|
>
|
|
90
96
|
{post.data.title}
|
|
@@ -98,7 +104,7 @@ const archiveYears = [...archivesByYearMonth.entries()]
|
|
|
98
104
|
</div>
|
|
99
105
|
))
|
|
100
106
|
) : (
|
|
101
|
-
<div class=
|
|
107
|
+
<div class="stalux-archive-no-posts">{t("archives.noPosts")}</div>
|
|
102
108
|
)}
|
|
103
109
|
</div>
|
|
104
110
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getCollection } from "astro:content";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { getSiteData } from "@utils/config-utils";
|
|
5
5
|
import { createTranslator } from "@utils/i18n";
|
|
6
6
|
|
|
@@ -9,6 +9,6 @@ const siteConfig = getSiteData(configEntries);
|
|
|
9
9
|
const { t } = createTranslator(siteConfig.lang || "zh-CN");
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div id={
|
|
12
|
+
<div id={"stalux-to-archive-archs"}>
|
|
13
13
|
<a href="/archives" data-astro-prefetch>{t("archives.viewAll")}</a>
|
|
14
14
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
+
import "../../../styles/generated-categories.css";
|
|
2
3
|
import { getCollection } from "astro:content";
|
|
3
|
-
|
|
4
|
+
|
|
4
5
|
import { createTranslator } from "@utils/i18n";
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
@@ -19,13 +20,13 @@ const siteConfig = (configEntries.find((e) => e.id === "site")?.data ?? {}) as R
|
|
|
19
20
|
const { t } = createTranslator((siteConfig.lang as string) || "zh-CN");
|
|
20
21
|
---
|
|
21
22
|
|
|
22
|
-
<article class=
|
|
23
|
+
<article class="stalux-category-card">
|
|
23
24
|
<a
|
|
24
25
|
href={`/categories/${props.category.name}/`}
|
|
25
|
-
class=
|
|
26
|
+
class="stalux-categoryheader a-none"
|
|
26
27
|
data-astro-prefetch
|
|
27
28
|
>
|
|
28
|
-
<div class=
|
|
29
|
+
<div class="stalux-category-icon">
|
|
29
30
|
<svg
|
|
30
31
|
aria-hidden="true"
|
|
31
32
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -43,9 +44,9 @@ const { t } = createTranslator((siteConfig.lang as string) || "zh-CN");
|
|
|
43
44
|
></path>
|
|
44
45
|
</svg>
|
|
45
46
|
</div>
|
|
46
|
-
<div class=
|
|
47
|
-
<h2 class=
|
|
48
|
-
<div class=
|
|
47
|
+
<div class="stalux-category-content">
|
|
48
|
+
<h2 class="categoryName">{props.category.name}</h2>
|
|
49
|
+
<div class="categoryCount">
|
|
49
50
|
{t("categories.postCount", { n: props.category.count })}
|
|
50
51
|
</div>
|
|
51
52
|
</div>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
+
import "../../../styles/generated-categories.css";
|
|
2
3
|
import CategoriesCard from "@components/stalux/categories/categoriesCard.astro";
|
|
3
|
-
|
|
4
|
+
|
|
4
5
|
import { getCategoryCountList } from "@utils/collections-stats";
|
|
5
6
|
|
|
6
7
|
const categoryList = await getCategoryCountList(Astro.logger);
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
<ul class=
|
|
10
|
+
<ul class="stalux-categories">
|
|
10
11
|
{categoryList.map((category) => (
|
|
11
12
|
<li>
|
|
12
13
|
<CategoriesCard category={category} />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Image } from "astro:assets";
|
|
3
3
|
import { getCollection } from "astro:content";
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import { getAuthorData } from "@utils/config-utils";
|
|
6
6
|
|
|
7
7
|
const configEntries = await getCollection("config");
|
|
@@ -17,8 +17,8 @@ const isHomePage = Astro.url.pathname === "/";
|
|
|
17
17
|
const navigationHref = isHomePage ? "/about" : "/";
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
<article class=
|
|
21
|
-
<figure class={
|
|
20
|
+
<article class="stalux-author" transition:persist-props>
|
|
21
|
+
<figure class={`stalux-author-figure ${props.iscolum ? "stalux-author-figure-column" : ""}`}>
|
|
22
22
|
<a href={navigationHref} class="a-none" data-astro-prefetch>
|
|
23
23
|
<Image src={authorConfig.avatar} alt={authorConfig.name} width={100} height={100} />
|
|
24
24
|
</a>
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
import styles from "@styles/components/common/date.module.css";
|
|
3
2
|
---
|
|
4
3
|
|
|
5
|
-
<div id={
|
|
6
|
-
<time id={
|
|
7
|
-
<time id={
|
|
4
|
+
<div id={"stalux-date-date-time"} class="date-time" transition:persist-props>
|
|
5
|
+
<time id={"stalux-date-date"} data-ref="date" datetime=""></time>
|
|
6
|
+
<time id={"stalux-date-time"} data-ref="time" datetime=""></time>
|
|
8
7
|
</div>
|
|
9
8
|
|
|
10
9
|
<script is:inline>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getCollection } from "astro:content";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { getTypetextsData } from "@utils/config-utils";
|
|
5
5
|
import Typewriter from "astro-typewriter";
|
|
6
6
|
|
|
@@ -8,4 +8,4 @@ const configEntries = await getCollection("config");
|
|
|
8
8
|
const typetextsConfig = getTypetextsData(configEntries);
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
{typetextsConfig?.items && <Typewriter class=
|
|
11
|
+
{typetextsConfig?.items && <Typewriter class="stalux-typewriter" messages={typetextsConfig?.items} />}
|
|
@@ -22,7 +22,7 @@ function badgeImg(opts: BadgeOptions) {
|
|
|
22
22
|
const height = svg.match(/<svg\b[^>]*\bheight="(\d+)"/)?.[1];
|
|
23
23
|
const dimensions = width && height ? ` width="${width}" height="${height}"` : "";
|
|
24
24
|
// Closed badge groups should not initialize every SVG document during first paint.
|
|
25
|
-
const img = `<img src="${src}" alt="${alt}" class="badge" loading="lazy" decoding="async"${dimensions} />`;
|
|
25
|
+
const img = `<img src="${src}" alt="${alt}" class="stalux-badge" loading="lazy" decoding="async"${dimensions} />`;
|
|
26
26
|
if (opts.href) {
|
|
27
27
|
return `<a href="${opts.href}" target="_blank" rel="${opts.rel ?? "noopener"}">${img}</a>`;
|
|
28
28
|
}
|
|
@@ -31,23 +31,23 @@ function badgeImg(opts: BadgeOptions) {
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
33
|
{badges && badges.length > 0 && (
|
|
34
|
-
<div class="badges-wrapper">
|
|
34
|
+
<div class="stalux-badges-wrapper">
|
|
35
35
|
{badges.map((item: BadgeItem, idx: number) => {
|
|
36
36
|
if (isBadgeGroup(item)) {
|
|
37
37
|
const groupId = `badge-group-${idx}`;
|
|
38
38
|
return (
|
|
39
|
-
<details class="badge-group" id={groupId}>
|
|
40
|
-
<summary class="badge-group-summary">
|
|
41
|
-
<span class="badge-group-arrow">▶</span>
|
|
42
|
-
<span class="badge-group-title">{item.title}</span>
|
|
43
|
-
<span class="badge-group-hint" data-hint="expanded">
|
|
39
|
+
<details class="stalux-badge-group badge-group" id={groupId}>
|
|
40
|
+
<summary class="stalux-badge-group-summary">
|
|
41
|
+
<span class="stalux-badge-group-arrow">▶</span>
|
|
42
|
+
<span class="stalux-badge-group-title">{item.title}</span>
|
|
43
|
+
<span class="stalux-badge-group-hint" data-hint="expanded">
|
|
44
44
|
{t("footer.collapse")}
|
|
45
45
|
</span>
|
|
46
|
-
<span class="badge-group-hint" data-hint="collapsed">
|
|
46
|
+
<span class="stalux-badge-group-hint" data-hint="collapsed">
|
|
47
47
|
{t("footer.expand")}
|
|
48
48
|
</span>
|
|
49
49
|
</summary>
|
|
50
|
-
<div class="badge-group-items badges">
|
|
50
|
+
<div class="stalux-badge-group-items stalux-badges">
|
|
51
51
|
{item.items.map((b) => (
|
|
52
52
|
<Fragment set:html={badgeImg(b)} />
|
|
53
53
|
))}
|
|
@@ -59,91 +59,3 @@ function badgeImg(opts: BadgeOptions) {
|
|
|
59
59
|
})}
|
|
60
60
|
</div>
|
|
61
61
|
)}
|
|
62
|
-
|
|
63
|
-
<style>
|
|
64
|
-
.badges-wrapper {
|
|
65
|
-
display: flex;
|
|
66
|
-
justify-content: center;
|
|
67
|
-
align-items: center;
|
|
68
|
-
flex-wrap: wrap;
|
|
69
|
-
gap: 0.5rem;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* Badge HTML is emitted by set:html, so target it through the scoped wrapper. */
|
|
73
|
-
.badges-wrapper :global(.badge) {
|
|
74
|
-
width: auto;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.badge-group {
|
|
78
|
-
width: 100%;
|
|
79
|
-
border: none;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.badge-group-summary {
|
|
83
|
-
cursor: pointer;
|
|
84
|
-
display: flex;
|
|
85
|
-
justify-content: center;
|
|
86
|
-
align-items: center;
|
|
87
|
-
gap: 0.4rem;
|
|
88
|
-
padding: 0.2rem 0;
|
|
89
|
-
color: var(--white-70p);
|
|
90
|
-
font-size: 0.85rem;
|
|
91
|
-
user-select: none;
|
|
92
|
-
list-style: none;
|
|
93
|
-
transition: color 0.2s;
|
|
94
|
-
}
|
|
95
|
-
.badge-group-summary:hover {
|
|
96
|
-
color: var(--white-70p);
|
|
97
|
-
}
|
|
98
|
-
.badge-group-summary::-webkit-details-marker {
|
|
99
|
-
display: none;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.badge-group-arrow {
|
|
103
|
-
font-size: 0.65rem;
|
|
104
|
-
transition: transform 0.2s;
|
|
105
|
-
display: inline-block;
|
|
106
|
-
}
|
|
107
|
-
.badge-group[open] .badge-group-arrow {
|
|
108
|
-
transform: rotate(90deg);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.badge-group-title {
|
|
112
|
-
color: var(--white-80p);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.badge-group-hint {
|
|
116
|
-
font-size: 0.7rem;
|
|
117
|
-
color: var(--white-70p);
|
|
118
|
-
}
|
|
119
|
-
.badge-group[open] .badge-group-hint[data-hint="collapsed"],
|
|
120
|
-
.badge-group:not([open]) .badge-group-hint[data-hint="expanded"] {
|
|
121
|
-
display: none;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.badge-group-items {
|
|
125
|
-
padding-top: 0.35rem;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.badges {
|
|
129
|
-
display: flex;
|
|
130
|
-
justify-content: center;
|
|
131
|
-
align-items: center;
|
|
132
|
-
flex-wrap: wrap;
|
|
133
|
-
gap: 0.5rem;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.badge {
|
|
137
|
-
height: 20px;
|
|
138
|
-
vertical-align: middle;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
@media (max-width: 768px) {
|
|
142
|
-
.badges {
|
|
143
|
-
gap: 0.3rem;
|
|
144
|
-
}
|
|
145
|
-
.badge {
|
|
146
|
-
height: 18px;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
</style>
|
|
@@ -19,7 +19,7 @@ const showBeian = !!(icp || pubsec);
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
{showBeian && (
|
|
22
|
-
<div class="beian-info">
|
|
22
|
+
<div class="stalux-beian-beian-info">
|
|
23
23
|
{icp && (
|
|
24
24
|
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">
|
|
25
25
|
{icp}
|
|
@@ -30,7 +30,7 @@ const showBeian = !!(icp || pubsec);
|
|
|
30
30
|
href={`http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=${pubsecNumber}`}
|
|
31
31
|
target="_blank"
|
|
32
32
|
rel="noopener noreferrer"
|
|
33
|
-
class="public-security-beian"
|
|
33
|
+
class="stalux-beian-public-security-beian"
|
|
34
34
|
>
|
|
35
35
|
<img
|
|
36
36
|
src="https://beian.mps.gov.cn/img/logo01.dd7ff50e.png"
|
|
@@ -41,45 +41,3 @@ const showBeian = !!(icp || pubsec);
|
|
|
41
41
|
)}
|
|
42
42
|
</div>
|
|
43
43
|
)}
|
|
44
|
-
|
|
45
|
-
<style>
|
|
46
|
-
.beian-info {
|
|
47
|
-
display: flex;
|
|
48
|
-
justify-content: center;
|
|
49
|
-
flex-wrap: wrap;
|
|
50
|
-
gap: 1rem;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.beian-info a {
|
|
54
|
-
color: rgba(255, 255, 255, 0.7);
|
|
55
|
-
text-decoration: none;
|
|
56
|
-
transition: color 0.3s ease;
|
|
57
|
-
font-size: 0.9rem;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.beian-info a:hover {
|
|
61
|
-
color: rgba(255, 255, 255, 0.9);
|
|
62
|
-
text-decoration: none;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.public-security-beian {
|
|
66
|
-
display: inline-flex;
|
|
67
|
-
align-items: center;
|
|
68
|
-
gap: 5px;
|
|
69
|
-
color: rgba(255, 255, 255, 0.7);
|
|
70
|
-
text-decoration: none;
|
|
71
|
-
transition: color 0.3s ease;
|
|
72
|
-
font-size: 0.9rem;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.public-security-beian:hover {
|
|
76
|
-
color: rgba(255, 255, 255, 0.9);
|
|
77
|
-
text-decoration: none;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.public-security-beian img {
|
|
81
|
-
width: 15px;
|
|
82
|
-
height: 15px;
|
|
83
|
-
display: inline-block;
|
|
84
|
-
}
|
|
85
|
-
</style>
|
|
@@ -21,21 +21,6 @@ const copyrightYear =
|
|
|
21
21
|
: currentYear;
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
<small class="copyright">
|
|
24
|
+
<small class="stalux-copyright">
|
|
25
25
|
<span>© {copyrightYear} {props.author || ""}. {t("footer.rightsReserved")}</span>
|
|
26
26
|
</small>
|
|
27
|
-
|
|
28
|
-
<style>
|
|
29
|
-
.copyright {
|
|
30
|
-
color: var(--white-70p);
|
|
31
|
-
font-weight: 500;
|
|
32
|
-
display: flex;
|
|
33
|
-
gap: 0.3em;
|
|
34
|
-
justify-content: center;
|
|
35
|
-
flex-wrap: wrap;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.copyright span {
|
|
39
|
-
margin: 0;
|
|
40
|
-
}
|
|
41
|
-
</style>
|
|
@@ -16,17 +16,17 @@ const { showStats = true, wordCount, buildtime } = Astro.props;
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
{showStats && (
|
|
19
|
-
<p class="site-stats">
|
|
19
|
+
<p class="stalux-stats-site-stats">
|
|
20
20
|
<span id="vercount_container_site_uv">
|
|
21
21
|
{t("footer.visitors")}
|
|
22
22
|
<span id="vercount_value_site_uv">Loading...</span> {t("footer.visits")}
|
|
23
23
|
</span>
|
|
24
|
-
<span class="stats-separator">|</span>
|
|
24
|
+
<span class="stalux-stats-stats-separator">|</span>
|
|
25
25
|
<span id="vercount_container_site_pv">
|
|
26
26
|
{t("footer.totalVisits")}
|
|
27
27
|
<span id="vercount_value_site_pv">Loading...</span> {t("footer.times")}
|
|
28
28
|
</span>
|
|
29
|
-
<span class="stats-separator">|</span>
|
|
29
|
+
<span class="stalux-stats-stats-separator">|</span>
|
|
30
30
|
<span id="word-count-container">
|
|
31
31
|
{t("footer.totalWords")}
|
|
32
32
|
<span id="word-count-value">{wordCount ?? "Loading..."}</span> {t("footer.chars")}
|
|
@@ -36,7 +36,7 @@ const { showStats = true, wordCount, buildtime } = Astro.props;
|
|
|
36
36
|
|
|
37
37
|
{buildtime && (
|
|
38
38
|
<div
|
|
39
|
-
class="site-build-time"
|
|
39
|
+
class="stalux-stats-site-build-time"
|
|
40
40
|
data-stalux-buildtime={buildtime}
|
|
41
41
|
data-stalux-runtime-format={t("footer.runtimeFormat")}
|
|
42
42
|
>
|
|
@@ -46,24 +46,3 @@ const { showStats = true, wordCount, buildtime } = Astro.props;
|
|
|
46
46
|
</span>
|
|
47
47
|
</div>
|
|
48
48
|
)}
|
|
49
|
-
|
|
50
|
-
<style>
|
|
51
|
-
.site-stats {
|
|
52
|
-
display: flex;
|
|
53
|
-
justify-content: center;
|
|
54
|
-
flex-wrap: wrap;
|
|
55
|
-
gap: 0.5rem;
|
|
56
|
-
font-size: 0.9rem;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.stats-separator {
|
|
60
|
-
color: rgba(255, 255, 255, 0.5);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.site-build-time {
|
|
64
|
-
margin-top: 0.5rem;
|
|
65
|
-
font-size: 0.9rem;
|
|
66
|
-
color: rgba(255, 255, 255, 0.8);
|
|
67
|
-
text-align: center;
|
|
68
|
-
}
|
|
69
|
-
</style>
|
|
@@ -9,7 +9,7 @@ const showThemeInfoSection = !!(showPoweredBy || showThemeInfo);
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
{showThemeInfoSection && (
|
|
12
|
-
<div class="theme-info">
|
|
12
|
+
<div class="stalux-theme-info">
|
|
13
13
|
{showPoweredBy && (
|
|
14
14
|
<span>
|
|
15
15
|
Powered by
|
|
@@ -33,30 +33,3 @@ const showThemeInfoSection = !!(showPoweredBy || showThemeInfo);
|
|
|
33
33
|
)}
|
|
34
34
|
</div>
|
|
35
35
|
)}
|
|
36
|
-
|
|
37
|
-
<style>
|
|
38
|
-
.theme-info {
|
|
39
|
-
color: var(--white-70p);
|
|
40
|
-
font-size: 0.85rem;
|
|
41
|
-
display: flex;
|
|
42
|
-
justify-content: center;
|
|
43
|
-
gap: 0.3em;
|
|
44
|
-
flex-wrap: wrap;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.theme-info span {
|
|
48
|
-
margin: 0;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.theme-info a {
|
|
52
|
-
color: rgba(255, 255, 255, 0.8);
|
|
53
|
-
text-decoration: none;
|
|
54
|
-
transition: color 0.3s ease;
|
|
55
|
-
margin: 0 0.2em;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.theme-info a:hover {
|
|
59
|
-
color: rgba(255, 255, 255, 1);
|
|
60
|
-
text-decoration: none;
|
|
61
|
-
}
|
|
62
|
-
</style>
|
|
@@ -5,7 +5,7 @@ import FooterBeian from "@components/stalux/footer/FooterBeian.astro";
|
|
|
5
5
|
import FooterCopyright from "@components/stalux/footer/FooterCopyright.astro";
|
|
6
6
|
import FooterStats from "@components/stalux/footer/FooterStats.astro";
|
|
7
7
|
import FooterThemeInfo from "@components/stalux/footer/FooterThemeInfo.astro";
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
import type { BadgeItem, BadgeOptions } from "@utils/badge-generator";
|
|
10
10
|
import { getAuthorData, getFooterData, getSiteData } from "@utils/config-utils";
|
|
11
11
|
import { formatWordCount, getTotalWordCount } from "@utils/word-count-utils";
|
|
@@ -50,8 +50,8 @@ const totalWordCount = await getTotalWordCount(Astro.logger);
|
|
|
50
50
|
const formattedWordCount = formatWordCount(totalWordCount, siteConfig.lang || "zh-CN");
|
|
51
51
|
---
|
|
52
52
|
|
|
53
|
-
<footer class=
|
|
54
|
-
<div class=
|
|
53
|
+
<footer class="stalux-footer" transition:persist-props>
|
|
54
|
+
<div class="stalux-footer-content">
|
|
55
55
|
<!-- 版权信息 -->
|
|
56
56
|
{footerConfig?.copyright?.enabled && (
|
|
57
57
|
<FooterCopyright author={author} startYear={footerConfig?.copyright?.startYear} />
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { getCollection } from "astro:content";
|
|
3
3
|
import Navs from "@components/stalux/layout/navs.astro";
|
|
4
4
|
import Stalux from "@layouts/Stalux.astro";
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { getSiteData } from "@utils/config-utils";
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
@@ -20,7 +20,7 @@ const siteConfig = getSiteData(configEntries);
|
|
|
20
20
|
<Stalux title={`${title} | ${siteConfig.title}`} description={description}>
|
|
21
21
|
<div style="height: 3em;"></div>
|
|
22
22
|
<Navs />
|
|
23
|
-
<h1 class=
|
|
24
|
-
{subheading && <div class=
|
|
23
|
+
<h1 class="stalux-page-title">{heading}</h1>
|
|
24
|
+
{subheading && <div class="stalux-page-description">{subheading}</div>}
|
|
25
25
|
<slot />
|
|
26
26
|
</Stalux>
|