Skip to content

feat: 支持图片渐进式加载并添加控制开关 - #473

Draft
Sonder9999 wants to merge 6 commits into
CuteLeaf:masterfrom
Sonder9999:feat/progressive-image-loading
Draft

feat: 支持图片渐进式加载并添加控制开关#473
Sonder9999 wants to merge 6 commits into
CuteLeaf:masterfrom
Sonder9999:feat/progressive-image-loading

Conversation

@Sonder9999

@Sonder9999 Sonder9999 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Type of change

  • New feature(a non-breaking change that adds functionality)

Checklist

  • I have read the CONTRIBUTING document.
  • I have checked to ensure that this Pull Request is not for personal changes.
  • I have performed a self-review of my own code.
  • My changes generate no new warnings.

Changes

参考链接: 图片渐进式加载
本 PR 实现了图片的渐进式加载功能。在封面图和图片包装组件完全加载前,会优先展示一个经过高斯模糊处理的低分辨率占位图,以提升首屏视觉体验和感知加载速度。(后面看了一下实际效果,发现其实已经实现过了,渐变过渡,算是增强版本?)

具体变更如下:

  • LQIP 生成脚本升级:更新了 scripts/generate-lqips.ts,将原来基于 2x2 像素提取的 18 位十六进制渐变色占位图,改为了使用 Sharp 生成的 16x16 真实低清 base64 占位图。
  • 向下兼容:更新了 src/utils/lqip-utils.ts,完美兼容旧版的 18 位渐变色格式与新版的 base64 占位图格式。
  • Astro 组件整合:在 CoverImage.astroImageWrapper.astro 中,通过 Astro 的 getImage 动态生成 20px 宽度、20% 质量的本地微缩图,并通过 CSS 变量 --tiny-src 注入。
  • 样式与动画:在 src/styles/main.css 中添加了模糊效果(20px)、防白边的微调缩放(1.05)以及平滑的淡入淡出过渡动画。
  • 控制开关:在设置面板(DisplaySettingsIntegrated.svelte)中,新增了“图片设置”区块以及“图片渐进式加载”开关,并将用户偏好持久化至 localStorage
  • 防闪烁处理:在 Layout.astro 的 HTML 渲染前读取缓存配置并设置 data-progressive-loading 属性,避免页面加载时出现白屏或闪烁。
  • 多语言支持:用AI补全了英文、简体中文、繁体中文、日文和俄文翻译文件中的相关翻译键(progressiveLoadingimageSettings)。

How To Test

  1. 启动开发服务器(pnpm dev)或进行构建预览(pnpm build && pnpm preview)。
  2. 打开侧边栏/底部设置面板,确认在**“图片设置”区域新增了“图片渐进式加载”**的开关。
  3. 开启此开关,在浏览器控制台中将网络限速为“Slow 3G”后刷新页面。
  4. 观察封面图和内容图片,是否会首先呈现模糊的低高清 base64 占位图,随后平滑淡入切换为高清原图。
  5. 关闭开关,验证图片是否回退到普通的直接加载模式,不再有模糊占位。

Screenshots (if applicable)

之前的渐变过渡 (Before) 开启渐进式加载图片之后 (After)
之前的渐变过渡 渐进式加载图片
渐变过渡 渐进式加载

Summary by Sourcery

引入可配置的渐进式图片加载功能,使用微小的模糊占位图并更新 LQIP 支持。

New Features:

  • 添加一个用户可切换的渐进式图片加载设置,通过持久化存储和文档级数据属性来控制占位符行为。
  • 在 Astro 封面和图片组件中生成本地的微型图片缩略图,在加载期间作为模糊占位图使用。
  • 在显示设置面板中新增「图片设置」区域,用于管理渐进式加载,并提供恢复默认的控制项。

Enhancements:

  • 更新 LQIP 生成脚本,使用 Sharp 创建 16x16 低质量 JPEG base64 占位图,以取代原先的 18 字符渐变色方案。
  • 扩展 LQIP 工具以同时支持旧的渐变格式和新的 base64 图片占位图,并将其接入现有组件。
  • 增强 LQIP 占位符样式,加入模糊、轻微缩放以及更平滑的过渡效果,由 HTML 元素上的渐进式加载标志进行驱动。
  • 在布局初始化阶段尽早设置渐进式加载状态,以避免首屏渲染时的闪烁。

Documentation:

  • 为渐进式图片加载和图片设置新增 i18n 键值及对应的多语言翻译。
Original summary in English

Summary by Sourcery

Introduce configurable progressive image loading using tiny blurred placeholders and updated LQIP support.

New Features:

  • Add a user-toggleable progressive image loading setting with persistence and document-level data attribute to control placeholder behavior.
  • Generate tiny local image thumbnails in Astro cover and image components to serve as blurred placeholders during loading.
  • Add an Image Settings section in the display settings panel to manage progressive loading with a reset-to-default control.

Enhancements:

  • Update the LQIP generation script to create 16x16 low-quality JPEG base64 placeholders using Sharp instead of 18-character gradient colors.
  • Extend LQIP utilities to support both legacy gradient format and new base64 image placeholders, wiring them into existing components.
  • Enhance LQIP placeholder styles with blur, slight scaling, and smoother transitions, driven by the progressive loading flag on the HTML element.
  • Initialize progressive loading state early in the layout to avoid flicker on first render.

Documentation:

  • Add i18n keys and translations for progressive image loading and image settings across supported languages.

@netlify

netlify Bot commented Jul 7, 2026

Copy link
Copy Markdown

Deploy Preview for demo-firefly ready!

Name Link
🔨 Latest commit 32feb79
🔍 Latest deploy log https://app.netlify.com/projects/demo-firefly/deploys/6a4ce197e4d7b60008bb531f
😎 Deploy Preview https://deploy-preview-473--demo-firefly.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@sourcery-ai

sourcery-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

审阅者指南

通过升级 LQIP 流水线以使用真实的低分辨率 base64 缩略图,将其接入 Astro 图片组件,添加带有持久化设置的用户开关,并基于文档级数据属性应用模糊/过渡效果,同时在页面早期初始化以避免闪烁,从而实现可配置的渐进式图片加载。

渐进式图片加载切换与应用的时序图

sequenceDiagram
    actor User
    participant DisplaySettingsIntegrated as DisplaySettingsIntegrated
    participant SettingUtils as setting_utils_ts
    participant Document as document_html
    participant Layout as Layout_astro

    User->>DisplaySettingsIntegrated: click progressiveLoading button
    DisplaySettingsIntegrated->>DisplaySettingsIntegrated: toggleProgressiveLoading()
    DisplaySettingsIntegrated->>SettingUtils: setProgressiveLoadingEnabled(enabled)
    SettingUtils->>SettingUtils: localStorage.setItem("progressiveLoadingEnabled", String(enabled))
    SettingUtils->>Document: document.documentElement.setAttribute(data-progressive-loading, String(enabled))
    SettingUtils->>Document: new CustomEvent("progressiveLoadingToggle")

    Note over Layout,Document: On initial load
    Layout->>Document: localStorage.getItem("progressiveLoadingEnabled")
    Layout->>Document: document.documentElement.setAttribute(data-progressive-loading, progressiveEnabled)
    Layout->>SettingUtils: initProgressiveLoading()
    SettingUtils->>Document: document.documentElement.setAttribute(data-progressive-loading, enabled)
Loading

文件级变更

变更 详情 文件
通过文档级标记和初始化钩子持久化渐进式图片加载设置。
  • 围绕 progressiveLoadingEnabled 标志新增 localStorage 读写辅助方法,包括默认值为 true,以及在 localStorage 不可用时的安全防护。
  • 更新 Layout.astro,以便在渲染前初始化 data-progressive-loading,并在启动时调用新的 initProgressiveLoading 辅助函数。
  • 在 setter 中派发 progressiveLoadingToggle CustomEvent,以便其他代码能对运行时变更作出响应。
src/utils/setting-utils.ts
src/layouts/Layout.astro
在集成显示设置中暴露渐进式图片加载的 UI 区块和切换开关。
  • 将渐进式加载状态注入 Svelte 设置组件,并在挂载时从存储的设置中进行初始化。
  • 新增“图片设置”区域,包含与现有控件风格一致的切换按钮以及“重置为默认”按钮。
  • 将开关与 setProgressiveLoadingEnabled 绑定,以保持 UI、文档属性和存储之间的同步。
src/components/controls/DisplaySettingsIntegrated.svelte
将 LQIP 生成从十六进制渐变切换为 base64 低分辨率图片,同时在运行时保持向后兼容。
  • 重新实现 LQIP 生成器,使用 sharp 生成 16x16 的低质量 JPEG,并输出 data:image/jpeg;base64 URL,而不是 18 字符的十六进制渐变。
  • 扩展 LQIP 运行时工具,以检测 base64 占位符与传统 18 字符紧凑字符串,并推导出相应的背景样式。
  • 在仅存在旧的 18 字符紧凑字符串时保留现有渐变支持作为回退。
scripts/generate-lqips.ts
src/utils/lqip-utils.ts
src/constants/lqips.json
将微缩图集成到 Astro 图片组件中,并通过自定义属性将其接入 CSS。
  • 在 CoverImage.astro 和 ImageWrapper.astro 中导入 getImage,用于在构建时为本地图片生成宽度为 20px 的低质量派生图。
  • 在 LQIP 占位符包装元素中注入 --tiny-src CSS 变量和 data-tiny-src 标记,以便 CSS 可以切换使用微缩图。
  • 保持现有 LQIP 属性和整体布局不变,只增强占位符的行为。
src/components/common/CoverImage.astro
src/components/common/ImageWrapper.astro
优化 LQIP 样式,并添加基于渐进式加载标志的模糊/缩放行为。
  • 增强 .lqip-placeholder,以支持更多过渡效果和背景适配选项。
  • 引入 html[data-progressive-loading="true"] 作用域下的样式,为占位符应用模糊和轻微缩放,并在存在 --tiny-src 时强制背景图片使用该变量。
  • 通过保留 .loaded 的不透明度行为,确保加载状态仍然以淡出方式结束。
src/styles/main.css
为新的图片设置和渐进式加载开关添加 i18n 键与翻译。
  • 为共享的 i18n 键枚举新增 progressiveLoading 和 imageSettings 条目。
  • 在英文、简体中文、繁体中文、日文和俄文等语言环境中填充这些新键的翻译。
src/i18n/i18nKey.ts
src/i18n/languages/en.ts
src/i18n/languages/ja.ts
src/i18n/languages/ru.ts
src/i18n/languages/zh_CN.ts
src/i18n/languages/zh_TW.ts

提示与命令

与 Sourcery 交互

  • 触发新审阅: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 在审阅评论下回复,请求 Sourcery 从该评论创建 issue。也可以回复 @sourcery-ai issue 来从该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题中任意位置写入 @sourcery-ai 以随时生成标题。也可以在拉取请求中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中任意位置写入 @sourcery-ai summary,即可在指定位置生成 PR 摘要。也可以在拉取请求中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,以解决所有 Sourcery 评论。当你已经处理完所有评论且不希望再看到它们时很有用。
  • 关闭所有 Sourcery 审阅: 在拉取请求中评论 @sourcery-ai dismiss,以关闭所有现有的 Sourcery 审阅。特别适合在你想从一次全新的审阅开始时使用——别忘了再评论 @sourcery-ai review 来触发新的审阅!

自定义你的体验

访问你的控制面板 以:

  • 启用或禁用审阅特性,例如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、移除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Implements configurable progressive image loading by upgrading the LQIP pipeline to use real low-res base64 thumbnails, wiring them into Astro image components, adding a user-facing toggle with persisted settings, and applying blur/transition effects based on a document-level data attribute initialized early to avoid flicker.

Sequence diagram for progressive image loading toggle and application

sequenceDiagram
    actor User
    participant DisplaySettingsIntegrated as DisplaySettingsIntegrated
    participant SettingUtils as setting_utils_ts
    participant Document as document_html
    participant Layout as Layout_astro

    User->>DisplaySettingsIntegrated: click progressiveLoading button
    DisplaySettingsIntegrated->>DisplaySettingsIntegrated: toggleProgressiveLoading()
    DisplaySettingsIntegrated->>SettingUtils: setProgressiveLoadingEnabled(enabled)
    SettingUtils->>SettingUtils: localStorage.setItem("progressiveLoadingEnabled", String(enabled))
    SettingUtils->>Document: document.documentElement.setAttribute(data-progressive-loading, String(enabled))
    SettingUtils->>Document: new CustomEvent("progressiveLoadingToggle")

    Note over Layout,Document: On initial load
    Layout->>Document: localStorage.getItem("progressiveLoadingEnabled")
    Layout->>Document: document.documentElement.setAttribute(data-progressive-loading, progressiveEnabled)
    Layout->>SettingUtils: initProgressiveLoading()
    SettingUtils->>Document: document.documentElement.setAttribute(data-progressive-loading, enabled)
Loading

File-Level Changes

Change Details Files
Persisted progressive image loading setting with document-level flag and init hook.
  • Added getter/setter helpers around localStorage for the progressiveLoadingEnabled flag, including a default of true and safe guards when localStorage is unavailable.
  • Updated Layout.astro to initialize data-progressive-loading before rendering and to call a new initProgressiveLoading helper on startup.
  • Dispatched a progressiveLoadingToggle CustomEvent from the setter so other code can react to runtime changes.
src/utils/setting-utils.ts
src/layouts/Layout.astro
Exposed a UI section and toggle switch for progressive image loading in the integrated display settings.
  • Injected progressive loading state into the Svelte settings component and initialized it from stored settings on mount.
  • Added an Image Settings section with a toggle button styled consistently with existing controls and a reset-to-default button.
  • Hooked the toggle to setProgressiveLoadingEnabled to keep UI, document attribute, and storage in sync.
src/components/controls/DisplaySettingsIntegrated.svelte
Switched LQIP generation from hex gradients to base64 low-res images while keeping backward compatibility at runtime.
  • Reimplemented the LQIP generator to use sharp to produce 16x16 low-quality JPEGs and emit data:image/jpeg;base64 URLs instead of 18-char hex gradients.
  • Extended LQIP runtime utilities to detect base64 placeholders vs legacy hex compact strings and derive appropriate background styles.
  • Kept existing gradient support as a fallback when only old 18-char compact strings are present.
scripts/generate-lqips.ts
src/utils/lqip-utils.ts
src/constants/lqips.json
Integrated tiny thumbnails into Astro image components and wired them to CSS via custom properties.
  • Imported getImage in CoverImage.astro and ImageWrapper.astro to generate 20px wide, low-quality derivatives for local images at build time.
  • Injected a --tiny-src CSS variable and data-tiny-src flag into the LQIP placeholder wrapper to allow CSS to swap in the tiny thumbnail.
  • Kept existing LQIP props and overall layout, only augmenting the placeholder behavior.
src/components/common/CoverImage.astro
src/components/common/ImageWrapper.astro
Refined LQIP styling and added blur/scale behavior that is conditional on the progressive loading flag.
  • Enhanced .lqip-placeholder to support additional transitions and background fitting options.
  • Introduced html[data-progressive-loading="true"]-scoped styles that apply a blur and slight scale to placeholders, and that force background-image to use --tiny-src when available.
  • Ensured that loading state still fades out by keeping the .loaded opacity behavior.
src/styles/main.css
Added i18n keys and translations for the new image settings and progressive loading toggle.
  • Extended the shared i18n key enum with progressiveLoading and imageSettings entries.
  • Populated translations for the new keys in English, Simplified and Traditional Chinese, Japanese, and Russian locales.
src/i18n/i18nKey.ts
src/i18n/languages/en.ts
src/i18n/languages/ja.ts
src/i18n/languages/ru.ts
src/i18n/languages/zh_CN.ts
src/i18n/languages/zh_TW.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并给出了一些高层次的反馈:

  • 渐进式加载(progressive loading)的初始化逻辑现在分别存在于 Layout.astro 中的内联脚本和 setting-utils 中的 initProgressiveLoading,建议将它们整合到一个单独的 helper 中,以避免未来出现行为差异,并确保默认值和属性设置保持同步。
  • setProgressiveLoadingEnabled 中,window.dispatchEvent 在调用时没有防护 window 为 undefined 的情况;增加一个 typeof window !== "undefined" 检查可以让它在非浏览器或预渲染环境中更加安全。
  • 新增的 getLqipStyle 重新实现了已经在 getLqipGradient 中存在的 LQIP key 查找逻辑;通过重构将这部分逻辑抽成共享的查找 helper,可以减少重复并确保渐变模式和 base64 模式之间的行为一致。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The progressive loading initialization logic is now split between the inline script in `Layout.astro` and `initProgressiveLoading` in `setting-utils`; consider consolidating this into a single helper to avoid future divergence and ensure the default value and attribute setting stay in sync.
- In `setProgressiveLoadingEnabled`, `window.dispatchEvent` is called without guarding against `window` being undefined; adding a `typeof window !== "undefined"` check would make this safe in non-browser or prerendered contexts.
- The new `getLqipStyle` reimplements LQIP key lookup logic that already exists in `getLqipGradient`; refactoring to share a common lookup helper would reduce duplication and keep behavior consistent between gradient and base64 modes.

## Individual Comments

### Comment 1
<location path="src/components/common/CoverImage.astro" line_range="159-161" />
<code_context>
 >
 	<!-- LQIP 渐变占位 -->
-	<div class="lqip-placeholder absolute inset-0 pointer-events-none" style={lqipProps.style} aria-hidden="true"></div>
+	<div 
+		class="lqip-placeholder absolute inset-0 pointer-events-none" 
+		style={`${lqipProps.style};${tinyImgUrl ? `--tiny-src: url(${tinyImgUrl})` : ''}`} 
+		data-tiny-src={tinyImgUrl ? "true" : undefined}
+		aria-hidden="true"
</code_context>
<issue_to_address>
**issue (bug_risk):** 在构建 style 字符串时,需要防范 `lqipProps.style` 为 undefined。

在当前的模板字符串写法中,如果 `lqipProps.style``undefined`,将会渲染成 `style="undefined;..."`,而之前 Astro 会完全省略该属性。为避免这种情况,可以对 `lqipProps.style` 做归一化处理或按条件构建 style,例如 `const baseStyle = lqipProps.style ?? ''`,然后 `style={tinyImgUrl ? `${baseStyle};--tiny-src: url(${tinyImgUrl})` : baseStyle}`。
</issue_to_address>

### Comment 2
<location path="src/components/common/ImageWrapper.astro" line_range="119-121" />
<code_context>
+}
 ---

 <div
</code_context>
<issue_to_address>
**issue (bug_risk):** 在没有 LQIP style 时,避免输出 `style="undefined;..."`。

与 `CoverImage.astro` 中的情况类似,如果 `lqipProps.style` 未设置,将会渲染成 `style="undefined;..."`,这与之前 `style={lqipProps.style}` 的行为不同。建议将 `lqipProps.style` 归一化为空字符串,或者仅在存在基础 style 时才添加 `style` 属性,以避免出现非预期的内联样式。
</issue_to_address>

### Comment 3
<location path="src/utils/setting-utils.ts" line_range="1304-1313" />
<code_context>
+	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 } }),
+	);
</code_context>
<issue_to_address>
**issue (bug_risk):** 在非浏览器/SSR 环境中,需要对 `window.dispatchEvent` 的使用进行防护。

该 helper 已经对 `localStorage``document` 做了防护,但 `window.dispatchEvent` 仍然是无条件调用,这会在 SSR 或无 window 的环境中抛出异常。请以类似方式增加防护(例如 `if (typeof window !== 'undefined') { ... }`),以便在共享代码路径中也能安全使用。
</issue_to_address>

Sourcery 对开源项目免费 —— 如果你觉得这些评审有帮助,请考虑分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据这些反馈改进后续的代码评审。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • The progressive loading initialization logic is now split between the inline script in Layout.astro and initProgressiveLoading in setting-utils; consider consolidating this into a single helper to avoid future divergence and ensure the default value and attribute setting stay in sync.
  • In setProgressiveLoadingEnabled, window.dispatchEvent is called without guarding against window being undefined; adding a typeof window !== "undefined" check would make this safe in non-browser or prerendered contexts.
  • The new getLqipStyle reimplements LQIP key lookup logic that already exists in getLqipGradient; refactoring to share a common lookup helper would reduce duplication and keep behavior consistent between gradient and base64 modes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The progressive loading initialization logic is now split between the inline script in `Layout.astro` and `initProgressiveLoading` in `setting-utils`; consider consolidating this into a single helper to avoid future divergence and ensure the default value and attribute setting stay in sync.
- In `setProgressiveLoadingEnabled`, `window.dispatchEvent` is called without guarding against `window` being undefined; adding a `typeof window !== "undefined"` check would make this safe in non-browser or prerendered contexts.
- The new `getLqipStyle` reimplements LQIP key lookup logic that already exists in `getLqipGradient`; refactoring to share a common lookup helper would reduce duplication and keep behavior consistent between gradient and base64 modes.

## Individual Comments

### Comment 1
<location path="src/components/common/CoverImage.astro" line_range="159-161" />
<code_context>
 >
 	<!-- LQIP 渐变占位 -->
-	<div class="lqip-placeholder absolute inset-0 pointer-events-none" style={lqipProps.style} aria-hidden="true"></div>
+	<div 
+		class="lqip-placeholder absolute inset-0 pointer-events-none" 
+		style={`${lqipProps.style};${tinyImgUrl ? `--tiny-src: url(${tinyImgUrl})` : ''}`} 
+		data-tiny-src={tinyImgUrl ? "true" : undefined}
+		aria-hidden="true"
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against `lqipProps.style` being undefined when building the style string.

With the current template literal, an `undefined` `lqipProps.style` will render as `style="undefined;..."`, whereas previously Astro omitted the attribute entirely. To avoid this, normalize `lqipProps.style` or build the style conditionally, e.g. `const baseStyle = lqipProps.style ?? ''` and then `style={tinyImgUrl ? `${baseStyle};--tiny-src: url(${tinyImgUrl})` : baseStyle}`.
</issue_to_address>

### Comment 2
<location path="src/components/common/ImageWrapper.astro" line_range="119-121" />
<code_context>
+}
 ---

 <div
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid emitting `style="undefined;..."` when no LQIP style is available.

As in `CoverImage.astro`, if `lqipProps.style` is unset this will render `style="undefined;..."`, which differs from the previous `style={lqipProps.style}` behavior. Consider normalizing `lqipProps.style` to an empty string or only adding the `style` attribute when a base style is present to avoid unintended inline styles.
</issue_to_address>

### Comment 3
<location path="src/utils/setting-utils.ts" line_range="1304-1313" />
<code_context>
+	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 } }),
+	);
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard `window.dispatchEvent` usage for non-browser/SSR environments.

This helper guards `localStorage` and `document` but calls `window.dispatchEvent` unconditionally, which will throw in SSR/non-window environments. Please gate the dispatch similarly (e.g. `if (typeof window !== 'undefined') { ... }`) so it’s safe in shared code paths.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/components/common/CoverImage.astro
Comment thread src/components/common/ImageWrapper.astro
Comment on lines +1304 to +1313
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(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 在非浏览器/SSR 环境中,需要对 window.dispatchEvent 的使用进行防护。

该 helper 已经对 localStoragedocument 做了防护,但 window.dispatchEvent 仍然是无条件调用,这会在 SSR 或无 window 的环境中抛出异常。请以类似方式增加防护(例如 if (typeof window !== 'undefined') { ... }),以便在共享代码路径中也能安全使用。

Original comment in English

issue (bug_risk): Guard window.dispatchEvent usage for non-browser/SSR environments.

This helper guards localStorage and document but calls window.dispatchEvent unconditionally, which will throw in SSR/non-window environments. Please gate the dispatch similarly (e.g. if (typeof window !== 'undefined') { ... }) so it’s safe in shared code paths.

@CuteLeaf

CuteLeaf commented Jul 7, 2026

Copy link
Copy Markdown
Owner

占用太大了 2.26kb 涨到17.8kb

image

如果在设置面板关闭,就会出现下面情况

image

@Sonder9999

Copy link
Copy Markdown
Contributor Author

占用太大了 2.26kb 涨到17.8kb

image ## 如果在设置面板关闭,就会出现下面情况 image

知道什么原因了,改了之后原来的渐变色的被覆盖了,关闭之后高斯模糊没生效,然后没有模糊滤镜的 16x16 极小图片被直接拉伸放大就看到了这模糊的图片,应该都是lqips.json那边的问题,我改一下

@CuteLeaf
CuteLeaf marked this pull request as draft July 7, 2026 10:57
@Sonder9999

Copy link
Copy Markdown
Contributor Author
  • 动态生成
    不再将 base64 编码的占位图存放在 JSON 文件中。在构建阶段利用 getImage() 动态生成宽度为 32px、质量为 30% (可以调整) 的优化 WebP 缩略图:
    • pnpm build:运行之后将图片存放于目录 dist/_astro/图片名.[哈希值].webp 中。
  • 渐变
    保留了 scripts/generate-lqips.ts 的渐变。在缩略图未加载完成或生成失败时,降级显示该 CSS 渐变背景。
image

@CuteLeaf

CuteLeaf commented Jul 7, 2026

Copy link
Copy Markdown
Owner

这个缩略图生成可以跟og一样,加个开关,默认关闭,因为会影响构建速度。

还有没必要把这东西往前台设置面板那里加。

@Sonder9999

Copy link
Copy Markdown
Contributor Author

删除了前端的设置面板上的开关,现在是代码控制了,默认关闭

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants