@xingwangzhe/stalux 1.20.0 → 1.20.2
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 +16 -1
- package/package.json +1 -1
- package/scripts/cli.mjs +7 -12
- package/src/components/stalux/analytics/clarity.astro +4 -3
- package/src/components/stalux/analytics/google.astro +2 -2
- package/src/layouts/Stalux.astro +2 -2
- package/src/scripts/background.ts +42 -20
- package/src/styles/base/init.css +8 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ export default defineConfig({
|
|
|
54
54
|
Create `src/content.config.ts`:
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
|
-
import { defineCollections } from "@xingwangzhe/stalux/schemas";
|
|
57
|
+
import { defineCollections } from "@xingwangzhe/stalux/schemas/collections";
|
|
58
58
|
export const collections = defineCollections({ contentDir: "stalux" });
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -144,6 +144,21 @@ stalux/
|
|
|
144
144
|
└── words/ # Quotes / short notes
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
### Analytics configuration
|
|
148
|
+
|
|
149
|
+
Analytics are configured in `stalux/config/head.yml`, so no template changes are needed:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
id: head
|
|
153
|
+
bingClarityId: "YOUR_CLARITY_PROJECT_ID"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`bingClarityId` is the historical Stalux field name for a Microsoft Clarity Project ID. Get the ID from the Clarity project under **Settings → Setup → Get tracking code**. Stalux injects the asynchronous tracking code into `<head>` and keeps one loader during Astro View Transitions. Do not install the same project again through `anyhead`, a tag manager, or another plugin.
|
|
157
|
+
|
|
158
|
+
The Project ID is a public browser identifier. Never put a Clarity Data Export API token in this YAML or in client-side code. If the site uses a strict CSP, consent banner, or CMP, configure those host-site policies and signals separately; this theme does not make legal compliance decisions for the site.
|
|
159
|
+
|
|
160
|
+
After deployment, verify the script URL contains the exact Project ID and that the browser sends requests to `https://www.clarity.ms/collect`.
|
|
161
|
+
|
|
147
162
|
---
|
|
148
163
|
|
|
149
164
|
## 🛠️ Development Commands
|
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -60,9 +60,10 @@ items:
|
|
|
60
60
|
`,
|
|
61
61
|
"head.yml": `id: head
|
|
62
62
|
# googleAnalyticsId: "G-XXXXXXXXXX"
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
63
|
+
# bingClarityId: "xxxxxxxxxx"
|
|
64
|
+
# umami:
|
|
65
|
+
# id: ""
|
|
66
|
+
# url: ""
|
|
66
67
|
# anyhead: ""
|
|
67
68
|
`,
|
|
68
69
|
"footer.yml": `id: footer
|
|
@@ -91,7 +92,7 @@ badges:
|
|
|
91
92
|
custom: |
|
|
92
93
|
<div id="custom-footer-hook"></div>
|
|
93
94
|
`,
|
|
94
|
-
"media-links.yml": `id:
|
|
95
|
+
"media-links.yml": `id: media-links
|
|
95
96
|
items:
|
|
96
97
|
- icon: "github"
|
|
97
98
|
link: "https://github.com/yourname"
|
|
@@ -102,24 +103,18 @@ description: "Friends & Resources"
|
|
|
102
103
|
sites:
|
|
103
104
|
- name: "Astro"
|
|
104
105
|
description: "The web framework for content-driven websites"
|
|
105
|
-
|
|
106
|
+
link: "https://astro.build"
|
|
106
107
|
icon: "https://astro.build/favicon.svg"
|
|
107
108
|
`,
|
|
108
109
|
"comment.yml": `id: comment
|
|
109
110
|
enabled: false
|
|
110
|
-
waline:
|
|
111
|
-
serverURL: ""
|
|
112
|
-
lang: ""
|
|
113
|
-
locale: ""
|
|
114
|
-
pageSize: 10
|
|
115
|
-
recaptchaV3Key: ""
|
|
116
111
|
`,
|
|
117
112
|
"promote.yml": `id: promote
|
|
118
113
|
export_md: false
|
|
119
114
|
# llm_promote: |
|
|
120
115
|
`,
|
|
121
116
|
"ai-discovery.yml": `id: ai-discovery
|
|
122
|
-
conformance: "
|
|
117
|
+
conformance: "disabled"
|
|
123
118
|
`,
|
|
124
119
|
"typetexts.yml": `id: typetexts
|
|
125
120
|
items:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getCollection } from "astro:content";
|
|
3
|
-
import {
|
|
3
|
+
import { getHeadData } from "@utils/config-utils";
|
|
4
4
|
const configEntries = await getCollection("config");
|
|
5
5
|
const headConfig = getHeadData(configEntries);
|
|
6
|
-
const id = headConfig?.bingClarityId
|
|
6
|
+
const id = headConfig?.bingClarityId;
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<script is:inline data-astro-rerun define:vars={{ id }}>
|
|
10
10
|
// 防止重复初始化
|
|
11
|
-
if (!window.clarity) {
|
|
11
|
+
if (id && !document.getElementById("stalux-clarity-script") && !window.clarity) {
|
|
12
12
|
(function (c, l, a, r, i, t, y) {
|
|
13
13
|
c[a] =
|
|
14
14
|
c[a] ||
|
|
@@ -16,6 +16,7 @@ const id = headConfig?.bingClarityId | undefined;
|
|
|
16
16
|
(c[a].q = c[a].q || []).push(arguments);
|
|
17
17
|
};
|
|
18
18
|
t = l.createElement(r);
|
|
19
|
+
t.id = "stalux-clarity-script";
|
|
19
20
|
t.async = 1;
|
|
20
21
|
t.src = "https://www.clarity.ms/tag/" + i;
|
|
21
22
|
y = l.getElementsByTagName(r)[0];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getCollection } from "astro:content";
|
|
3
|
-
import {
|
|
3
|
+
import { getHeadData } from "@utils/config-utils";
|
|
4
4
|
const configEntries = await getCollection("config");
|
|
5
5
|
const headConfig = getHeadData(configEntries);
|
|
6
|
-
const gaID = headConfig?.googleAnalyticsId
|
|
6
|
+
const gaID = headConfig?.googleAnalyticsId;
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<script
|
package/src/layouts/Stalux.astro
CHANGED
|
@@ -128,8 +128,8 @@ const llmPromote = llmPromoteRaw
|
|
|
128
128
|
data-stalux-bg-index="0"
|
|
129
129
|
>
|
|
130
130
|
{llmPromote && <div style="display:none">{llmPromote}</div>}
|
|
131
|
-
<div class="bg-layer bg-a" style="opacity: 1;" aria-hidden="true"></div>
|
|
132
|
-
<div class="bg-layer bg-b" aria-hidden="true"></div>
|
|
131
|
+
<div class="bg-layer bg-a" style="opacity: 1;" transition:persist aria-hidden="true"></div>
|
|
132
|
+
<div class="bg-layer bg-b" transition:persist aria-hidden="true"></div>
|
|
133
133
|
<main class="stalux-main">
|
|
134
134
|
<slot />
|
|
135
135
|
</main>
|
|
@@ -38,27 +38,49 @@ function setLayerOpacity(layer: "a" | "b", opacity: number): void {
|
|
|
38
38
|
if (el) el.style.opacity = String(opacity);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
function getActiveLayer(): "a" | "b" {
|
|
42
|
+
const aOpacity = Number(getLayerEl("a")?.style.opacity ?? 0);
|
|
43
|
+
const bOpacity = Number(getLayerEl("b")?.style.opacity ?? 0);
|
|
44
|
+
return bOpacity > aOpacity ? "b" : "a";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function pickBackgroundIndex(previous: number): number {
|
|
48
|
+
if (backgroundImages.length < 2) return 0;
|
|
49
|
+
let index = Math.floor(Math.random() * backgroundImages.length);
|
|
50
|
+
while (index === previous) {
|
|
51
|
+
index = Math.floor(Math.random() * backgroundImages.length);
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
return index;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function crossfadeBackground(): void {
|
|
57
|
+
if (backgroundImages.length === 0) return;
|
|
58
|
+
|
|
59
|
+
const activeLayer = getActiveLayer();
|
|
60
|
+
const nextLayer: "a" | "b" = activeLayer === "a" ? "b" : "a";
|
|
61
|
+
const previousIndex = Number(document.body.dataset.staluxBgIndex ?? -1);
|
|
62
|
+
const index = pickBackgroundIndex(previousIndex);
|
|
63
|
+
const next = getLayerEl(nextLayer);
|
|
64
|
+
if (!next || !backgroundImages[index]) return;
|
|
65
|
+
|
|
66
|
+
next.style.backgroundImage = `url('${backgroundImages[index]}')`;
|
|
67
|
+
setLayerOpacity(nextLayer, 1);
|
|
68
|
+
setLayerOpacity(activeLayer, 0);
|
|
51
69
|
document.body.dataset.staluxBgIndex = String(index);
|
|
52
|
-
document.body.dataset.staluxBgLayer =
|
|
70
|
+
document.body.dataset.staluxBgLayer = nextLayer;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function initializeBackground(): void {
|
|
74
|
+
const active = getLayerEl(getActiveLayer());
|
|
75
|
+
if (active?.style.backgroundImage) return;
|
|
76
|
+
crossfadeBackground();
|
|
53
77
|
}
|
|
54
78
|
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// 不能再用它判断“服务端已渲染正确背景”,否则随机逻辑永不执行。
|
|
64
|
-
document.addEventListener("astro:page-load", applyBackground);
|
|
79
|
+
// before-swap 在 View Transition 的快照之后、DOM 替换之前触发;背景层使用
|
|
80
|
+
// transition:persist 保留,因此可以在页面内容交换期间完成双层 crossfade。
|
|
81
|
+
// 非 VT 浏览器也会触发该生命周期,fallback 同样保持平滑。
|
|
82
|
+
if (!(window as Window & { __STALUX_BG_LISTENER__?: boolean }).__STALUX_BG_LISTENER__) {
|
|
83
|
+
(window as Window & { __STALUX_BG_LISTENER__?: boolean }).__STALUX_BG_LISTENER__ = true;
|
|
84
|
+
document.addEventListener("astro:before-swap", crossfadeBackground);
|
|
85
|
+
document.addEventListener("astro:page-load", initializeBackground);
|
|
86
|
+
}
|
package/src/styles/base/init.css
CHANGED
|
@@ -263,7 +263,7 @@ ul {
|
|
|
263
263
|
background: #2a2a2a;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
-
/* 背景层 -
|
|
266
|
+
/* 背景层 - 双层随机背景,在路由切换时交叉淡入淡出 */
|
|
267
267
|
.bg-layer {
|
|
268
268
|
position: fixed;
|
|
269
269
|
inset: 0;
|
|
@@ -275,12 +275,19 @@ ul {
|
|
|
275
275
|
filter: var(--stalux-bg-filter, none);
|
|
276
276
|
pointer-events: none;
|
|
277
277
|
opacity: 0;
|
|
278
|
+
transition: opacity 650ms ease-in-out;
|
|
278
279
|
/* 禁止浏览器强制色彩模式(高对比度/暗黑模式)调整背景图颜色 */
|
|
279
280
|
forced-color-adjust: none;
|
|
280
281
|
/* 关键:防止 Safari/WebKit 在暗色模式下自动调整 SVG 背景图颜色 */
|
|
281
282
|
color-scheme: only light;
|
|
282
283
|
}
|
|
283
284
|
|
|
285
|
+
@media (prefers-reduced-motion: reduce) {
|
|
286
|
+
.bg-layer {
|
|
287
|
+
transition-duration: 0ms;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
284
291
|
/* footer 基础样式,保证页脚始终可见且不覆盖内容 */
|
|
285
292
|
footer {
|
|
286
293
|
padding: var(--space-lg) var(--space-md);
|