@xingwangzhe/stalux 1.42.0 → 1.43.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.
Files changed (36) hide show
  1. package/README.md +5 -5
  2. package/package.json +7 -1
  3. package/src/components/stalux/archives/archivesList.astro +0 -2
  4. package/src/components/stalux/archives/toArchive.astro +1 -5
  5. package/src/components/stalux/common/Typewriter.astro +1 -7
  6. package/src/components/stalux/common/author.astro +1 -6
  7. package/src/components/stalux/common/date.astro +1 -11
  8. package/src/components/stalux/layout/PageHeading.astro +2 -11
  9. package/src/components/stalux/layout/footer.astro +1 -6
  10. package/src/components/stalux/layout/head.astro +0 -2
  11. package/src/components/stalux/links/socialMedia.astro +1 -10
  12. package/src/components/stalux/posts/ArticleSummary.astro +2 -8
  13. package/src/components/stalux/posts/PostTaxonomy.astro +3 -14
  14. package/src/components/stalux/posts/postCC.astro +2 -2
  15. package/src/components/stalux/posts/postCard.astro +1 -5
  16. package/src/components/stalux/posts/postContent.astro +4 -23
  17. package/src/components/stalux/posts/postLeft.astro +4 -22
  18. package/src/components/stalux/posts/postRight.astro +5 -27
  19. package/src/components/stalux/posts/postToc.astro +3 -10
  20. package/src/components/stalux/posts/randomPost.astro +0 -1
  21. package/src/components/stalux/tags/tagHeader.astro +1 -5
  22. package/src/index.ts +20 -1
  23. package/src/internal/style-names.generated.ts +59 -69
  24. package/src/layouts/PostLayout.astro +1 -5
  25. package/src/layouts/Stalux.astro +3 -19
  26. package/src/pages/index.astro +1 -5
  27. package/src/scripts/navigation-client.ts +13 -0
  28. package/src/scripts/navigation-scripts.ts +191 -0
  29. package/src/scripts/route-motion.ts +78 -11
  30. package/src/scripts/swup-router.ts +366 -0
  31. package/src/scripts/tags-cloud.ts +1 -1
  32. package/src/scripts/view-transitions.ts +3 -233
  33. package/src/scripts/word-list.ts +9 -3
  34. package/src/styles/generated.css +1 -1
  35. package/src/styles/motion.css +2 -211
  36. package/src/scripts/archive-reveal.ts +0 -76
package/README.md CHANGED
@@ -18,9 +18,9 @@ Standalone images written as `![Image description](url)` receive a `figure` and
18
18
 
19
19
  Code blocks default to the single `dark-plus` theme, with system color-scheme switching and theme selectors disabled. To opt into another theme or switching behavior, explicitly override `themes`, `useDarkModeMediaQuery`, and `themeCssSelector` through `expressiveCode`. This only changes generated code styles and adds no telemetry.
20
20
 
21
- Route changes use native CSS View Transitions with CSS animations on the reading and list content; sidebars, navigation, footer and background remain stationary. The policy covers every theme route category: previous/next articles slide horizontally in opposite directions, home and information pages use gentle perspective turns, words use a small rotation, and taxonomy details enter vertically. Desktop and mobile both retain spatial motion: article-to-article switching lasts 260ms, while other route animations take 100–180ms. History traversal uses a shorter, smaller directional slide while Astro restores the reading position. Reduced motion, browser-provided history gestures and same-page anchors add no visible VT animation. Standalone HTML keeps native navigation. See the [1.41.0 transition policy and performance boundaries](https://github.com/xingwangzhe/stalux/blob/v1.41.0/docs/view-transitions-1.41.0.md).
21
+ Swup owns soft navigation and transition timing. Astro renders the static documents; the browser runtime replaces only `main[data-stalux-route]`, keeping the header, footer, scroll sentinel and two background layers alive. The incoming visible heading receives a brief opacity or directional hint selected by the route policy: entering an article can move 6px vertically, explicit previous/next article links use opposite 8px horizontal hints, and returning to a list uses a 4px upward hint. Other article links and taxonomy changes fade without inventing a reading direction. Desktop effects last 80–140ms; phones use an 80ms fade without translation. The article body and long lists stay immediately readable. Reduced motion and browser-provided history gestures skip content motion; same-page anchors use their scrolling behavior and same-URL clicks preserve the reading position. Standalone HTML and exported data use document navigation. See the [Swup transition architecture and route policy](docs/view-transitions-swup.md).
22
22
 
23
- The sticky header stays at the top while the body grows with long content; the persisted header and footer stay in place during navigation. Text is immediately clear, and the incoming heading is measured once after Astro swaps the document and restores scrolling. Astro continues to own document/font preparation, history, scrolling and page-script lifecycle. Shared motion state settles when the native transition finishes or is canceled. CSS animation duration is reported separately from total navigation time, which includes networking, layout and browser settlement.
23
+ The runtime uses Swup's Head, Accessibility, Preload, Scroll and JS plugins with Stalux lifecycle handlers. It waits for incoming stylesheets and gives the destination font a bounded 150ms head start, disposes old interactions before replacement, loads first-seen page scripts, then dispatches the Astro-compatible page lifecycle events used by comments, counters, tag clouds and WebMCP. Backgrounds decode independently and crossfade after the content animation finishes; stale navigation work cannot replace the current background. History positions are restored by the Swup runtime, including reduced-motion visits. This requires no new configuration or telemetry. Animation duration describes the effect itself, not total navigation time or a measured performance improvement.
24
24
 
25
25
  ---
26
26
 
@@ -136,7 +136,7 @@ Processed pages are cached under `node_modules/.astro/stalux-page-output/`. The
136
136
 
137
137
  ### Visibility-aware loading and updates
138
138
 
139
- 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.
139
+ 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 the same Swup navigation as ordinary internal links. 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.
140
140
 
141
141
  ### Modern JavaScript
142
142
 
@@ -195,7 +195,7 @@ id: head
195
195
  bingClarityId: "YOUR_CLARITY_PROJECT_ID"
196
196
  ```
197
197
 
198
- Google Analytics, Clarity, and Umami use low-priority native asynchronous scripts. Each SDK loads once per session, and failures do not block reading or navigation. Vercount rebinds visible counters after each `astro:page-load`. GA captures each URL, title, and referrer, then sends pageviews in visit order through separate background tasks after the native transition releases rendering, the content animation is installed and a paint has been yielded. A bounded timer handles task starvation; hiding or leaving the document flushes pending views immediately. The SDK still runs on the main thread; this scheduling reduces synchronous work on the route's first frame. Umami disables automatic pageviews while retaining click tracking and captures page information before the SDK resolves so rapid navigation cannot mix visits. An existing older runtime or legacy Partytown session performs one full reload when it encounters the new runtime to prevent duplicate listeners and tracking.
198
+ Google Analytics, Clarity, and Umami use low-priority native asynchronous scripts. Each SDK loads once per session, and failures do not block reading or navigation. Vercount rebinds visible counters after each `astro:page-load`. GA captures each URL, title, and referrer, then sends pageviews in visit order through separate background tasks after the shared Swup content-motion gate settles and a paint has been yielded. A bounded timer handles task starvation; hiding or leaving the document flushes pending views immediately. The SDK still runs on the main thread; this scheduling reduces synchronous work on the route's first frame. Umami disables automatic pageviews while retaining click tracking and captures page information before the SDK resolves so rapid navigation cannot mix visits. An existing older runtime or legacy Partytown session performs one full reload when it encounters the new runtime to prevent duplicate listeners and tracking.
199
199
 
200
200
  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).
201
201
 
@@ -284,7 +284,7 @@ This is a build-time metadata field. It does not create a contact endpoint or ex
284
284
 
285
285
  The root reserves scrollbar space and uses explicit line height. The homepage typewriter reserves the maximum wrapped height of its complete messages and keeps the text origin fixed; clocks reserve line boxes and use tabular digits. Existing typing, cursor and route animations remain enabled. No additional configuration is required.
286
286
 
287
- A wrapper around Astro ClientRouter's `astro:before-preparation` loader warms the destination body font before the DOM swap without installing it on the old page. It waits at most one second; failures, timeout and superseding navigation do not block the route. Initial loads on slow networks may still show the system fallback. Content authors must reserve dimensions for remote images and third-party embeds. Reduced-motion and print behavior remain supported.
287
+ Swup's pre-replacement preparation warms the destination body font without installing it on the old page. The font receives at most 150ms of preparation time; failure, timeout and superseding navigation release that font wait. Incoming stylesheets and first-seen page modules have separate bounded loading waits so the next page can initialize its interactions. Initial loads on slow networks may still show the system fallback. Content authors must reserve dimensions for remote images and third-party embeds. Reduced-motion and print behavior remain supported.
288
288
 
289
289
  See [style maintenance](docs/STYLING.md) and [lifecycle and static interfaces](docs/RUNTIME.md). Astro development documentation is available through the [official MCP endpoint](https://mcp.docs.astro.build/mcp); `.codex/config.toml`, `.mcp.json` and `AGENTS.md` record the project setup. This development MCP is separate from the blog's browser WebMCP tools.
290
290
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.42.0",
3
+ "version": "1.43.0",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -110,6 +110,11 @@
110
110
  "@mcp-b/webmcp-polyfill": "^5.1.0",
111
111
  "@microsoft/clarity": "1.0.2",
112
112
  "@pagefind/component-ui": "^1.5.2",
113
+ "@swup/a11y-plugin": "^5.2.1",
114
+ "@swup/head-plugin": "^2.3.1",
115
+ "@swup/js-plugin": "^3.2.0",
116
+ "@swup/preload-plugin": "^3.2.12",
117
+ "@swup/scroll-plugin": "^4.0.0",
113
118
  "@takumi-rs/core": "2.17.1",
114
119
  "@waline/client": "^3.16.1",
115
120
  "@xingwangzhe/cjk-font-split-native": "^0.4.10",
@@ -127,6 +132,7 @@
127
132
  "photoswipe": "^5.4.4",
128
133
  "satteri": "^0.10.5",
129
134
  "simple-icons": "^16.35.0",
135
+ "swup": "4.10.0",
130
136
  "temml": "^0.14.0",
131
137
  "yaml": "^2.9.1"
132
138
  },
@@ -127,9 +127,7 @@ const archiveYears = [...archivesByYearMonth.entries()]
127
127
 
128
128
  <script>
129
129
  import { mountArchiveDescriptions } from "../../../scripts/archive-descriptions";
130
- import { mountArchiveReveal } from "../../../scripts/archive-reveal";
131
130
  import { registerPageLifecycle } from "../../../scripts/page-runtime";
132
131
 
133
- registerPageLifecycle("archive-reveal", mountArchiveReveal);
134
132
  registerPageLifecycle("archive-descriptions", mountArchiveDescriptions);
135
133
  </script>
@@ -9,10 +9,6 @@ const siteConfig = getSiteData(configEntries);
9
9
  const { t } = createTranslator(siteConfig.lang || "zh-CN");
10
10
  ---
11
11
 
12
- <div
13
- id={"stalux-to-archive-archs"}
14
- transition:name="stalux-home-archive-link"
15
- transition:animate="slide"
16
- >
12
+ <div id={"stalux-to-archive-archs"}>
17
13
  <a href="/archives" data-astro-prefetch>{t("archives.viewAll")}</a>
18
14
  </div>
@@ -10,13 +10,7 @@ const texts = normalizeMessages(messages);
10
10
  ---
11
11
 
12
12
  {texts.length > 0 && (
13
- <div
14
- class={className}
15
- data-stalux-typewriter
16
- data-messages={JSON.stringify(texts)}
17
- transition:name="stalux-home-typewriter"
18
- transition:animate="fade"
19
- >
13
+ <div class={className} data-stalux-typewriter data-messages={JSON.stringify(texts)}>
20
14
  <span class="stalux-typewriter-accessible">{texts.join(", ")}</span>
21
15
  <span class="stalux-typewriter-reserve" aria-hidden="true">
22
16
  {texts.map((text) => (
@@ -17,12 +17,7 @@ const isHomePage = Astro.url.pathname === "/";
17
17
  const navigationHref = isHomePage ? "/about" : "/";
18
18
  ---
19
19
 
20
- <article
21
- class="stalux-author stalux-u-flex stalux-u-justify-center stalux-u-flex-col"
22
- transition:persist-props
23
- transition:name={isHomePage ? "stalux-home-author" : undefined}
24
- transition:animate={isHomePage ? "fade" : undefined}
25
- >
20
+ <article class="stalux-author stalux-u-flex stalux-u-justify-center stalux-u-flex-col">
26
21
  <figure
27
22
  class={`stalux-author-figure ${props.iscolum ? "stalux-author-figure-column stalux-u-flex-col" : ""}`}
28
23
  >
@@ -1,14 +1,4 @@
1
- ---
2
- const isHomePage = Astro.url.pathname === "/";
3
- ---
4
-
5
- <div
6
- id={"stalux-date-date-time"}
7
- class="date-time"
8
- transition:persist-props
9
- transition:name={isHomePage ? "stalux-home-date-time" : undefined}
10
- transition:animate={isHomePage ? "fade" : undefined}
11
- >
1
+ <div id={"stalux-date-date-time"} class="date-time">
12
2
  <time id={"stalux-date-date"} data-ref="date" datetime=""></time>
13
3
  <time id={"stalux-date-time"} data-ref="time" datetime=""></time>
14
4
  </div>
@@ -8,20 +8,11 @@ const { heading, description } = Astro.props;
8
8
  ---
9
9
 
10
10
  <>
11
- <h1
12
- class="stalux-page-title stalux-u-text-center"
13
- data-stalux-motion-focus
14
- transition:animate="none"
15
- >
11
+ <h1 class="stalux-page-title stalux-u-text-center" data-stalux-motion-focus>
16
12
  {heading}
17
13
  </h1>
18
14
  {description && (
19
- <div
20
- class="stalux-page-description stalux-u-text-center"
21
- data-stalux-motion-content
22
- transition:name="stalux-page-description"
23
- transition:animate="none"
24
- >
15
+ <div class="stalux-page-description stalux-u-text-center" data-stalux-motion-content>
25
16
  {description}
26
17
  </div>
27
18
  )}
@@ -51,12 +51,7 @@ const totalWordCount = await getTotalWordCount(Astro.logger);
51
51
  const formattedWordCount = formatWordCount(totalWordCount, siteConfig.lang || "zh-CN");
52
52
  ---
53
53
 
54
- <footer
55
- class="stalux-footer stalux-u-w-full stalux-u-text-center"
56
- data-stalux-font-group="footer"
57
- transition:persist="stalux-site-footer"
58
- transition:persist-props
59
- >
54
+ <footer class="stalux-footer stalux-u-w-full stalux-u-text-center" data-stalux-font-group="footer">
60
55
  <div class="stalux-footer-content stalux-u-flex stalux-u-flex-col">
61
56
  <!-- 版权信息 -->
62
57
  {footerConfig?.copyright?.enabled && (
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  import { Font } from "astro:assets";
3
3
  import { getCollection } from "astro:content";
4
- import { ClientRouter } from "astro:transitions";
5
4
  // Emit a stable asset even while the search component JavaScript stays lazy.
6
5
  // The closed search dialog does not need to block the page's first paint.
7
6
  import pagefindStyles from "virtual:stalux-search-style";
@@ -54,7 +53,6 @@ const ldJson = JSON.stringify(seo.schema).replace(/<\//g, "<\\/");
54
53
 
55
54
  <head>
56
55
  <meta charset="utf-8">
57
- <ClientRouter fallback="swap" />
58
56
  <SEO
59
57
  title={seo.title}
60
58
  description={seo.description}
@@ -17,8 +17,6 @@ import {
17
17
  const configEntries = await getCollection("config");
18
18
  const mediaLinksSection = getMediaLinksData(configEntries);
19
19
  const mediaLinks = mediaLinksSection?.items ?? [];
20
- const isPostPage = Astro.url.pathname.startsWith("/posts/");
21
- const isHomePage = Astro.url.pathname === "/";
22
20
 
23
21
  // 静态图标映射表:新增图标时只需添加对应的 simple-icons 导入和映射
24
22
  const iconMap: Record<string, SimpleIcon> = {
@@ -35,14 +33,7 @@ function getIconByTitle(iconName: string): SimpleIcon | undefined {
35
33
  }
36
34
  ---
37
35
 
38
- <nav
39
- class="stalux-social"
40
- transition:persist-props
41
- transition:name={isHomePage ? "stalux-home-social" : undefined}
42
- transition:animate={isHomePage ? "fade" : undefined}
43
- aria-label="Social media"
44
- data-stalux-social-animate={String(!isPostPage)}
45
- >
36
+ <nav class="stalux-social" aria-label="Social media">
46
37
  <ul>
47
38
  {mediaLinks.map((item) => {
48
39
  const icon = item.icon ? getIconByTitle(item.icon) : undefined;
@@ -4,18 +4,12 @@ interface Props {
4
4
  label: string;
5
5
  transitionName: string;
6
6
  }
7
- const { description, label, transitionName } = Astro.props;
7
+ const { description, label } = Astro.props;
8
8
  const summary = description?.trim();
9
9
  ---
10
10
 
11
11
  {summary && (
12
- <aside
13
- class="stalux-article-summary"
14
- data-stalux-motion-content
15
- aria-label={label}
16
- transition:name={transitionName}
17
- transition:animate="none"
18
- >
12
+ <aside class="stalux-article-summary" data-stalux-motion-content aria-label={label}>
19
13
  <p class="stalux-article-summary-label">{label}</p>
20
14
  <p class="stalux-article-summary-text">{summary}</p>
21
15
  </aside>
@@ -43,15 +43,10 @@ const cfg = {
43
43
  }[kind];
44
44
  ---
45
45
 
46
- <nav
47
- class="stalux-post-taxonomy-container"
48
- transition:name={cfg.containerName}
49
- transition:animate="none"
50
- aria-label={title ?? cfg.heading}
51
- >
46
+ <nav class="stalux-post-taxonomy-container" aria-label={title ?? cfg.heading}>
52
47
  <h3 class="stalux-post-taxonomy-title">{title ?? cfg.heading}</h3>
53
48
  {items.length > 0 ? (
54
- <div class={cfg.listClass} transition:name={cfg.contentName} transition:animate="fade">
49
+ <div class={cfg.listClass}>
55
50
  {items.map((item) => (
56
51
  <a
57
52
  href={`${cfg.prefix}${item}/`}
@@ -63,12 +58,6 @@ const cfg = {
63
58
  ))}
64
59
  </div>
65
60
  ) : (
66
- <div
67
- class="stalux-post-taxonomy-empty"
68
- transition:name={cfg.contentName}
69
- transition:animate="fade"
70
- >
71
- {cfg.empty}
72
- </div>
61
+ <div class="stalux-post-taxonomy-empty">{cfg.empty}</div>
73
62
  )}
74
63
  </nav>
@@ -20,13 +20,13 @@ const siteConfig = (configEntries.find((e) => e.id === "site")?.data ?? {}) as R
20
20
  unknown
21
21
  >;
22
22
  const { t } = createTranslator((siteConfig.lang as string) || "zh-CN");
23
- const { title, author, url, cc = "CC-BY-NC-SA-4.0", transitionName } = Astro.props;
23
+ const { title, author, url, cc = "CC-BY-NC-SA-4.0" } = Astro.props;
24
24
 
25
25
  const licenseLink = buildCCLink(cc);
26
26
  const licenseName = buildCCName(cc, t);
27
27
  ---
28
28
 
29
- <div class="stalux-license-box" transition:name={transitionName} transition:animate="none">
29
+ <div class="stalux-license-box">
30
30
  <div class="stalux-license-content">
31
31
  <p class="stalux-license-title">{title}</p>
32
32
  <p class="stalux-license-author">{t("post.author")}{author}</p>
@@ -4,7 +4,6 @@ import { getCollection } from "astro:content";
4
4
 
5
5
  import { getSiteData } from "@utils/config-utils";
6
6
  import { toMachineDateTime } from "@utils/semantic-time";
7
- import { getPostTitleTransitionName } from "@utils/view-transitions";
8
7
 
9
8
  interface Props {
10
9
  post: CollectionEntry<"posts">;
@@ -42,10 +41,7 @@ const description = post.data.desc || "";
42
41
  </div>
43
42
  </a>
44
43
  )}
45
- <h2
46
- class="stalux-card-post-title"
47
- transition:name={priority ? getPostTitleTransitionName(post.data.abbrlink) : undefined}
48
- >
44
+ <h2 class="stalux-card-post-title">
49
45
  <a href={`/posts/${post.data.abbrlink}/`} class="a-none" data-astro-prefetch="viewport">
50
46
  {post.data.title}
51
47
  </a>
@@ -38,26 +38,13 @@ const exportMd = Boolean(promoteConfig?.export_md) && !isAboutPage;
38
38
  const mdSourceUrl = exportMd ? `${Astro.url.pathname.replace(/\/$/, "")}.md` : "";
39
39
  ---
40
40
 
41
- <article
42
- class="stalux-article"
43
- data-stalux-gallery={props.hasImage ? "true" : undefined}
44
- transition:name={props.transitionName ?? "stalux-article-container"}
45
- transition:animate="none"
46
- >
41
+ <article class="stalux-article" data-stalux-gallery={props.hasImage ? "true" : undefined}>
47
42
  <!-- Article Header -->
48
- <header
49
- class="stalux-post-article-header"
50
- transition:name={`${transitionPrefix}-header`}
51
- transition:animate="fade"
52
- >
43
+ <header class="stalux-post-article-header">
53
44
  <h1 class="stalux-post-title" data-stalux-motion-focus>
54
45
  {props.title}
55
46
  </h1>
56
- <div
57
- class="stalux-post-metadata"
58
- transition:name={`${transitionPrefix}-metadata`}
59
- transition:animate="none"
60
- >
47
+ <div class="stalux-post-metadata">
61
48
  {props.date && (
62
49
  <time
63
50
  class="stalux-post-meta-item"
@@ -78,11 +65,7 @@ const mdSourceUrl = exportMd ? `${Astro.url.pathname.replace(/\/$/, "")}.md` : "
78
65
  </time>
79
66
  )}
80
67
  </div>
81
- <div
82
- class="stalux-post-page-stats"
83
- transition:name={`${transitionPrefix}-stats`}
84
- transition:animate="none"
85
- >
68
+ <div class="stalux-post-page-stats">
86
69
  {(props.readingMinutes ?? 0) > 0 && (
87
70
  <span class="stalux-post-reading-time">
88
71
  {t("post.readingTime")}
@@ -131,8 +114,6 @@ const mdSourceUrl = exportMd ? `${Astro.url.pathname.replace(/\/$/, "")}.md` : "
131
114
  data-pagefind-body
132
115
  data-stalux-post-id={props.postId === undefined ? undefined : String(props.postId)}
133
116
  data-pagefind-filter={props.postId === undefined ? undefined : "post[data-stalux-post-id]"}
134
- transition:name={`${transitionPrefix}-body`}
135
- transition:animate="none"
136
117
  >
137
118
  <slot />
138
119
  </section>
@@ -3,34 +3,16 @@ import "../../../styles/generated-article.css";
3
3
  import SocialMedia from "@components/stalux/links/socialMedia.astro";
4
4
  import PostAuthor from "@components/stalux/posts/postAuthor.astro";
5
5
  import RandomPost from "@components/stalux/posts/randomPost.astro";
6
-
7
- import { getSidebarAnimation } from "@utils/view-transitions";
8
6
  ---
9
7
 
10
- <aside
11
- class="stalux-sidebar"
12
- transition:name="left-sidebar"
13
- transition:animate={getSidebarAnimation("left")}
14
- >
15
- <div
16
- class="stalux-sidebar-container"
17
- transition:name="stalux-article-left-author"
18
- transition:animate="fade"
19
- >
8
+ <aside class="stalux-sidebar">
9
+ <div class="stalux-sidebar-container">
20
10
  <PostAuthor />
21
11
  </div>
22
- <div
23
- class="stalux-sidebar-container"
24
- transition:name="stalux-article-left-social"
25
- transition:animate="fade"
26
- >
12
+ <div class="stalux-sidebar-container">
27
13
  <SocialMedia />
28
14
  </div>
29
- <div
30
- class="stalux-sidebar-container"
31
- transition:name="stalux-article-left-random"
32
- transition:animate="fade"
33
- >
15
+ <div class="stalux-sidebar-container">
34
16
  <RandomPost />
35
17
  </div>
36
18
  </aside>
@@ -5,8 +5,6 @@ import Weather from "@components/stalux/common/Weather.astro";
5
5
  import PostTaxonomy from "@components/stalux/posts/PostTaxonomy.astro";
6
6
  import PostToc from "@components/stalux/posts/postToc.astro";
7
7
 
8
- import { getSidebarAnimation } from "@utils/view-transitions";
9
-
10
8
  interface Props {
11
9
  headings?: Array<{ depth: number; slug: string; text: string }>;
12
10
  tags?: string[];
@@ -16,38 +14,18 @@ interface Props {
16
14
  const { headings = [], tags = [], categories = [] } = Astro.props;
17
15
  ---
18
16
 
19
- <aside
20
- class="stalux-sidebar-right"
21
- transition:name="right-sidebar"
22
- transition:animate={getSidebarAnimation("right")}
23
- >
24
- <div
25
- class="stalux-sidebar-container"
26
- transition:name="stalux-article-right-date"
27
- transition:animate="none"
28
- >
17
+ <aside class="stalux-sidebar-right">
18
+ <div class="stalux-sidebar-container">
29
19
  <PostDate />
30
20
  <Weather />
31
21
  </div>
32
- <div
33
- class="stalux-sidebar-container"
34
- transition:name="stalux-article-right-toc"
35
- transition:animate="none"
36
- >
22
+ <div class="stalux-sidebar-container">
37
23
  <PostToc headings={headings} />
38
24
  </div>
39
- <div
40
- class="stalux-sidebar-container"
41
- transition:name="stalux-article-right-tags"
42
- transition:animate="none"
43
- >
25
+ <div class="stalux-sidebar-container">
44
26
  <PostTaxonomy kind="tag" items={tags} />
45
27
  </div>
46
- <div
47
- class="stalux-sidebar-container"
48
- transition:name="stalux-article-right-categories"
49
- transition:animate="none"
50
- >
28
+ <div class="stalux-sidebar-container">
51
29
  <PostTaxonomy kind="category" items={categories} />
52
30
  </div>
53
31
  </aside>
@@ -29,15 +29,10 @@ const tocItems = headings
29
29
  }));
30
30
  ---
31
31
 
32
- <nav
33
- transition:name="toc-container"
34
- transition:animate="none"
35
- data-toc-active-class="stalux-toc-active"
36
- aria-label={t("taxonomy.toc")}
37
- >
32
+ <nav data-toc-active-class="stalux-toc-active" aria-label={t("taxonomy.toc")}>
38
33
  <h3 class="stalux-toc-title">{title}</h3>
39
34
  {tocItems.length > 0 ? (
40
- <ul class="stalux-toc-list" transition:name="toc-content" transition:animate="fade">
35
+ <ul class="stalux-toc-list">
41
36
  {tocItems.map((heading) => (
42
37
  <li>
43
38
  <a
@@ -51,9 +46,7 @@ const tocItems = headings
51
46
  ))}
52
47
  </ul>
53
48
  ) : (
54
- <div class="stalux-toc-empty" transition:name="toc-content" transition:animate="fade">
55
- {t("taxonomy.noToc")}
56
- </div>
49
+ <div class="stalux-toc-empty">{t("taxonomy.noToc")}</div>
57
50
  )}
58
51
  </nav>
59
52
 
@@ -19,7 +19,6 @@ const { count = 5, title = t("randomPost.title") } = Astro.props;
19
19
 
20
20
  <aside
21
21
  class="stalux-random-container"
22
- transition:persist-props
23
22
  aria-label={t("randomPost.title")}
24
23
  data-stalux-random-posts
25
24
  data-count={count}
@@ -27,11 +27,7 @@ if (typeKey === "category" || typeKey === "categories" || typeKey === "分类")
27
27
  }
28
28
  ---
29
29
 
30
- <header
31
- class="stalux-tag-header"
32
- transition:name="stalux-taxonomy-page-header-shell"
33
- transition:animate="none"
34
- >
30
+ <header class="stalux-tag-header">
35
31
  <h1 class="stalux-tag-page-title" data-stalux-motion-focus>
36
32
  <span class="stalux-tag-category-icon">
37
33
  <svg
package/src/index.ts CHANGED
@@ -163,7 +163,26 @@ export function stalux(options: StaluxOptions = {}): AstroIntegration[] {
163
163
  config.build.inlineStylesheets === "always" ? "always" : "never",
164
164
  },
165
165
  vite: {
166
- optimizeDeps: { exclude: ["@mcp-b/webmcp-polyfill"] },
166
+ optimizeDeps: {
167
+ exclude: ["@mcp-b/webmcp-polyfill"],
168
+ // Discover lazy page features before the first visit:
169
+ // Vite re-optimization would otherwise reload the
170
+ // entire document midway through a Swup navigation.
171
+ include: [
172
+ "swup",
173
+ "@swup/a11y-plugin",
174
+ "@swup/head-plugin",
175
+ "@swup/js-plugin",
176
+ "@swup/preload-plugin",
177
+ "@swup/scroll-plugin",
178
+ "@microsoft/clarity",
179
+ "@pagefind/component-ui",
180
+ "@waline/client",
181
+ "@xingwangzhe/tags-cloud",
182
+ "photoswipe",
183
+ "photoswipe/lightbox",
184
+ ],
185
+ },
167
186
  css: { lightningcss: { targets: modernCssTargets } },
168
187
  build: {
169
188
  target: config.vite.build?.target ?? "esnext",