Commit 7b54325

HPCesia <me@hpcesia.com>
2025-02-13 04:45:40
feat: migrate to swup
- Add `@swup/astro` dependence and set base config. - Refactor `SideToolBar.astro` to fix swup compatibility, now it's using css instead of js to show the hide part of the toolbar. - Delete transition attributes of Astro view transition API.
1 parent ae299f4
src/components/aside/ProfileCard.astro
@@ -5,7 +5,7 @@ import Button from '@components/widgets/Button.astro';
 import { Icon } from 'astro-icon/components';
 ---
 
-<div id="profile-card" transition:name="profile-card" class="card border-base-300 border-2">
+<div id="profile-card" class="card border-base-300 border-2">
   <figure class="px-4 pt-4">
     <a href="/about/">
       <ImageWrapper class="rounded-xl" src={profileConfig.avatar} alt={profileConfig.name} />
src/components/aside/SiteInfoCard.astro
@@ -4,7 +4,7 @@ import Stats from './siteinfo/Stats.astro';
 import Tags from './siteinfo/Tags.astro';
 ---
 
-<div class="card border-base-300 border-2" transition:name="site-info-card">
+<div class="card border-base-300 border-2">
   <div class="card-body px-4 py-2">
     <ul>
       {
src/components/aside/TOC.astro
@@ -38,11 +38,7 @@ function buildTocTree(headings: MarkdownHeading[]) {
 const tocTree = buildTocTree(headings);
 ---
 
-<div
-  id="toc"
-  class:list={['card border-base-300 bg-base-100 border-2', className]}
-  transition:name="toc-card"
->
+<div id="toc" class:list={['card border-base-300 bg-base-100 border-2', className]}>
   <div class="card-body max-h-96 overflow-y-auto p-2">
     <ul>
       {
src/components/Search.astro
@@ -3,7 +3,7 @@ import { searchConfig } from '@/config';
 import Pagefind from './search/Pagefind.astro';
 ---
 
-<dialog id="search_modal" class="modal" transition:persist>
+<dialog id="search_modal" class="modal">
   <div class="modal-box">
     <form method="dialog">
       <button class="btn btn-circle btn-ghost btn-sm absolute top-2 right-2">✕</button>
src/components/SideToolBar.astro
@@ -5,25 +5,17 @@ import Button from './widgets/Button.astro';
 import DarkModeButton from './widgets/DarkModeButton.astro';
 ---
 
-<div
-  id="side-toolbar"
-  class="fixed right-0 bottom-10 z-30 grid grid-cols-1 gap-2"
-  transition:name="side-toolbar"
-  transition:persist
->
-  <div
-    id="stb-hide"
-    class="grid translate-x-full grid-cols-1 gap-2 pr-4 duration-500 ease-in-out"
-    inert
-  >
-    <DarkModeButton id="stb-dark-mode" class="btn-circle btn-primary btn-sm" />
-  </div>
+<div id="side-toolbar" class="fixed right-0 bottom-10 z-30 grid grid-cols-1 gap-2">
   <div
     id="stb-show"
-    class="grid translate-x-full grid-cols-1 gap-2 pr-4 duration-500 ease-in-out"
-    inert
+    class="peer order-2 grid translate-x-full grid-cols-1 gap-2 pr-4 duration-500 ease-in-out"
   >
     <Button id="stb-show-more" class="btn-circle btn-primary btn-sm">
+      <input
+        type="checkbox"
+        class="absolute z-10 h-8 w-8 cursor-pointer appearance-none border-0"
+        checked
+      />
       <Icon name="material-symbols:settings-rounded" class="animate-spin" />
     </Button>
     {
@@ -50,13 +42,18 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
       />
     </Button>
   </div>
+  <div
+    id="stb-hide"
+    class="order-1 grid grid-cols-1 gap-2 pr-4 duration-500 ease-in-out peer-[:first-child:has(:checked)]:translate-x-full"
+  >
+    <DarkModeButton id="stb-dark-mode" class="btn-circle btn-primary btn-sm" />
+  </div>
 </div>
 
 <script>
   import { getReadingProgress } from '@scripts/utils';
 
   function initSideToolBar() {
-    const stbHide = document.getElementById('stb-hide');
     const stbShow = document.getElementById('stb-show');
     const stbShowMore = document.getElementById('stb-show-more');
     const stbBackToTop = document.getElementById('stb-back-to-top');
@@ -65,11 +62,6 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
     const stbToc = document.getElementById('stb-toc');
     const stbTocWrapper = document.getElementById('stb-toc-wrapper');
 
-    stbShowMore?.addEventListener('click', () => {
-      stbHide?.classList.toggle('translate-x-full');
-      stbHide?.toggleAttribute('inert');
-    });
-
     stbBackToTop?.addEventListener('click', () => {
       window.scrollTo({
         top: 0,
@@ -82,6 +74,12 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
       stbTocWrapper?.classList.toggle('-translate-x-full');
     });
 
+    // 清理可能存在的旧目录
+    stbTocWrapper!.innerHTML = '';
+    stbToc?.classList.add('hidden');
+    stbTocWrapper?.classList.add('hidden');
+    stbTocWrapper?.classList.add('-translate-x-full');
+
     const toc = document.getElementById('toc');
     if (toc && stbTocWrapper) {
       const remainAttrs = ['class', 'style'];
@@ -108,13 +106,9 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
       // 控制工具栏显隐
       if (window.scrollY > 0) {
         stbShow?.classList.remove('translate-x-full');
-        stbShow?.removeAttribute('inert');
       } else {
         stbShow?.classList.add('translate-x-full');
-        stbHide?.classList.add('translate-x-full');
-        stbShow?.setAttribute('inert', '');
-        stbHide?.setAttribute('inert', '');
-
+        stbShowMore!.querySelector('input')!.checked = true;
         stbTocWrapper?.classList.add('scale-0');
         stbTocWrapper?.classList.remove('-translate-x-full');
       }
@@ -138,6 +132,8 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
     });
   }
 
-  document.addEventListener('astro:after-swap', initSideToolBar);
+  document.addEventListener('astro:page-load', () => {
+    initSideToolBar();
+  });
   initSideToolBar();
 </script>
src/layouts/GlobalLayout.astro
@@ -3,7 +3,6 @@ import { profileConfig, siteConfig } from '@/config';
 import '@/styles/global.css';
 import type { Favicon } from '@/types/config';
 import { defaultFavicons } from '@constants/icon';
-import { ClientRouter } from 'astro:transitions';
 
 interface Props {
   title?: string;
@@ -33,8 +32,6 @@ const favicons: Favicon[] =
     <meta charset="UTF-8" />
     <meta name="author" content={profileConfig.name} />
 
-    <ClientRouter />
-
     <!-- Open Graph / Facebook -->
     <meta property="og:site_name" content={siteConfig.title} />
     <meta property="og:url" content={Astro.url} />
@@ -80,7 +77,7 @@ const favicons: Favicon[] =
 
 <script>
   import { convertTimeToRelative } from '@scripts/utils';
-  import mediumZoom from 'medium-zoom';
+  import mediumZoom from 'medium-zoom/dist/pure';
 
   // 深色模式切换
   function applyDarkMode() {
@@ -107,6 +104,7 @@ const favicons: Favicon[] =
 </script>
 
 <style is:global>
+  @import 'medium-zoom/dist/style.css';
   .medium-zoom-overlay,
   .medium-zoom-image--opened {
     z-index: 999;
src/layouts/MainLayout.astro
@@ -21,12 +21,12 @@ const { title, description, lang } = Astro.props;
     <slot name="header" />
     <div id="body-wrap" class="w-full items-center md:px-4">
       <!-- Main content -->
-      <div class="mx-auto flex max-w-(--breakpoint-xl) flex-col gap-4">
+      <main class="mx-auto flex max-w-(--breakpoint-xl) flex-col gap-4">
         <slot name="header-content" />
         <div class="flex gap-4">
-          <main id="main-content" class="my-4 w-full">
+          <div id="main-content" class="my-4 w-full">
             <slot />
-          </main>
+          </div>
           <div id="aside-content" class="my-4 flex w-96 flex-col gap-4 max-xl:hidden">
             <slot name="aside-fixed" />
             <div class="sticky top-20 flex flex-col gap-4">
@@ -34,7 +34,7 @@ const { title, description, lang } = Astro.props;
             </div>
           </div>
         </div>
-      </div>
+      </main>
     </div>
   </Navbar>
   {searchConfig.enable && <Search />}
src/global.d.ts
@@ -0,0 +1,7 @@
+import type { Swup } from '@swup/astro/client';
+
+declare global {
+  interface Window {
+    swup: Swup;
+  }
+}
astro.config.mjs
@@ -11,6 +11,7 @@ import { wrapCode } from './src/plugins/shiki-transformers.ts';
 import { rehypeHeadingIds } from '@astrojs/markdown-remark';
 import mdx from '@astrojs/mdx';
 import sitemap from '@astrojs/sitemap';
+import swup from '@swup/astro';
 // import { transformerNotationDiff } from '@shikijs/transformers';
 // import { transformerNotationHighlight } from '@shikijs/transformers';
 import tailwindcss from '@tailwindcss/vite';
@@ -32,6 +33,11 @@ export default defineConfig({
     sitemap({ filter: (page) => !page.includes('/archives/') && !page.includes('/about/') }),
     pagefind(),
     mdx(),
+    swup({
+      containers: ['main'],
+      animationClass: 'swup-transition-',
+      globalInstance: true,
+    }),
   ],
   markdown: {
     shikiConfig: {
package.json
@@ -21,6 +21,7 @@
     "@iconify-json/material-symbols": "^1.2.14",
     "@iconify-json/mdi": "^1.2.3",
     "@shikijs/transformers": "^2.3.2",
+    "@swup/astro": "^1.5.0",
     "@tailwindcss/vite": "^4.0.6",
     "astro": "^5.2.5",
     "astro-compress": "2.3.5",
@@ -42,10 +43,10 @@
     "remark-math": "^6.0.0",
     "sanitize-html": "^2.14.0",
     "sharp": "^0.33.5",
+    "shiki": "^2.3.2",
     "tailwindcss": "^4.0.6",
     "typescript": "^5.7.3",
-    "unist-util-visit": "^5.0.0",
-    "shiki": "^2.3.2"
+    "unist-util-visit": "^5.0.0"
   },
   "devDependencies": {
     "@astrojs/check": "^0.9.4",