Commit 4544a20

HPCesia <me@hpcesia.com>
2025-08-21 08:23:10
feat: switchable zoom feature
1 parent 69f197b
src/components/misc/ImageZoomLoader.astro
@@ -0,0 +1,10 @@
+<script>
+  import PhotoSwipeLightbox from 'photoswipe/lightbox';
+
+  window.lightbox = PhotoSwipeLightbox;
+  window.pswpModuleImporter = () => import('photoswipe');
+
+  const event = new CustomEvent('pswp:enable');
+  document.dispatchEvent(event);
+  // console.log("Producer: PhotoSwipe resources are ready and 'pswp:enable' event dispatched.");
+</script>
src/components/utils/Markdown.astro
@@ -52,65 +52,69 @@ const referenceReplacer = (_: string, reference: string, alias: string) => {
 };
 const referencePattern = /%%%%(.*?)(?:%%(.*?))?%%%%/g;
 
-const imageZoomReplacer =
-  zoomReplacer ||
-  (async (html: string) => {
-    const $ = cheerioLoad(html);
-    const imgs = $('img:where(:not(inline img, a img))');
-    if (imgs.length === 0) return html;
+const imageZoomReplacer = !buildConfig.enableImageZoom
+  ? (html: string) => html
+  : zoomReplacer ||
+    (async (html: string) => {
+      const $ = cheerioLoad(html);
+      const imgs = $('img:where(:not(inline img, a img))');
+      if (imgs.length === 0) return html;
 
-    const srcWHMap = new Map<string, { width: number; height: number }>();
-    await Promise.all(
-      imgs.map(async (_, el) => {
-        if (el.type !== 'tag') return '';
-        const src = el.attribs['src'];
-        if (!src) return '';
-        let width = parseInt(el.attribs['width']) || undefined;
-        let height = parseInt(el.attribs['height']) || undefined;
-        if (
-          (!width || !height) &&
-          !src.startsWith('/') &&
-          buildConfig.inferRemoteImageSize.enable
-        ) {
-          try {
-            const metadata = await inferRemoteSize(src);
-            width = metadata.width;
-            height = metadata.height;
-          } catch (error) {
+      const srcWHMap = new Map<string, { width: number; height: number }>();
+      await Promise.all(
+        imgs.map(async (_, el) => {
+          if (el.type !== 'tag') return '';
+          const src = el.attribs['src'];
+          if (!src) return '';
+          let width = parseInt(el.attribs['width']) || undefined;
+          let height = parseInt(el.attribs['height']) || undefined;
+          if (
+            (!width || !height) &&
+            !src.startsWith('/') &&
+            buildConfig.inferRemoteImageSize.enable
+          ) {
+            try {
+              const metadata = await inferRemoteSize(src);
+              width = metadata.width;
+              height = metadata.height;
+            } catch (error) {
+              console.warn(
+                `[WARN] Could not infer size for image "${src}": ${(error as Error).message}.`
+              );
+            }
+          }
+          if (width && height) {
+            srcWHMap.set(src, { width, height });
+          } else {
             console.warn(
-              `[WARN] Could not infer size for image "${src}": ${(error as Error).message}.`
+              [
+                `[WARN] Size for image "${src}" could not be determined, the zoom feature may not work correctly.`,
+                `Default size will be used: ${JSON.stringify(buildConfig.inferRemoteImageSize.defaultSize)}`,
+                `To ensure the zoom feature works, please provide width and height attributes for the image.`,
+                `If the image is in 'public' folder, you can use the 'width' and 'height' attributes in the <img> tag.`,
+                `If the image is from remote, please enable 'inferRemoteImageSize' in the config or provide the size manually.`,
+                `Or you can disable the zoom feature by setting 'enableImageZoom' to false in the config.`,
+              ].join('\n       ')
             );
+            srcWHMap.set(src, buildConfig.inferRemoteImageSize.defaultSize);
           }
-        }
-        if (width && height) {
-          srcWHMap.set(src, { width, height });
-        } else {
-          console.warn(
-            `[WARN] Size for image "${src}" could not be determined, the zoom feature may not work correctly.
-                    To ensure the zoom feature works, please provide width and height attributes for the image.
-                    If the image is in 'public' folder, you can use the 'width' and 'height' attributes in the <img> tag.
-                    If the image is from remote, please enable 'inferRemoteImageSize' in the config or provide the size manually.
-            `
-          );
-          srcWHMap.set(src, buildConfig.inferRemoteImageSize.defaultSize);
-        }
-      })
-    );
+        })
+      );
 
-    $('img:where(:not(inline img, a img))').wrap((_, el) => {
-      if (el.type !== 'tag') return '';
-      const src = el.attribs['src'];
-      if (!src) return '';
-      const { width, height } = srcWHMap.get(src) || {};
-      const attrs = [
-        `data-pswp-src="${el.attribs['src']}"`,
-        width ? `data-pswp-width="${width}"` : undefined,
-        height ? `data-pswp-height="${height}"` : undefined,
-      ];
-      return `<a ${attrs.join(' ')}></a>`;
+      $('img:where(:not(inline img, a img))').wrap((_, el) => {
+        if (el.type !== 'tag') return '';
+        const src = el.attribs['src'];
+        if (!src) return '';
+        const { width, height } = srcWHMap.get(src) || {};
+        const attrs = [
+          `data-pswp-src="${el.attribs['src']}"`,
+          width ? `data-pswp-width="${width}"` : undefined,
+          height ? `data-pswp-height="${height}"` : undefined,
+        ];
+        return `<a ${attrs.join(' ')}></a>`;
+      });
+      return $.html();
     });
-    return $.html();
-  });
 const imageZoomPattern = null; // Use null to process entire HTML
 
 const Fragment = bidirectionalReferences ? Replacer : 'Fragment';
src/layouts/GlobalLayout.astro
@@ -1,8 +1,9 @@
 ---
-import { profileConfig, searchConfig, siteConfig, toolBarConfig } from '@/config';
+import { buildConfig, profileConfig, searchConfig, siteConfig, toolBarConfig } from '@/config';
 import '@/styles/global.css';
 import '@/styles/transition.css';
 import Banner from '@components/Banner.astro';
+import ImageZoomLoader from '@components/misc/ImageZoomLoader.astro';
 import Navbar from '@components/Navbar.astro';
 import PageFooter from '@components/PageFooter.astro';
 import Search from '@components/Search.astro';
@@ -153,16 +154,7 @@ const siteLang = lang.replace('_', '-');
   setup();
 </script>
 
-<script>
-  import PhotoSwipeLightbox from 'photoswipe/lightbox';
-
-  window.lightbox = PhotoSwipeLightbox;
-  window.pswpModuleImporter = () => import('photoswipe');
-
-  const event = new CustomEvent('pswp:enable');
-  document.dispatchEvent(event);
-  // console.log("Producer: PhotoSwipe resources are ready and 'pswp:enable' event dispatched.");
-</script>
+{buildConfig.enableImageZoom && <ImageZoomLoader />}
 
 <style is:global>
   a[data-pwsp-src] {
src/types/config.d.ts
@@ -238,6 +238,12 @@ export type BuildConfig = {
       height: number;
     };
   };
+  /**
+   * Whether to enable image zoom feature.
+   *
+   * 是否启用图像缩放功能。
+   */
+  enableImageZoom: boolean;
 };
 
 export type ProfileConfig = {
src/config.ts
@@ -50,6 +50,7 @@ export const buildConfig: BuildConfig = {
       height: 600,
     },
   },
+  enableImageZoom: true,
 };
 
 export const profileConfig: ProfileConfig = {