@xingwangzhe/stalux 1.20.3 → 1.21.1
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.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"description": "A powerful, modern Astro blog theme — use as template or install as plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
"@waline/client": "^3.15.2",
|
|
85
85
|
"@xingwangzhe/satteri-mermaid": "0.7.3",
|
|
86
86
|
"@xingwangzhe/satteri-photoswipe": "^0.2.2",
|
|
87
|
+
"@xingwangzhe/stalux": "1.21.0",
|
|
87
88
|
"@xingwangzhe/tags-cloud": "^1.2.5",
|
|
88
89
|
"animejs": "^4.5.0",
|
|
89
90
|
"astro-expressive-code": "^0.44.1",
|
|
@@ -8,13 +8,21 @@ import BingClarity from "@components/stalux/analytics/clarity.astro";
|
|
|
8
8
|
import "@styles/base/init.css";
|
|
9
9
|
import Umami from "@components/stalux/analytics/umami.astro";
|
|
10
10
|
import { langToOpenGraphLocale } from "@utils/i18n";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getAuthorData,
|
|
13
|
+
getHeadData,
|
|
14
|
+
getMediaLinksData,
|
|
15
|
+
getPromoteData,
|
|
16
|
+
getSiteData,
|
|
17
|
+
} from "@utils/config-utils";
|
|
18
|
+
import { getRouteKind } from "@utils/view-transitions";
|
|
12
19
|
|
|
13
20
|
const configEntries = await getCollection("config");
|
|
14
21
|
const siteConfig = getSiteData(configEntries);
|
|
15
22
|
const authorConfig = getAuthorData(configEntries);
|
|
16
23
|
const headConfig = getHeadData(configEntries);
|
|
17
24
|
const promoteConfig = getPromoteData(configEntries);
|
|
25
|
+
const mediaLinksConfig = getMediaLinksData(configEntries);
|
|
18
26
|
|
|
19
27
|
// Twitter 卡片类型定义
|
|
20
28
|
type TwitterCardType = "summary" | "summary_large_image";
|
|
@@ -34,21 +42,31 @@ interface Props {
|
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
const props = Astro.props as Props;
|
|
37
|
-
const effectiveTitle = props.title;
|
|
45
|
+
const effectiveTitle = siteConfig.seoTitle || props.title;
|
|
38
46
|
const effectiveDescription = props.description;
|
|
39
47
|
const isArticle = props.isArticle ?? false;
|
|
40
48
|
|
|
41
49
|
const canonicalBase = siteConfig.canonical || siteConfig.url;
|
|
50
|
+
const siteUrl = new URL(canonicalBase || Astro.url.origin).href.replace(/\/$/, "");
|
|
51
|
+
const siteName = siteConfig.title || effectiveTitle;
|
|
42
52
|
const canonicalUrl = canonicalBase
|
|
43
|
-
? new URL(Astro.url.pathname, canonicalBase).href
|
|
44
|
-
: Astro.url.href;
|
|
53
|
+
? new URL(Astro.url.pathname, `${canonicalBase.replace(/\/$/, "")}/`).href
|
|
54
|
+
: new URL(Astro.url.pathname, Astro.url).href;
|
|
45
55
|
const faviconPath = siteConfig.favicon || "/favicon.ico";
|
|
46
56
|
// 社交分享图片 / JSON-LD image 必须用绝对 URL
|
|
47
|
-
const baseImgUrl = canonicalBase
|
|
48
|
-
const toAbsolute = (
|
|
57
|
+
const baseImgUrl = canonicalBase?.replace(/\/$/, "") || Astro.url.origin;
|
|
58
|
+
const toAbsolute = (value?: string) => {
|
|
59
|
+
if (!value) return undefined;
|
|
60
|
+
if (/^(?:https?:|data:|\/\/)/i.test(value)) {
|
|
61
|
+
return value.startsWith("//") ? `${Astro.url.protocol}${value}` : value;
|
|
62
|
+
}
|
|
63
|
+
return `${baseImgUrl}/${value.replace(/^\/+/, "")}`;
|
|
64
|
+
};
|
|
49
65
|
const ogImagePath = toAbsolute(props.cover || authorConfig.avatar || faviconPath);
|
|
50
66
|
const isNotFoundPage =
|
|
51
67
|
Astro.url.pathname === "/404" || Astro.url.pathname === "/404/";
|
|
68
|
+
const routeKind = getRouteKind(Astro.url.pathname);
|
|
69
|
+
const isCollectionPage = routeKind.endsWith("-index") || routeKind.endsWith("-detail");
|
|
52
70
|
const resolvedNoindex = Boolean(siteConfig.noindex) || isNotFoundPage || Boolean(props.noindex);
|
|
53
71
|
const resolvedNofollow = Boolean(siteConfig.nofollow) || isNotFoundPage;
|
|
54
72
|
|
|
@@ -62,6 +80,7 @@ const openGraphConfig: Record<string, unknown> = {
|
|
|
62
80
|
optional: {
|
|
63
81
|
description: effectiveDescription,
|
|
64
82
|
locale: langToOpenGraphLocale(siteConfig.lang || "zh-CN"),
|
|
83
|
+
siteName,
|
|
65
84
|
},
|
|
66
85
|
image: {
|
|
67
86
|
url: ogImagePath,
|
|
@@ -123,6 +142,21 @@ const extendedMeta = [
|
|
|
123
142
|
];
|
|
124
143
|
|
|
125
144
|
let schema: Record<string, unknown>;
|
|
145
|
+
const sameAs = mediaLinksConfig?.items
|
|
146
|
+
.map((item) => item.link)
|
|
147
|
+
.filter((link) => /^https?:\/\//i.test(link));
|
|
148
|
+
const authorEntity = {
|
|
149
|
+
"@type": "Person",
|
|
150
|
+
name: authorConfig.name,
|
|
151
|
+
...(toAbsolute(authorConfig.avatar) ? { image: toAbsolute(authorConfig.avatar) } : {}),
|
|
152
|
+
...(sameAs.length ? { sameAs } : {}),
|
|
153
|
+
};
|
|
154
|
+
const publisher = {
|
|
155
|
+
"@type": "Organization",
|
|
156
|
+
name: siteName,
|
|
157
|
+
url: siteUrl,
|
|
158
|
+
...(authorConfig.avatar ? { logo: toAbsolute(authorConfig.avatar) } : {}),
|
|
159
|
+
};
|
|
126
160
|
if (isArticle) {
|
|
127
161
|
schema = {
|
|
128
162
|
"@context": "https://schema.org",
|
|
@@ -130,28 +164,38 @@ if (isArticle) {
|
|
|
130
164
|
headline: effectiveTitle,
|
|
131
165
|
description: effectiveDescription,
|
|
132
166
|
url: canonicalUrl,
|
|
133
|
-
image: ogImagePath,
|
|
134
|
-
datePublished: props.date,
|
|
135
|
-
dateModified: props.updated || props.date,
|
|
136
|
-
keywords: props.tags
|
|
137
|
-
author: props.author
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
name: props.author,
|
|
141
|
-
}
|
|
142
|
-
: undefined,
|
|
167
|
+
...(ogImagePath ? { image: ogImagePath } : {}),
|
|
168
|
+
...(props.date ? { datePublished: props.date } : {}),
|
|
169
|
+
...(props.updated || props.date ? { dateModified: props.updated || props.date } : {}),
|
|
170
|
+
...(props.tags?.length ? { keywords: props.tags.join(", ") } : {}),
|
|
171
|
+
author: props.author ? { ...authorEntity, name: props.author } : authorEntity,
|
|
172
|
+
publisher,
|
|
173
|
+
inLanguage: siteConfig.lang || "zh-CN",
|
|
143
174
|
mainEntityOfPage: {
|
|
144
175
|
"@type": "WebPage",
|
|
145
176
|
"@id": canonicalUrl,
|
|
146
177
|
},
|
|
147
178
|
};
|
|
148
|
-
} else {
|
|
179
|
+
} else if (routeKind === "home") {
|
|
149
180
|
schema = {
|
|
150
181
|
"@context": "https://schema.org",
|
|
151
182
|
"@type": "WebSite",
|
|
152
183
|
url: canonicalUrl,
|
|
153
184
|
name: effectiveTitle,
|
|
154
185
|
description: effectiveDescription,
|
|
186
|
+
inLanguage: siteConfig.lang || "zh-CN",
|
|
187
|
+
publisher,
|
|
188
|
+
author: authorEntity,
|
|
189
|
+
};
|
|
190
|
+
} else {
|
|
191
|
+
schema = {
|
|
192
|
+
"@context": "https://schema.org",
|
|
193
|
+
"@type": isCollectionPage ? "CollectionPage" : routeKind === "about" ? "AboutPage" : "WebPage",
|
|
194
|
+
url: canonicalUrl,
|
|
195
|
+
name: effectiveTitle,
|
|
196
|
+
description: effectiveDescription,
|
|
197
|
+
inLanguage: siteConfig.lang || "zh-CN",
|
|
198
|
+
isPartOf: { "@type": "WebSite", url: siteUrl, name: siteName },
|
|
155
199
|
};
|
|
156
200
|
}
|
|
157
201
|
const ldJson = JSON.stringify(schema, null, 2).replace(/<\//g, "<\\/");
|
package/src/pages/index.astro
CHANGED
|
@@ -21,6 +21,7 @@ import { getSiteData, getAuthorData, getHeadData, getNavsData, getLinksData, get
|
|
|
21
21
|
<div class={styles.homeNavs}>
|
|
22
22
|
<Navs />
|
|
23
23
|
</div>
|
|
24
|
+
<h2 class="sr-only" style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;">关于本站</h2>
|
|
24
25
|
<Author />
|
|
25
26
|
<TextType />
|
|
26
27
|
<DateTime />
|
package/src/schemas/config.ts
CHANGED
|
@@ -16,6 +16,7 @@ export const siteSchema = z.object({
|
|
|
16
16
|
title: z.string().min(1, "site.title is required"),
|
|
17
17
|
url: z.string().url("site.url must be a valid URL"),
|
|
18
18
|
description: z.string().min(1, "site.description is required"),
|
|
19
|
+
seoTitle: z.string().min(1).optional(),
|
|
19
20
|
timezone: z.string().optional().default("Asia/Shanghai"),
|
|
20
21
|
canonical: z.string().url("site.canonical must be a valid URL").optional(),
|
|
21
22
|
twitterSite: z.string().optional(),
|