From 0640943c283798545884a926d7c90d2ca72031d0 Mon Sep 17 00:00:00 2001 From: thuanbui Date: Tue, 17 Mar 2026 17:32:21 +0900 Subject: [PATCH] feat: introduce Picture component for optimized image handling across posts and hero sections --- src/components/blog/PostItem.astro | 4 +- src/components/ui/Picture.astro | 60 ++++++++++++++++++++++++++++++ src/components/widgets/Hero.astro | 6 +-- src/pages/[...slug].astro | 4 +- 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/components/ui/Picture.astro diff --git a/src/components/blog/PostItem.astro b/src/components/blog/PostItem.astro index 25eb474..fe3d36c 100644 --- a/src/components/blog/PostItem.astro +++ b/src/components/blog/PostItem.astro @@ -3,6 +3,7 @@ import Tags from "@/components/ui/Tags.astro"; import Categories from "@/components/ui/Categories.astro"; import { type CollectionEntry, render } from "astro:content"; import { toR2Url } from "@/utils/r2"; +import Picture from "@/components/ui/Picture.astro"; export interface Props { post: CollectionEntry<"blog">; @@ -23,10 +24,11 @@ const readingTime = remarkPluginFrontmatter?.minutesRead
{ coverImage && ( - {post.data.title} ) } diff --git a/src/components/ui/Picture.astro b/src/components/ui/Picture.astro new file mode 100644 index 0000000..4eddb85 --- /dev/null +++ b/src/components/ui/Picture.astro @@ -0,0 +1,60 @@ +--- +import { R2_BASE } from "@/config/r2.mjs"; + +export interface Props { + src: string; + alt: string; + class?: string; + sizes?: string; + fetchpriority?: "high" | "low" | "auto"; + loading?: "lazy" | "eager"; +} + +const { + src, + alt, + class: className, + sizes = "(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1200px", + fetchpriority, + loading, +} = Astro.props; + +const WIDTHS = [480, 800, 1200]; + +const isR2 = src.includes(R2_BASE.replace("https://", "")); + +function buildTransformUrl(src: string, width: number) { + const path = src.replace(R2_BASE, ""); + return `${R2_BASE}/cdn-cgi/image/width=${width},format=auto,onerror=redirect${path}`; +} + +const srcset = WIDTHS.map((w) => `${buildTransformUrl(src, w)} ${w}w`).join( + ", ", +); +const defaultSrc = isR2 ? buildTransformUrl(src, 800) : src; +--- + +{ + isR2 ? ( + + + {alt} + + ) : ( + {alt} + ) +} diff --git a/src/components/widgets/Hero.astro b/src/components/widgets/Hero.astro index b364b3d..77975a0 100644 --- a/src/components/widgets/Hero.astro +++ b/src/components/widgets/Hero.astro @@ -5,6 +5,7 @@ import Headline from "@/components/ui/Headline.astro"; import Button from "@/components/ui/Button.astro"; import { Icon } from "astro-icon/components"; import { toR2Url } from "@/utils/r2"; +import Picture from "@/components/ui/Picture.astro"; const { title = await Astro.slots.render("title"), @@ -33,11 +34,10 @@ const heroImage = toR2Url(bgImage); { heroImage && ( -