@xingwangzhe/stalux 1.29.6 → 1.29.7

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 (40) hide show
  1. package/README.md +22 -2
  2. package/package.json +2 -1
  3. package/src/components/stalux/analytics/clarity.astro +1 -1
  4. package/src/components/stalux/analytics/google.astro +1 -1
  5. package/src/components/stalux/analytics/umami.astro +1 -1
  6. package/src/components/stalux/archives/archivesList.astro +27 -17
  7. package/src/components/stalux/categories/categoriesList.astro +2 -2
  8. package/src/components/stalux/common/verCount.astro +1 -1
  9. package/src/components/stalux/footer/FooterBadges.astro +14 -3
  10. package/src/components/stalux/layout/head.astro +8 -4
  11. package/src/components/stalux/links/linkList.astro +1 -1
  12. package/src/components/stalux/tags/tagsCloud.astro +22 -12
  13. package/src/components/stalux/words/wordList.astro +1 -1
  14. package/src/index.ts +15 -3
  15. package/src/layouts/Stalux.astro +0 -5
  16. package/src/scripts/analytics-runtime.ts +166 -0
  17. package/src/scripts/core-runtime.ts +0 -1
  18. package/src/scripts/date-time.ts +9 -5
  19. package/src/scripts/navigation.ts +48 -25
  20. package/src/scripts/runtime-counter.ts +2 -3
  21. package/src/scripts/search-dialog.ts +24 -0
  22. package/src/scripts/tags-cloud.ts +63 -29
  23. package/src/scripts/visible-clock.ts +24 -0
  24. package/src/scripts/waline.ts +1 -1
  25. package/src/styles/components/archives/archivesList.module.css +15 -87
  26. package/src/styles/components/categories/categoriesCard.module.css +3 -8
  27. package/src/styles/components/categories/categoriesList.module.css +7 -8
  28. package/src/styles/components/links/linkCard.module.css +0 -2
  29. package/src/styles/components/links/linkList.module.css +3 -3
  30. package/src/styles/components/posts/postAuthor.module.css +0 -1
  31. package/src/styles/components/posts/postCard.module.css +3 -12
  32. package/src/styles/components/tags/tagHeader.module.css +31 -31
  33. package/src/styles/components/tags/tagsCloud.module.css +34 -50
  34. package/src/utils/content-index.ts +1 -1
  35. package/src/utils/feed.ts +1 -1
  36. package/src/scripts/after-load.ts +0 -27
  37. package/src/scripts/clarity.ts +0 -48
  38. package/src/scripts/google-analytics.ts +0 -90
  39. package/src/scripts/umami.ts +0 -28
  40. package/src/scripts/vercount.ts +0 -38
@@ -1,69 +1,46 @@
1
1
  /* ── 移动端:卡片容器(桌面端隐藏) ── */
2
2
  .cards {
3
+ display: block;
4
+ padding: 1rem;
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ .tagGroup {
3
9
  display: flex;
4
10
  flex-wrap: wrap;
5
11
  gap: 0.75rem;
6
12
  justify-content: center;
7
13
  align-items: flex-start;
8
- align-content: flex-start;
9
- padding: 1rem;
10
- box-sizing: border-box;
14
+ margin-bottom: 0.75rem;
15
+ content-visibility: auto;
16
+ contain-intrinsic-block-size: auto 24rem;
17
+ overflow-clip-margin: 30px;
11
18
  }
12
19
 
13
- @media (min-width: 769px) {
14
- .cards {
15
- display: none;
20
+ @supports not (content-visibility: auto) {
21
+ .tagGroup {
22
+ contain-intrinsic-block-size: auto;
16
23
  }
17
24
  }
18
25
 
19
- @media (max-width: 768px) {
20
- .tagCard {
21
- animation: stalux-tag-arrive 240ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
22
- }
23
-
24
- .tagCard:nth-child(2) {
25
- animation-delay: 30ms;
26
- }
27
-
28
- .tagCard:nth-child(3) {
29
- animation-delay: 60ms;
30
- }
31
-
32
- .tagCard:nth-child(4) {
33
- animation-delay: 90ms;
34
- }
35
-
36
- .tagCard:nth-child(5) {
37
- animation-delay: 120ms;
38
- }
39
-
40
- .tagCard:nth-child(n + 6) {
41
- animation-delay: 150ms;
42
- }
26
+ .canvasFrame {
27
+ container-type: inline-size;
43
28
  }
44
29
 
45
- @keyframes stalux-tag-arrive {
46
- from {
47
- opacity: 0;
48
- transform: translateY(0.5rem);
49
- }
50
-
51
- to {
52
- opacity: 1;
53
- transform: translateY(0);
30
+ @media (min-width: 769px) {
31
+ .cards {
32
+ display: none;
54
33
  }
55
34
  }
56
35
 
57
- @media (prefers-reduced-motion: reduce) {
58
- .tagCard {
59
- animation: none;
60
- }
61
- }
36
+ /* Keep server-rendered tag links visible from the first paint. */
62
37
 
63
38
  /* ── 桌面端:Canvas 容器(移动端隐藏) ── */
64
39
  .canvas {
65
40
  display: none;
66
41
  width: 100%;
42
+ --cloud-base-diameter: 660px;
43
+ height: min(calc(var(--cloud-base-diameter) * var(--cloud-density)), 120cqw);
67
44
  min-height: 520px;
68
45
  position: relative;
69
46
  }
@@ -87,18 +64,14 @@
87
64
  border: 1px solid var(--white-20p);
88
65
  transition:
89
66
  transform var(--transition-slow),
90
- border-color var(--transition-slow),
91
- box-shadow var(--transition-slow);
67
+ border-color var(--transition-slow);
92
68
  overflow: hidden;
93
69
  }
94
70
 
95
71
  .tagCard::before {
96
72
  content: "";
97
73
  position: absolute;
98
- top: 0;
99
- left: 0;
100
- width: 100%;
101
- height: 100%;
74
+ inset: 0;
102
75
  background: linear-gradient(
103
76
  120deg,
104
77
  rgba(255, 255, 255, 0),
@@ -169,3 +142,14 @@
169
142
  padding: 2rem;
170
143
  width: 100%;
171
144
  }
145
+
146
+ @media (min-width: 1024px) {
147
+ .canvas {
148
+ --cloud-base-diameter: 840px;
149
+ }
150
+ }
151
+ @media (min-width: 1440px) {
152
+ .canvas {
153
+ --cloud-base-diameter: 960px;
154
+ }
155
+ }
@@ -94,7 +94,7 @@ function finalizeTaxonomy<T extends IndexablePost>(
94
94
  export function buildPostContentIndex<T extends IndexablePost>(
95
95
  sourcePosts: readonly T[],
96
96
  ): PostContentIndex<T> {
97
- const posts = [...sourcePosts].sort(
97
+ const posts = sourcePosts.toSorted(
98
98
  (left, right) => toTimestamp(right.data.date) - toTimestamp(left.data.date),
99
99
  );
100
100
  const byAbbrlink = new Map<string, T>();
package/src/utils/feed.ts CHANGED
@@ -32,7 +32,7 @@ export async function buildFeedItems(
32
32
  updatedTag: string,
33
33
  logger?: AstroRuntimeLogger,
34
34
  ): Promise<FeedItem[]> {
35
- const sortedPosts = [...posts].sort((a, b) => {
35
+ const sortedPosts = posts.toSorted((a, b) => {
36
36
  // Newest first: compare post dates, use the greater of updated/date
37
37
  const aTime = toTimestamp(a.data.updated || a.data.date);
38
38
  const bTime = toTimestamp(b.data.updated || b.data.date);
@@ -1,27 +0,0 @@
1
- type IdleWindow = Window & {
2
- requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number;
3
- };
4
-
5
- /** Run non-essential work after the initial page load and during an idle period. */
6
- export function afterLoadAndIdle(callback: () => void): void {
7
- let scheduled = false;
8
- const schedule = () => {
9
- if (scheduled) return;
10
- scheduled = true;
11
- const idleWindow = window as IdleWindow;
12
- if (idleWindow.requestIdleCallback) {
13
- idleWindow.requestIdleCallback(callback, { timeout: 2_000 });
14
- } else {
15
- window.setTimeout(callback, 0);
16
- }
17
- };
18
-
19
- if (document.readyState === "complete") {
20
- schedule();
21
- return;
22
- }
23
-
24
- window.addEventListener("load", schedule, { once: true });
25
- // Still load analytics if a third-party resource prevents the load event.
26
- window.setTimeout(schedule, 5_000);
27
- }
@@ -1,48 +0,0 @@
1
- import { afterLoadAndIdle } from "./after-load";
2
- import { createClientLogger } from "./logger";
3
-
4
- const logger = createClientLogger("clarity");
5
-
6
- declare global {
7
- interface Window {
8
- clarity?: ((...args: unknown[]) => void) & { q?: unknown[][] };
9
- __staluxClarityLoaded?: boolean;
10
- __staluxClarityPageLoadListener?: boolean;
11
- }
12
- }
13
-
14
- function load() {
15
- const id = document.body?.dataset.staluxClarityId;
16
- if (!id || window.__staluxClarityLoaded || document.getElementById("stalux-clarity-script"))
17
- return;
18
- afterLoadAndIdle(() => {
19
- if (window.__staluxClarityLoaded || document.getElementById("stalux-clarity-script"))
20
- return;
21
- window.__staluxClarityLoaded = true;
22
- window.clarity =
23
- window.clarity ||
24
- Object.assign((...args: unknown[]) => window.clarity?.q?.push(args), { q: [] });
25
- const script = document.createElement("script");
26
- script.id = "stalux-clarity-script";
27
- script.async = true;
28
- script.src = `https://www.clarity.ms/tag/${encodeURIComponent(id)}`;
29
- script.addEventListener("load", () => logger.debug("external script loaded"), {
30
- once: true,
31
- });
32
- script.addEventListener(
33
- "error",
34
- () => logger.warn("external script failed to load (network or content blocker)"),
35
- { once: true },
36
- );
37
- logger.debug("loading external script after page load and idle time");
38
- document.head.appendChild(script);
39
- });
40
- }
41
-
42
- if (!window.__staluxClarityPageLoadListener) {
43
- window.__staluxClarityPageLoadListener = true;
44
- document.addEventListener("astro:page-load", load);
45
- }
46
- if (document.readyState === "loading")
47
- document.addEventListener("DOMContentLoaded", load, { once: true });
48
- else load();
@@ -1,90 +0,0 @@
1
- import { createClientLogger } from "./logger";
2
-
3
- const logger = createClientLogger("google-analytics");
4
-
5
- declare global {
6
- interface Window {
7
- dataLayer?: unknown[];
8
- gtag?: (...args: unknown[]) => void;
9
- __staluxAnalyticsLoaded?: boolean;
10
- __staluxAnalyticsPageLoadListener?: boolean;
11
- __staluxGoogleScriptLoaded?: boolean;
12
- }
13
- }
14
-
15
- function appendWhenIdle(script: HTMLScriptElement): void {
16
- const append = () => document.head.appendChild(script);
17
- const requestIdle = (
18
- window as Window & {
19
- requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number;
20
- }
21
- ).requestIdleCallback;
22
-
23
- if (requestIdle) requestIdle.call(window, append, { timeout: 1200 });
24
- else window.setTimeout(append, 0);
25
- }
26
-
27
- function appendAfterPageLoad(script: HTMLScriptElement): void {
28
- let appended = false;
29
- const schedule = () => {
30
- if (appended) return;
31
- appended = true;
32
- appendWhenIdle(script);
33
- };
34
-
35
- if (document.readyState === "complete") {
36
- schedule();
37
- return;
38
- }
39
-
40
- window.addEventListener("load", schedule, { once: true });
41
- // Avoid indefinitely delaying analytics if an image or other resource stalls load.
42
- window.setTimeout(schedule, 5000);
43
- }
44
-
45
- function load() {
46
- const gaID = document.body?.dataset.staluxGaId;
47
- if (!gaID) return;
48
- window.dataLayer = window.dataLayer || [];
49
- window.gtag = window.gtag || ((...args: unknown[]) => window.dataLayer?.push(args));
50
- if (!window.__staluxGoogleScriptLoaded) {
51
- window.__staluxGoogleScriptLoaded = true;
52
- const script = document.createElement("script");
53
- script.async = true;
54
- script.fetchPriority = "low";
55
- script.dataset.staluxGoogle = "true";
56
- script.src = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(gaID)}`;
57
- script.addEventListener("load", () => logger.debug("external script loaded"), {
58
- once: true,
59
- });
60
- script.addEventListener(
61
- "error",
62
- () => logger.warn("external script failed to load (network or content blocker)"),
63
- { once: true },
64
- );
65
- logger.debug("deferred external script until page load and idle time");
66
- appendAfterPageLoad(script);
67
- }
68
- if (!window.__staluxAnalyticsLoaded) {
69
- window.__staluxAnalyticsLoaded = true;
70
- window.gtag("js", new Date());
71
- window.gtag("config", gaID);
72
- }
73
- }
74
-
75
- if (!window.__staluxAnalyticsPageLoadListener) {
76
- window.__staluxAnalyticsPageLoadListener = true;
77
- let firstPageLoad = true;
78
- document.addEventListener("astro:page-load", () => {
79
- load();
80
- if (firstPageLoad) {
81
- firstPageLoad = false;
82
- return;
83
- }
84
- window.gtag?.("event", "page_view", { page_path: window.location.pathname });
85
- });
86
- }
87
-
88
- if (document.readyState === "loading")
89
- document.addEventListener("DOMContentLoaded", load, { once: true });
90
- else load();
@@ -1,28 +0,0 @@
1
- import { afterLoadAndIdle } from "./after-load";
2
- import { createClientLogger } from "./logger";
3
-
4
- const logger = createClientLogger("umami");
5
-
6
- const id = document.body?.dataset.staluxUmamiId;
7
- const url = document.body?.dataset.staluxUmamiUrl;
8
-
9
- if (id && url) {
10
- afterLoadAndIdle(() => {
11
- if (document.querySelector("script[data-stalux-umami]")) return;
12
- const script = document.createElement("script");
13
- script.async = true;
14
- script.dataset.staluxUmami = "true";
15
- script.dataset.websiteId = id;
16
- script.src = url;
17
- script.addEventListener("load", () => logger.debug("external script loaded"), {
18
- once: true,
19
- });
20
- script.addEventListener(
21
- "error",
22
- () => logger.warn("external script failed to load (network or content blocker)"),
23
- { once: true },
24
- );
25
- logger.debug("loading external script after page load and idle time");
26
- document.head.appendChild(script);
27
- });
28
- }
@@ -1,38 +0,0 @@
1
- import { afterLoadAndIdle } from "./after-load";
2
- import { createClientLogger } from "./logger";
3
-
4
- const logger = createClientLogger("vercount");
5
-
6
- declare global {
7
- interface Window {
8
- __staluxVerCountLoaded?: boolean;
9
- }
10
- }
11
-
12
- function load() {
13
- if (document.querySelector("script[data-stalux-vercount]")) return;
14
- afterLoadAndIdle(() => {
15
- if (window.__staluxVerCountLoaded || document.querySelector("script[data-stalux-vercount]"))
16
- return;
17
- window.__staluxVerCountLoaded = true;
18
- const script = document.createElement("script");
19
- script.async = true;
20
- script.dataset.staluxVercount = "true";
21
- script.src = "https://events.vercount.one/js";
22
- script.addEventListener("load", () => logger.debug("external script loaded"), {
23
- once: true,
24
- });
25
- script.addEventListener(
26
- "error",
27
- () => logger.warn("external script failed to load (network or content blocker)"),
28
- { once: true },
29
- );
30
- logger.debug("loading external script after page load and idle time");
31
- document.head.appendChild(script);
32
- });
33
- }
34
-
35
- document.addEventListener("astro:page-load", load);
36
- if (document.readyState === "loading")
37
- document.addEventListener("DOMContentLoaded", load, { once: true });
38
- else load();