From 7c1029e7b59f105c2704560757f46a36f8561d33 Mon Sep 17 00:00:00 2001 From: sonder <2734165908@qq.com> Date: Sun, 5 Jul 2026 11:30:45 +0800 Subject: [PATCH 1/5] feat: implement progressive image loading with toggle switch --- src/components/common/CoverImage.astro | 20 ++++++++- src/components/common/ImageWrapper.astro | 20 ++++++++- .../controls/DisplaySettingsIntegrated.svelte | 44 +++++++++++++++++++ src/i18n/i18nKey.ts | 2 + src/i18n/languages/en.ts | 2 + src/i18n/languages/zh_CN.ts | 2 + src/layouts/Layout.astro | 12 ++++- src/styles/main.css | 11 ++++- src/utils/setting-utils.ts | 39 ++++++++++++++++ 9 files changed, 146 insertions(+), 6 deletions(-) diff --git a/src/components/common/CoverImage.astro b/src/components/common/CoverImage.astro index 2f41fa61b4..9783c62496 100644 --- a/src/components/common/CoverImage.astro +++ b/src/components/common/CoverImage.astro @@ -1,5 +1,5 @@ --- -import { Picture } from "astro:assets"; +import { Picture, getImage } from "astro:assets"; import * as path from "node:path"; import type { ImageMetadata } from "astro"; import { coverImageConfig } from "@/config"; @@ -136,6 +136,17 @@ const remoteReferrerPolicy = !isLocal && shouldAddNoReferrer(isPublic ? url(src) : src) ? "no-referrer" : undefined; + +// Generate tiny image for local images if available +let tinyImgUrl = ""; +if (isLocal && img) { + try { + const tinyImg = await getImage({ src: img, width: 20, quality: 20 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } +} ---
0 ? JSON.stringify(apiUrls) : undefined} > - + {showLoading && ( diff --git a/src/components/common/ImageWrapper.astro b/src/components/common/ImageWrapper.astro index ed0d6054b0..1e45d6e5d2 100644 --- a/src/components/common/ImageWrapper.astro +++ b/src/components/common/ImageWrapper.astro @@ -1,5 +1,5 @@ --- -import { Image, Picture } from "astro:assets"; +import { Image, Picture, getImage } from "astro:assets"; import * as path from "node:path"; import type { ImageMetadata } from "astro"; import type { ImageFormat, ResponsiveImageLayout } from "@/types/config"; @@ -103,9 +103,25 @@ const lqipProps = isLocal : isPublic ? getLqipProps(src, basePath, true) : getLqipProps(src); + +// Generate tiny image for local images if available +let tinyImgUrl = ""; +if (isLocal && img) { + try { + const tinyImg = await getImage({ src: img, width: 20, quality: 20 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } +} ---
- +
{isLocal && img && usePicture && ( { // 从localStorage读取樱花特效状态 sakuraEnabled = getStoredSakuraEnabled(); + // 从localStorage读取渐进式图片加载状态 + progressiveLoadingEnabled = getStoredProgressiveLoadingEnabled(); + // 从localStorage读取全屏透明设置状态 overlayOpacity = getStoredOverlayOpacity(); overlayBlur = getStoredOverlayBlur(); @@ -746,6 +757,39 @@ $effect(() => {
{/if} + +
+
+ {i18n(I18nKey.imageSettings)} + +
+
+ +
+
+ {#if allowLayoutSwitch}
diff --git a/src/i18n/i18nKey.ts b/src/i18n/i18nKey.ts index 270af4daaa..840180b0a7 100644 --- a/src/i18n/i18nKey.ts +++ b/src/i18n/i18nKey.ts @@ -270,6 +270,8 @@ enum I18nKey { overlayOpacity = "overlayOpacity", overlayBlur = "overlayBlur", overlayCardOpacity = "overlayCardOpacity", + progressiveLoading = "progressiveLoading", + imageSettings = "imageSettings", // 文章布局 postListLayout = "postListLayout", diff --git a/src/i18n/languages/en.ts b/src/i18n/languages/en.ts index 2299687386..78dd01f3bb 100644 --- a/src/i18n/languages/en.ts +++ b/src/i18n/languages/en.ts @@ -280,6 +280,8 @@ export const en: Translation = { [Key.overlayOpacity]: "Wallpaper Opacity", [Key.overlayBlur]: "Background Blur", [Key.overlayCardOpacity]: "Card Opacity", + [Key.progressiveLoading]: "Progressive Image Loading", + [Key.imageSettings]: "Image Settings", // Post List Layout [Key.postListLayout]: "Post List Layout", diff --git a/src/i18n/languages/zh_CN.ts b/src/i18n/languages/zh_CN.ts index 478f5aca2e..ac5e17b4fe 100644 --- a/src/i18n/languages/zh_CN.ts +++ b/src/i18n/languages/zh_CN.ts @@ -272,6 +272,8 @@ export const zh_CN: Translation = { [Key.overlayOpacity]: "壁纸透明度", [Key.overlayBlur]: "背景模糊度", [Key.overlayCardOpacity]: "卡片透明度", + [Key.progressiveLoading]: "图片渐进式加载", + [Key.imageSettings]: "图片设置", // 文章布局 [Key.postListLayout]: "文章布局", diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 534073876c..e319760452 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -350,6 +350,14 @@ const siteLang = lang.replace("_", "-"); wallpaperMode ); + // 初始化渐进式图片加载设置 - 在页面渲染前应用以避免闪烁 + const progressiveStored = localStorage.getItem("progressiveLoadingEnabled"); + const progressiveEnabled = progressiveStored === null ? "true" : progressiveStored; + document.documentElement.setAttribute( + "data-progressive-loading", + progressiveEnabled + ); + // 立即执行函数来处理DOM (function applyWallpaperMode() { // 使用 requestAnimationFrame 确保在下一帧之前执行 @@ -1651,7 +1659,7 @@ function disableAnimation() { } // Initialize wallpaper mode - import { initWallpaperMode, initThemeListener } from "@/utils/setting-utils"; + import { initWallpaperMode, initThemeListener, initProgressiveLoading } from "@/utils/setting-utils"; import { initIconLoader } from "@/utils/icon-loader"; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { @@ -1659,6 +1667,7 @@ function disableAnimation() { updateSidebarComponentsVisibility(); initWallpaperMode(); initThemeListener(); + initProgressiveLoading(); initIconLoader(); }); } else { @@ -1666,6 +1675,7 @@ function disableAnimation() { updateSidebarComponentsVisibility(); initWallpaperMode(); initThemeListener(); + initProgressiveLoading(); initIconLoader(); } diff --git a/src/styles/main.css b/src/styles/main.css index 0dd8de933c..aea803eecd 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -212,11 +212,20 @@ html { /* LQIP 占位渐变 */ .lqip-placeholder { z-index: 0; - transition: opacity 0.5s ease-out; + transition: opacity 0.5s ease-out, filter 0.5s ease-out, transform 0.5s ease-out; } .lqip-placeholder.loaded { opacity: 0; } + html[data-progressive-loading="true"] .lqip-placeholder { + filter: blur(20px); + transform: scale(1.05); /* 缩放以避免边缘模糊产生白边 */ + } + html[data-progressive-loading="true"] .lqip-placeholder[data-tiny-src="true"] { + background-image: var(--tiny-src) !important; + background-size: cover; + background-position: center; + } /* 开启边框和阴影效果时的样式 */ diff --git a/src/utils/setting-utils.ts b/src/utils/setting-utils.ts index e26fd65a6f..fea5177b6b 100644 --- a/src/utils/setting-utils.ts +++ b/src/utils/setting-utils.ts @@ -1284,3 +1284,42 @@ export function applyBannerCarouselEnabledToDocument(enabled: boolean): void { String(enabled), ); } + +// Progressive image loading functions +export function getDefaultProgressiveLoadingEnabled(): boolean { + return true; +} + +export function getStoredProgressiveLoadingEnabled(): boolean { + if (typeof localStorage === "undefined") { + return getDefaultProgressiveLoadingEnabled(); + } + const stored = localStorage.getItem("progressiveLoadingEnabled"); + if (stored === null) { + return getDefaultProgressiveLoadingEnabled(); + } + return stored === "true"; +} + +export function setProgressiveLoadingEnabled(enabled: boolean): void { + if ( + typeof localStorage === "undefined" || + typeof localStorage.setItem !== "function" + ) { + return; + } + localStorage.setItem("progressiveLoadingEnabled", String(enabled)); + if (typeof document !== "undefined") { + document.documentElement.setAttribute("data-progressive-loading", String(enabled)); + } + window.dispatchEvent( + new CustomEvent("progressiveLoadingToggle", { detail: { enabled } }), + ); +} + +export function initProgressiveLoading(): void { + const enabled = getStoredProgressiveLoadingEnabled(); + if (typeof document !== "undefined") { + document.documentElement.setAttribute("data-progressive-loading", String(enabled)); + } +} From dff4562f513ee3c776bda50e5945ecd6f1c3c7ee Mon Sep 17 00:00:00 2001 From: sonder <2734165908@qq.com> Date: Tue, 7 Jul 2026 13:36:24 +0800 Subject: [PATCH 2/5] feat: use real low-res base64 images for progressive loading --- scripts/generate-lqips.ts | 36 +++----------------- src/constants/lqips.json | 70 +++++++++++++++++++-------------------- src/styles/main.css | 5 +-- src/utils/lqip-utils.ts | 32 +++++++++++++++--- 4 files changed, 71 insertions(+), 72 deletions(-) diff --git a/scripts/generate-lqips.ts b/scripts/generate-lqips.ts index 8773f2f538..4887a4f4f5 100644 --- a/scripts/generate-lqips.ts +++ b/scripts/generate-lqips.ts @@ -16,41 +16,15 @@ const IGNORE_DIRS = [ "public/assets/music/**", ]; -interface RgbColor { - r: number; - g: number; - b: number; -} - type LqipMap = Record; -function rgbToHex(color: RgbColor): string { - const hex = (n: number) => n.toString(16).padStart(2, "0"); - return `#${hex(color.r)}${hex(color.g)}${hex(color.b)}`; -} - async function processImage(imagePath: string): Promise { try { - const { data, info } = await sharp(imagePath) - .resize(2, 2, { fit: "fill" }) - .raw() - .toBuffer({ resolveWithObject: true }); - - const channels = info.channels; - const colors: RgbColor[] = []; - - for (let i = 0; i < 4; i++) { - const offset = i * channels; - colors.push({ - r: data[offset], - g: data[offset + 1], - b: data[offset + 2], - }); - } - - // 使用 corners[0], [1], [3] 生成 135deg 斜向渐变 - const compact = `${rgbToHex(colors[0]).slice(1)}${rgbToHex(colors[1]).slice(1)}${rgbToHex(colors[3]).slice(1)}`; - return compact; + const buffer = await sharp(imagePath) + .resize(16, 16, { fit: "inside" }) + .jpeg({ quality: 15, mozjpeg: true }) + .toBuffer(); + return `data:image/jpeg;base64,${buffer.toString("base64")}`; } catch (error) { console.error(`Error processing ${imagePath}:`, error); return null; diff --git a/src/constants/lqips.json b/src/constants/lqips.json index f025b04df6..aa439da61f 100644 --- a/src/constants/lqips.json +++ b/src/constants/lqips.json @@ -1,37 +1,37 @@ { - "src:assets/images/firefly.png": "72d3af9ee699aced93", - "src:assets/images/cover.avif": "7c6f966a628a816e82", - "src:assets/images/avatar.avif": "dcd8d5d1cecabea9a9", - "public:gallery/firefly-2026/cover.avif": "7588a28a8f989e8d88", - "public:gallery/firefly-2026/1.avif": "c8bca9dde6d2babfb5", - "src:assets/images/DesktopWallpaper/d6.avif": "d9e5ec9ca7aebda9b0", - "src:assets/images/DesktopWallpaper/d5.avif": "e2dbe0e1dae1d9c9cd", - "src:assets/images/DesktopWallpaper/d4.avif": "727991b7a7bbe2b8c2", - "src:assets/images/DesktopWallpaper/d3.avif": "4268936f829e99adc7", - "src:assets/images/DesktopWallpaper/d2.avif": "b49db67a7e91d0aabc", - "src:assets/images/DesktopWallpaper/d1.avif": "8b9bb59ba6bae7d7dd", - "src:assets/images/MobileWallpaper/m6.avif": "a08eaac3abbfc7bdc8", - "src:assets/images/MobileWallpaper/m5.avif": "af99aecab1c1d2c2cb", - "src:assets/images/MobileWallpaper/m4.avif": "f0e1e2d4bfc7c2abc1", - "src:assets/images/MobileWallpaper/m3.avif": "c3a6b4dac2cad2c0c9", - "src:assets/images/MobileWallpaper/m2.avif": "f1e0ded8c2c6bbb0bc", - "src:assets/images/MobileWallpaper/m1.avif": "cccce0cbc0d59294c0", - "public:assets/images/sponsor/wechat.png": "d5d5d5dad9d7dbd8cf", - "public:assets/images/sponsor/alipay.png": "8ebbde91bedf93c0e0", - "public:assets/images/ad/ad1.webp": "a1b8b68a8e918c8f93", - "src:content/posts/images/vitepress.avif": "3d3d43e1e1e7ebe0da", - "src:content/posts/images/right-grid2.avif": "cbcdcddddcd9d8d7db", - "src:content/posts/images/obsidian.avif": "3a4145dce3e6e8ded8", - "src:content/posts/images/masonry.avif": "e4e6e4ecefebd3d1d2", - "src:content/posts/images/left-list.avif": "e9edeae3e6e3dddde1", - "src:content/posts/images/left-grid3.avif": "d7d9d9d6daddd8e1e3", - "src:content/posts/images/github.avif": "3a3a3be6e7e7eae9e9", - "src:content/posts/images/firefly3.avif": "7c6f966a628a816e81", - "src:content/posts/images/firefly2.avif": "7588a28a8f989e8d88", - "src:content/posts/images/firefly1.avif": "d4d7e5cdc4d7baaec9", - "src:content/posts/images/docusaurus.avif": "445347e2e8e3e8e4dc", - "src:content/posts/images/both-list.avif": "e5e7e4e6e8e7e3e3e5", - "src:content/posts/images/both-grid.avif": "d5d6d3e6e7e3d8d9e3", - "src:content/posts/images/1.avif": "b5b0b3bcb6bbe0e0df", - "src:content/posts/guide/cover.avif": "c8bca9dde6d2babfb5" + "src:assets/images/firefly.png": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAgEE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAAxmoP/8QAHRAAAgIBBQAAAAAAAAAAAAAAAAIBAxESEyEiMf/aAAgBAQABPwBK9aG1OORLITwuslsdz//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABURAQEAAAAAAAAAAAAAAAAAAAAh/9oACAEDAQE/AK//2Q==", + "src:assets/images/cover.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAID/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAJYKf//EABsQAAIDAAMAAAAAAAAAAAAAAAACAQMSMjNx/9oACAEBAAE/AM0qujCWJou4oR1R6f/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:assets/images/avatar.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAADapi//xAAaEAEAAwEBAQAAAAAAAAAAAAABAAIREkEx/9oACAEBAAE/ALquFshZryfdcl1Lrz7Kq2q57P/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABURAQEAAAAAAAAAAAAAAAAAAABB/9oACAEDAQE/AI//2Q==", + "public:gallery/firefly-2026/cover.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwIE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAASNJD/8QAHhAAAQMEAwAAAAAAAAAAAAAAAAECAwQREiJCcsH/2gAIAQEAAT8AZFhspq+6EvhT8+x//8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/AKz/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwCP/9k=", + "public:gallery/firefly-2026/1.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAgT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAApc7j/8QAHBAAAgEFAQAAAAAAAAAAAAAAAAIyARExQnJR/9oACAEBAAE/AL48FemzCwTsSS8n/8QAFREBAQAAAAAAAAAAAAAAAAAAAEH/2gAIAQIBAT8Aj//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/vitepress.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAKABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABQT/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAACRs5Mf/8QAGhABAAIDAQAAAAAAAAAAAAAAAQACEBEhUf/aAAgBAQABPwBbbesI1r4Y/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwB//9k=", + "src:content/posts/images/right-grid2.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQME/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA2NE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAMhAhUf/aAAgBAQABPwBrWMQhhomdx//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/obsidian.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAKABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABQT/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAACRstY//8QAGRABAAMBAQAAAAAAAAAAAAAAAQACESEQ/9oACAEBAAE/AFtr1hGtdeHn/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwB//9k=", + "src:content/posts/images/masonry.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAME/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA3pD/xAAdEAACAgEFAAAAAAAAAAAAAAAAAgERAyEyQXFy/9oACAEBAAE/ANexGWbprMu5fMmHk//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/left-list.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAQIDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAANANE//EABkQAQACAwAAAAAAAAAAAAAAAAIAECEyM//aAAgBAQABPwCLY5p9xP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/left-grid3.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA3LH/xAAbEAACAQUAAAAAAAAAAAAAAAABAgAQERJBgf/aAAgBAQABPwBgYuW1t2v/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:content/posts/images/github.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAIABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAj3Q//8QAGRAAAgMBAAAAAAAAAAAAAAAAAAECERIx/9oACAEBAAE/AJbt9Ef/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:content/posts/images/firefly3.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAID/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAJYKf//EABsQAAIDAAMAAAAAAAAAAAAAAAACAQMSMjNx/9oACAEBAAE/AM0qujCWJot4oR1R6f/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/firefly2.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwIE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAASNJD/8QAHhAAAQMEAwAAAAAAAAAAAAAAAAECAwQREiJCcsH/2gAIAQEAAT8AZFhspq+6EvhT8+x//8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/AKz/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwCP/9k=", + "src:content/posts/images/firefly1.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAADZIqf/xAAYEAADAQEAAAAAAAAAAAAAAAAAAQIxQv/aAAgBAQABPwCmTTZWo6P/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:content/posts/images/docusaurus.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAKABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABQT/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAACZodgf/8QAGhABAQACAwAAAAAAAAAAAAAAAQACESExQf/aAAgBAQABPwDJy2x0SG3j2L//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwCP/9k=", + "src:content/posts/images/both-list.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAQX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAACgIf/EABgQAAMBAQAAAAAAAAAAAAAAAAACMRBx/9oACAEBAAE/ABa9uLW6f//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:content/posts/images/both-grid.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABQBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAANryE//EABsQAAEEAwAAAAAAAAAAAAAAAAABAgMxQYGC/9oACAEBAAE/AH9KJsmwQ04//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwB//9k=", + "src:content/posts/images/1.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQME/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA1Ng//8QAGxAAAQQDAAAAAAAAAAAAAAAAAQACEEEREiH/2gAIAQEAAT8A0cbQaejMWV//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:content/posts/guide/cover.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAgT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAApc7j/8QAHBAAAgEFAQAAAAAAAAAAAAAAAAIyARExQnJR/9oACAEBAAE/AL48FemzCwTsSS8n/8QAFREBAQAAAAAAAAAAAAAAAAAAAEH/2gAIAQIBAT8Aj//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:assets/images/MobileWallpaper/m6.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQID/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAA1tV//8QAGBABAQEBAQAAAAAAAAAAAAAAAQIAERL/2gAIAQEAAT8AlbVrdreKBJyK7//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:assets/images/MobileWallpaper/m5.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAB/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAAZNl//8QAGRAAAwEBAQAAAAAAAAAAAAAAAAERAhJB/9oACAEBAAE/AE3rVdSKcuOekR//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:assets/images/MobileWallpaper/m4.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAADcJJf/xAAYEAADAQEAAAAAAAAAAAAAAAAAAhEBIv/aAAgBAQABPwB7RHq5TXtO8P/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:assets/images/MobileWallpaper/m3.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAgT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAAoZSv/8QAGxAAAgMAAwAAAAAAAAAAAAAAAAIBERMiMWH/2gAIAQEAAT8AR5blZopHXtmZ/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwB//9k=", + "src:assets/images/MobileWallpaper/m2.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA2oEf/8QAGxAAAwACAwAAAAAAAAAAAAAAAAECAxEhMTL/2gAIAQEAAT8AyNsjxOx3wKq102f/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:assets/images/MobileWallpaper/m1.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQAAsDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQME/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAANbEp//EABoQAAMBAAMAAAAAAAAAAAAAAAACEQETQWH/2gAIAQEAAT8AZt6L6PKu2ac6n//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AI//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "src:assets/images/DesktopWallpaper/d6.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAANkRD//EABsQAAIBBQAAAAAAAAAAAAAAAAACAQMQESJB/9oACAEBAAE/AIfeSoubcY//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwCP/9k=", + "src:assets/images/DesktopWallpaper/d5.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAADcLJf/xAAYEAADAQEAAAAAAAAAAAAAAAAAATECEP/aAAgBAQABPwDXHR0//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwB//9k=", + "src:assets/images/DesktopWallpaper/d4.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAgP/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAAdXNX/8QAHBAAAgICAwAAAAAAAAAAAAAAAQIAAxExQXKB/9oACAEBAAE/AK6gqtkRUHEOvINP1n//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAWEQADAAAAAAAAAAAAAAAAAAAAESH/2gAIAQMBAT8AUP/Z", + "src:assets/images/DesktopWallpaper/d3.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAgED/8QAFAEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAAmhTP/8QAGxAAAgEFAAAAAAAAAAAAAAAAAAMCATEycYH/2gAIAQEAAT8AggauMxN6bG49P//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "src:assets/images/DesktopWallpaper/d2.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAwH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAAc1qv/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAECERIDUv/aAAgBAQABPwDFk+UcUkeRH//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABYRAAMAAAAAAAAAAAAAAAAAAAARIf/aAAgBAwEBPwBQ/9k=", + "src:assets/images/DesktopWallpaper/d1.avif": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAJABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwEC/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAH1Ur//EABwQAAIBBQEAAAAAAAAAAAAAAAACAwETMkFSgf/aAAgBAQABPwC0vJWNWIsfBNn/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8AUP/Z", + "public:assets/images/sponsor/wechat.png": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQABADASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAQAE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAA3JH/xAAYEAADAQEAAAAAAAAAAAAAAAAAAgMBEv/aAAgBAQABPwClOSblJ9CLuH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AH//2Q==", + "public:assets/images/sponsor/alipay.png": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAT/xAAUAQEAAAAAAAAAAAAAAAAAAAAD/9oADAMBAAIQAxAAAACgIf8A/8QAGhABAAMAAwAAAAAAAAAAAAAAAQACEhEhMf/aAAgBAQABPwC1ks9vsqug1EurwMC25//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z", + "public:assets/images/ad/ad1.webp": "data:image/jpeg;base64,/9j/2wBDADU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////2wBDATU1NTU5NTxDQzxTWlBaU3txZ2dxe7qFj4WPhbr/sM6wsM6w//r/9ub2//r/////////////////////////////wgARCAAIABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAP/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAC8hP/EABkQAAIDAQAAAAAAAAAAAAAAAAABAhIyE//aAAgBAQABPwC0NdEPTP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z" } \ No newline at end of file diff --git a/src/styles/main.css b/src/styles/main.css index aea803eecd..14b5987d43 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -213,6 +213,9 @@ html { .lqip-placeholder { z-index: 0; transition: opacity 0.5s ease-out, filter 0.5s ease-out, transform 0.5s ease-out; + background-size: cover; + background-position: center; + background-repeat: no-repeat; } .lqip-placeholder.loaded { opacity: 0; @@ -223,8 +226,6 @@ html { } html[data-progressive-loading="true"] .lqip-placeholder[data-tiny-src="true"] { background-image: var(--tiny-src) !important; - background-size: cover; - background-position: center; } diff --git a/src/utils/lqip-utils.ts b/src/utils/lqip-utils.ts index ae52efb63c..2137c38e16 100644 --- a/src/utils/lqip-utils.ts +++ b/src/utils/lqip-utils.ts @@ -21,7 +21,6 @@ export function getLqipGradient( isPublic?: boolean, ): string | undefined { if (isPublic) { - // public 图片:key 格式为 public:xxx(去掉开头的 /) const relativePath = src.replace(/^\//, ""); const compact = lqips[`public:${relativePath}`] || lqips[relativePath]; if (compact?.length !== 18) return undefined; @@ -31,7 +30,6 @@ export function getLqipGradient( return `linear-gradient(135deg, ${c1} 0%, ${c2} 50%, ${c3} 100%)`; } - // src 图片:key 格式为 src:xxx const fullPath = basePath ? normalizePath(`${basePath}/${src}`) : src; const compact = lqips[`src:${fullPath}`] || @@ -62,8 +60,34 @@ export function getLqipStyle( isPublic?: boolean, ): string | undefined { if (isExternalImage(src)) return undefined; - const gradient = getLqipGradient(src, basePath, isPublic); - return gradient ? `background: ${gradient}` : undefined; + + let compact: string | undefined; + if (isPublic) { + const relativePath = src.replace(/^\//, ""); + compact = lqips[`public:${relativePath}`] || lqips[relativePath]; + } else { + const fullPath = basePath ? normalizePath(`${basePath}/${src}`) : src; + compact = + lqips[`src:${fullPath}`] || + lqips[`src:${src}`] || + lqips[fullPath] || + lqips[src]; + } + + if (!compact) return undefined; + + // Check if it's the new base64 image LQIP format + if (compact.startsWith("data:image/")) { + return `background-image: url(${compact})`; + } + + // Fallback to old 18-char hex gradient format + if (compact.length === 18) { + const gradient = getLqipGradient(src, basePath, isPublic); + return gradient ? `background: ${gradient}` : undefined; + } + + return undefined; } /** 获取 LQIP props(用于 Astro 组件),外部图片自动降级 */ From 5076e26bb4275ab3ff2fa282fd5439ffa2e7731b Mon Sep 17 00:00:00 2001 From: sonder <2734165908@qq.com> Date: Tue, 7 Jul 2026 14:37:49 +0800 Subject: [PATCH 3/5] feat(i18n): add missing translation keys and apply style formatting --- src/components/common/CoverImage.astro | 2 +- src/components/common/ImageWrapper.astro | 2 +- .../controls/DisplaySettingsIntegrated.svelte | 4 ++-- src/i18n/languages/ja.ts | 2 ++ src/i18n/languages/ru.ts | 2 ++ src/i18n/languages/zh_TW.ts | 2 ++ src/utils/setting-utils.ts | 10 ++++++++-- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/common/CoverImage.astro b/src/components/common/CoverImage.astro index 9783c62496..0d546734f9 100644 --- a/src/components/common/CoverImage.astro +++ b/src/components/common/CoverImage.astro @@ -1,5 +1,5 @@ --- -import { Picture, getImage } from "astro:assets"; +import { getImage, Picture } from "astro:assets"; import * as path from "node:path"; import type { ImageMetadata } from "astro"; import { coverImageConfig } from "@/config"; diff --git a/src/components/common/ImageWrapper.astro b/src/components/common/ImageWrapper.astro index 1e45d6e5d2..c052623f29 100644 --- a/src/components/common/ImageWrapper.astro +++ b/src/components/common/ImageWrapper.astro @@ -1,5 +1,5 @@ --- -import { Image, Picture, getImage } from "astro:assets"; +import { getImage, Image, Picture } from "astro:assets"; import * as path from "node:path"; import type { ImageMetadata } from "astro"; import type { ImageFormat, ResponsiveImageLayout } from "@/types/config"; diff --git a/src/components/controls/DisplaySettingsIntegrated.svelte b/src/components/controls/DisplaySettingsIntegrated.svelte index 329f820115..e53c295886 100644 --- a/src/components/controls/DisplaySettingsIntegrated.svelte +++ b/src/components/controls/DisplaySettingsIntegrated.svelte @@ -24,6 +24,7 @@ import { getStoredOverlayBlur, getStoredOverlayCardOpacity, getStoredOverlayOpacity, + getStoredProgressiveLoadingEnabled, getStoredSakuraEnabled, getStoredWallpaperMode, getStoredWavesEnabled, @@ -34,11 +35,10 @@ import { setOverlayBlur, setOverlayCardOpacity, setOverlayOpacity, + setProgressiveLoadingEnabled, setSakuraEnabled, setWallpaperMode, setWavesEnabled, - getStoredProgressiveLoadingEnabled, - setProgressiveLoadingEnabled, } from "@utils/setting-utils"; import { onMount } from "svelte"; import Icon from "@/components/common/Icon.svelte"; diff --git a/src/i18n/languages/ja.ts b/src/i18n/languages/ja.ts index ac28600fcf..3c719549e6 100644 --- a/src/i18n/languages/ja.ts +++ b/src/i18n/languages/ja.ts @@ -279,6 +279,8 @@ export const ja: Translation = { [Key.overlayOpacity]: "壁紙の透明度", [Key.overlayBlur]: "背景ぼかし", [Key.overlayCardOpacity]: "カード透明度", + [Key.progressiveLoading]: "画像プログレッシブ読み込み", + [Key.imageSettings]: "画像設定", // 投稿リストレイアウト [Key.postListLayout]: "投稿リストレイアウト", diff --git a/src/i18n/languages/ru.ts b/src/i18n/languages/ru.ts index 33b97653d2..0b644a45cf 100644 --- a/src/i18n/languages/ru.ts +++ b/src/i18n/languages/ru.ts @@ -282,6 +282,8 @@ export const ru: Translation = { [Key.overlayOpacity]: "Прозрачность обоев", [Key.overlayBlur]: "Размытие фона", [Key.overlayCardOpacity]: "Прозрачность карточек", + [Key.progressiveLoading]: "Прогрессивная загрузка изображений", + [Key.imageSettings]: "Настройки изображений", // Макет списка сообщений [Key.postListLayout]: "Макет списка сообщений", diff --git a/src/i18n/languages/zh_TW.ts b/src/i18n/languages/zh_TW.ts index c638121161..5eba1f2ee5 100644 --- a/src/i18n/languages/zh_TW.ts +++ b/src/i18n/languages/zh_TW.ts @@ -274,6 +274,8 @@ export const zh_TW: Translation = { [Key.overlayOpacity]: "桌布透明度", [Key.overlayBlur]: "背景模糊度", [Key.overlayCardOpacity]: "卡片透明度", + [Key.progressiveLoading]: "圖片漸進式載入", + [Key.imageSettings]: "圖片設定", // 文章佈局 [Key.postListLayout]: "文章佈局", diff --git a/src/utils/setting-utils.ts b/src/utils/setting-utils.ts index fea5177b6b..ddb11a6e8e 100644 --- a/src/utils/setting-utils.ts +++ b/src/utils/setting-utils.ts @@ -1310,7 +1310,10 @@ export function setProgressiveLoadingEnabled(enabled: boolean): void { } localStorage.setItem("progressiveLoadingEnabled", String(enabled)); if (typeof document !== "undefined") { - document.documentElement.setAttribute("data-progressive-loading", String(enabled)); + document.documentElement.setAttribute( + "data-progressive-loading", + String(enabled), + ); } window.dispatchEvent( new CustomEvent("progressiveLoadingToggle", { detail: { enabled } }), @@ -1320,6 +1323,9 @@ export function setProgressiveLoadingEnabled(enabled: boolean): void { export function initProgressiveLoading(): void { const enabled = getStoredProgressiveLoadingEnabled(); if (typeof document !== "undefined") { - document.documentElement.setAttribute("data-progressive-loading", String(enabled)); + document.documentElement.setAttribute( + "data-progressive-loading", + String(enabled), + ); } } From 4b561935658add21ce6ba75ac0611abe21a34f5c Mon Sep 17 00:00:00 2001 From: sonder <2734165908@qq.com> Date: Tue, 7 Jul 2026 18:49:30 +0800 Subject: [PATCH 4/5] feat: optimize lqip gradient and implement dynamic blurred thumbnail placeholders --- scripts/generate-lqips.ts | 36 ++++++++-- src/components/common/CoverImage.astro | 11 ++- src/components/common/ImageWrapper.astro | 11 ++- src/components/pages/gallery/AlbumCard.astro | 18 ++++- src/components/pages/gallery/PhotoCard.astro | 16 ++++- src/constants/lqips.json | 70 ++++++++++---------- src/pages/gallery/[album].astro | 18 ++++- src/pages/sponsor.astro | 28 +++++++- src/styles/main.css | 4 +- src/utils/lqip-utils.ts | 36 ++-------- 10 files changed, 168 insertions(+), 80 deletions(-) diff --git a/scripts/generate-lqips.ts b/scripts/generate-lqips.ts index 4887a4f4f5..8773f2f538 100644 --- a/scripts/generate-lqips.ts +++ b/scripts/generate-lqips.ts @@ -16,15 +16,41 @@ const IGNORE_DIRS = [ "public/assets/music/**", ]; +interface RgbColor { + r: number; + g: number; + b: number; +} + type LqipMap = Record; +function rgbToHex(color: RgbColor): string { + const hex = (n: number) => n.toString(16).padStart(2, "0"); + return `#${hex(color.r)}${hex(color.g)}${hex(color.b)}`; +} + async function processImage(imagePath: string): Promise { try { - const buffer = await sharp(imagePath) - .resize(16, 16, { fit: "inside" }) - .jpeg({ quality: 15, mozjpeg: true }) - .toBuffer(); - return `data:image/jpeg;base64,${buffer.toString("base64")}`; + const { data, info } = await sharp(imagePath) + .resize(2, 2, { fit: "fill" }) + .raw() + .toBuffer({ resolveWithObject: true }); + + const channels = info.channels; + const colors: RgbColor[] = []; + + for (let i = 0; i < 4; i++) { + const offset = i * channels; + colors.push({ + r: data[offset], + g: data[offset + 1], + b: data[offset + 2], + }); + } + + // 使用 corners[0], [1], [3] 生成 135deg 斜向渐变 + const compact = `${rgbToHex(colors[0]).slice(1)}${rgbToHex(colors[1]).slice(1)}${rgbToHex(colors[3]).slice(1)}`; + return compact; } catch (error) { console.error(`Error processing ${imagePath}:`, error); return null; diff --git a/src/components/common/CoverImage.astro b/src/components/common/CoverImage.astro index 0d546734f9..b0be0b29c5 100644 --- a/src/components/common/CoverImage.astro +++ b/src/components/common/CoverImage.astro @@ -137,15 +137,22 @@ const remoteReferrerPolicy = ? "no-referrer" : undefined; -// Generate tiny image for local images if available +// Generate tiny image for local or public images if available let tinyImgUrl = ""; if (isLocal && img) { try { - const tinyImg = await getImage({ src: img, width: 20, quality: 20 }); + const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); tinyImgUrl = tinyImg.src; } catch (e) { console.error("Failed to generate tiny thumbnail:", e); } +} else if (isPublic && src) { + try { + const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail for public image:", e); + } } --- diff --git a/src/components/common/ImageWrapper.astro b/src/components/common/ImageWrapper.astro index c052623f29..180e67b5af 100644 --- a/src/components/common/ImageWrapper.astro +++ b/src/components/common/ImageWrapper.astro @@ -104,15 +104,22 @@ const lqipProps = isLocal ? getLqipProps(src, basePath, true) : getLqipProps(src); -// Generate tiny image for local images if available +// Generate tiny image for local or public images if available let tinyImgUrl = ""; if (isLocal && img) { try { - const tinyImg = await getImage({ src: img, width: 20, quality: 20 }); + const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); tinyImgUrl = tinyImg.src; } catch (e) { console.error("Failed to generate tiny thumbnail:", e); } +} else if (isPublic && src) { + try { + const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail for public image:", e); + } } ---
diff --git a/src/components/pages/gallery/AlbumCard.astro b/src/components/pages/gallery/AlbumCard.astro index d8591e265d..a4f976f1b2 100644 --- a/src/components/pages/gallery/AlbumCard.astro +++ b/src/components/pages/gallery/AlbumCard.astro @@ -1,4 +1,5 @@ --- +import { getImage } from "astro:assets"; import I18nKey from "@/i18n/i18nKey"; import { i18n } from "@/i18n/translation"; import { getLqipProps } from "@/utils/lqip-utils"; @@ -30,6 +31,16 @@ const { // LQIP 渐变占位 const lqipProps = cover ? getLqipProps(cover, undefined, true) : { style: "" }; + +let tinyImgUrl = ""; +if (cover) { + try { + const tinyImg = await getImage({ src: cover, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } +} --- {cover ? ( <> - + {name} @@ -20,7 +29,12 @@ const lqipProps = getLqipProps(src, undefined, true); data-type="image" class="block rounded-xl overflow-hidden relative group cursor-pointer" > - + {alt} @@ -43,7 +54,12 @@ const coverLqipProps = cover
{cover ? (
- + {albumMeta.name} = {}; +for (const method of enabledMethods) { + if (method.qrCode) { + try { + const tinyImg = await getImage({ + src: method.qrCode, + width: 32, + quality: 30, + }); + tinyQrs[method.qrCode] = tinyImg.src; + } catch (e) { + console.error( + `Failed to generate tiny QR thumbnail for ${method.name}:`, + e, + ); + } + } +} --- @@ -88,7 +109,12 @@ function getQrLqipProps(qrCode: string) { {method.qrCode && (
- + {`${method.name} Date: Tue, 7 Jul 2026 19:18:42 +0800 Subject: [PATCH 5/5] feat: add generateTinyThumbnails config switch and remove progressive loading frontend settings --- src/components/common/CoverImage.astro | 30 +++++++------ src/components/common/ImageWrapper.astro | 29 ++++++------ .../controls/DisplaySettingsIntegrated.svelte | 44 +------------------ src/components/pages/gallery/AlbumCard.astro | 3 +- src/components/pages/gallery/PhotoCard.astro | 13 +++--- src/config/siteConfig.ts | 2 + src/pages/gallery/[album].astro | 2 +- src/pages/sponsor.astro | 30 +++++++------ src/types/siteConfig.ts | 2 + 9 files changed, 65 insertions(+), 90 deletions(-) diff --git a/src/components/common/CoverImage.astro b/src/components/common/CoverImage.astro index b0be0b29c5..403bfe8a32 100644 --- a/src/components/common/CoverImage.astro +++ b/src/components/common/CoverImage.astro @@ -2,7 +2,7 @@ import { getImage, Picture } from "astro:assets"; import * as path from "node:path"; import type { ImageMetadata } from "astro"; -import { coverImageConfig } from "@/config"; +import { coverImageConfig, siteConfig } from "@/config"; import type { ImageFormat, ResponsiveImageLayout } from "@/types/config"; import { getFallbackFormat, @@ -139,19 +139,21 @@ const remoteReferrerPolicy = // Generate tiny image for local or public images if available let tinyImgUrl = ""; -if (isLocal && img) { - try { - const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); - tinyImgUrl = tinyImg.src; - } catch (e) { - console.error("Failed to generate tiny thumbnail:", e); - } -} else if (isPublic && src) { - try { - const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); - tinyImgUrl = tinyImg.src; - } catch (e) { - console.error("Failed to generate tiny thumbnail for public image:", e); +if (siteConfig.post.generateTinyThumbnails) { + if (isLocal && img) { + try { + const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } + } else if (isPublic && src) { + try { + const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail for public image:", e); + } } } --- diff --git a/src/components/common/ImageWrapper.astro b/src/components/common/ImageWrapper.astro index 180e67b5af..0f211dd3aa 100644 --- a/src/components/common/ImageWrapper.astro +++ b/src/components/common/ImageWrapper.astro @@ -11,6 +11,7 @@ import { } from "@/utils/image-utils"; import { getLqipProps } from "@/utils/lqip-utils"; import { url } from "@/utils/url-utils"; +import { siteConfig } from "@/config"; interface Props { id?: string; @@ -106,19 +107,21 @@ const lqipProps = isLocal // Generate tiny image for local or public images if available let tinyImgUrl = ""; -if (isLocal && img) { - try { - const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); - tinyImgUrl = tinyImg.src; - } catch (e) { - console.error("Failed to generate tiny thumbnail:", e); - } -} else if (isPublic && src) { - try { - const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); - tinyImgUrl = tinyImg.src; - } catch (e) { - console.error("Failed to generate tiny thumbnail for public image:", e); +if (siteConfig.post.generateTinyThumbnails) { + if (isLocal && img) { + try { + const tinyImg = await getImage({ src: img, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } + } else if (isPublic && src) { + try { + const tinyImg = await getImage({ src: src, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail for public image:", e); + } } } --- diff --git a/src/components/controls/DisplaySettingsIntegrated.svelte b/src/components/controls/DisplaySettingsIntegrated.svelte index e53c295886..d863617e89 100644 --- a/src/components/controls/DisplaySettingsIntegrated.svelte +++ b/src/components/controls/DisplaySettingsIntegrated.svelte @@ -24,7 +24,6 @@ import { getStoredOverlayBlur, getStoredOverlayCardOpacity, getStoredOverlayOpacity, - getStoredProgressiveLoadingEnabled, getStoredSakuraEnabled, getStoredWallpaperMode, getStoredWavesEnabled, @@ -35,7 +34,6 @@ import { setOverlayBlur, setOverlayCardOpacity, setOverlayOpacity, - setProgressiveLoadingEnabled, setSakuraEnabled, setWallpaperMode, setWavesEnabled, @@ -84,7 +82,6 @@ let bannerCarouselEnabled = $state(true); const defaultBannerCarouselEnabled = getDefaultBannerCarouselEnabled(); let sakuraEnabled = $state(true); const defaultSakuraEnabled = getDefaultSakuraEnabled(); -let progressiveLoadingEnabled = $state(true); let overlayOpacity = $state(getDefaultOverlayOpacity()); const defaultOverlayOpacity = getDefaultOverlayOpacity(); let overlayBlur = $state(getDefaultOverlayBlur()); @@ -312,10 +309,7 @@ function toggleSakuraEnabled() { setSakuraEnabled(sakuraEnabled); } -function toggleProgressiveLoading() { - progressiveLoadingEnabled = !progressiveLoadingEnabled; - setProgressiveLoadingEnabled(progressiveLoadingEnabled); -} + function switchWallpaperMode(newMode: WALLPAPER_MODE) { wallpaperMode = newMode; @@ -405,9 +399,6 @@ onMount(() => { // 从localStorage读取樱花特效状态 sakuraEnabled = getStoredSakuraEnabled(); - // 从localStorage读取渐进式图片加载状态 - progressiveLoadingEnabled = getStoredProgressiveLoadingEnabled(); - // 从localStorage读取全屏透明设置状态 overlayOpacity = getStoredOverlayOpacity(); overlayBlur = getStoredOverlayBlur(); @@ -757,38 +748,7 @@ $effect(() => {
{/if} - -
-
- {i18n(I18nKey.imageSettings)} - -
-
- -
-
+ {#if allowLayoutSwitch} diff --git a/src/components/pages/gallery/AlbumCard.astro b/src/components/pages/gallery/AlbumCard.astro index a4f976f1b2..bcdb7cbb58 100644 --- a/src/components/pages/gallery/AlbumCard.astro +++ b/src/components/pages/gallery/AlbumCard.astro @@ -4,6 +4,7 @@ import I18nKey from "@/i18n/i18nKey"; import { i18n } from "@/i18n/translation"; import { getLqipProps } from "@/utils/lqip-utils"; import { url } from "@/utils/url-utils"; +import { siteConfig } from "@/config"; interface Props { id: string; @@ -33,7 +34,7 @@ const { const lqipProps = cover ? getLqipProps(cover, undefined, true) : { style: "" }; let tinyImgUrl = ""; -if (cover) { +if (siteConfig.post.generateTinyThumbnails && cover) { try { const tinyImg = await getImage({ src: cover, width: 32, quality: 30 }); tinyImgUrl = tinyImg.src; diff --git a/src/components/pages/gallery/PhotoCard.astro b/src/components/pages/gallery/PhotoCard.astro index a2cedf1827..f1f2ec518f 100644 --- a/src/components/pages/gallery/PhotoCard.astro +++ b/src/components/pages/gallery/PhotoCard.astro @@ -1,6 +1,7 @@ --- import { getImage } from "astro:assets"; import { getLqipProps } from "@/utils/lqip-utils"; +import { siteConfig } from "@/config"; interface Props { src: string; @@ -14,11 +15,13 @@ const { src, albumId, alt = "" } = Astro.props; const lqipProps = getLqipProps(src, undefined, true); let tinyImgUrl = ""; -try { - const tinyImg = await getImage({ src, width: 32, quality: 30 }); - tinyImgUrl = tinyImg.src; -} catch (e) { - console.error("Failed to generate tiny thumbnail:", e); +if (siteConfig.post.generateTinyThumbnails) { + try { + const tinyImg = await getImage({ src, width: 32, quality: 30 }); + tinyImgUrl = tinyImg.src; + } catch (e) { + console.error("Failed to generate tiny thumbnail:", e); + } } --- diff --git a/src/config/siteConfig.ts b/src/config/siteConfig.ts index 7694518f82..d543d2d1f6 100644 --- a/src/config/siteConfig.ts +++ b/src/config/siteConfig.ts @@ -161,6 +161,8 @@ export const siteConfig: SiteConfig = { sharePoster: true, // OpenGraph图片功能,注意开启后要渲染很长时间,不建议本地调试的时候开启 generateOgImages: false, + // 是否为图片生成渐进式加载所需的 32px 微缩图(构建时),开启后会增加构建时间,默认关闭 + generateTinyThumbnails: false, }, // bangumi配置 diff --git a/src/pages/gallery/[album].astro b/src/pages/gallery/[album].astro index 8ca8a83d13..009da1a079 100644 --- a/src/pages/gallery/[album].astro +++ b/src/pages/gallery/[album].astro @@ -39,7 +39,7 @@ const coverLqipProps = cover : { style: "" }; let tinyImgUrl = ""; -if (cover) { +if (siteConfig.post.generateTinyThumbnails && cover) { try { const tinyImg = await getImage({ src: cover, width: 32, quality: 30 }); tinyImgUrl = tinyImg.src; diff --git a/src/pages/sponsor.astro b/src/pages/sponsor.astro index 59618faa7c..4a364f87c5 100644 --- a/src/pages/sponsor.astro +++ b/src/pages/sponsor.astro @@ -34,20 +34,22 @@ function getQrLqipProps(qrCode: string) { // Generate tiny image for QR codes const tinyQrs: Record = {}; -for (const method of enabledMethods) { - if (method.qrCode) { - try { - const tinyImg = await getImage({ - src: method.qrCode, - width: 32, - quality: 30, - }); - tinyQrs[method.qrCode] = tinyImg.src; - } catch (e) { - console.error( - `Failed to generate tiny QR thumbnail for ${method.name}:`, - e, - ); +if (siteConfig.post.generateTinyThumbnails) { + for (const method of enabledMethods) { + if (method.qrCode) { + try { + const tinyImg = await getImage({ + src: method.qrCode, + width: 32, + quality: 30, + }); + tinyQrs[method.qrCode] = tinyImg.src; + } catch (e) { + console.error( + `Failed to generate tiny QR thumbnail for ${method.name}:`, + e, + ); + } } } } diff --git a/src/types/siteConfig.ts b/src/types/siteConfig.ts index 050847a22a..91b27af1cf 100644 --- a/src/types/siteConfig.ts +++ b/src/types/siteConfig.ts @@ -126,6 +126,8 @@ export type SiteConfig = { sharePoster?: boolean; // OpenGraph图片功能 generateOgImages: boolean; + // 是否为图片生成渐进式加载所需的 32px 微缩图 + generateTinyThumbnails?: boolean; }; // bangumi配置