refactor: simplify Picture component and remove unused R2 image handling, add figcaption

This commit is contained in:
Thuan Bui
2026-04-06 19:40:59 +07:00
parent c7e3ee2000
commit 95a476ab6a
2 changed files with 31 additions and 85 deletions
+3 -42
View File
@@ -1,54 +1,16 @@
--- ---
import { R2_BASE } from "@/config/r2.mjs";
export interface Props { export interface Props {
src: string; src: string;
alt: string; alt: string;
class?: string; class?: string;
sizes?: string;
fetchpriority?: "high" | "low" | "auto"; fetchpriority?: "high" | "low" | "auto";
loading?: "lazy" | "eager"; loading?: "lazy" | "eager";
} }
const { const { src, alt, class: className, fetchpriority, loading } = Astro.props;
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;
--- ---
{ <picture>
isR2 ? (
<picture>
<source type="image/webp" srcset={srcset} sizes={sizes} />
<img
src={defaultSrc}
srcset={srcset}
sizes={sizes}
alt={alt}
class={className}
fetchpriority={fetchpriority}
loading={loading}
/>
</picture>
) : (
<img <img
src={src} src={src}
alt={alt} alt={alt}
@@ -56,5 +18,4 @@ const defaultSrc = isR2 ? buildTransformUrl(src, 800) : src;
fetchpriority={fetchpriority} fetchpriority={fetchpriority}
loading={loading} loading={loading}
/> />
) </picture>
}
+21 -36
View File
@@ -1,14 +1,4 @@
import { visit } from "unist-util-visit"; import { visit } from "unist-util-visit";
import { R2_BASE } from "../config/r2.mjs";
const WIDTHS = [480, 800, 1200];
const SIZES = "(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1200px";
function buildTransformUrl(src, width) {
// Extract path từ full URL
const path = src.replace(R2_BASE, "");
return `${R2_BASE}/cdn-cgi/image/width=${width},format=auto,onerror=redirect${path}`;
}
export function rehypePictureWebp() { export function rehypePictureWebp() {
return (tree) => { return (tree) => {
@@ -16,46 +6,41 @@ export function rehypePictureWebp() {
if (node.tagName !== "img") return; if (node.tagName !== "img") return;
if (!parent || index == null) return; if (!parent || index == null) return;
const src = node.properties?.src || ""; const alt = node.properties?.alt || node.alt || "";
const pictureNode = {
// Chỉ xử lý ảnh từ R2
if (!src.startsWith(R2_BASE)) return;
// Tạo srcset với nhiều width
const srcset = WIDTHS.map(
(w) => `${buildTransformUrl(src, w)} ${w}w`,
).join(", ");
const defaultSrc = buildTransformUrl(src, 800);
parent.children[index] = {
type: "element", type: "element",
tagName: "picture", tagName: "picture",
properties: {}, properties: {},
children: [ children: [
{
type: "element",
tagName: "source",
properties: {
type: "image/webp",
srcSet: srcset,
sizes: SIZES,
},
children: [],
},
{ {
...node, ...node,
properties: { properties: {
...node.properties, ...node.properties,
src: defaultSrc,
srcSet: srcset,
sizes: SIZES,
loading: "lazy", loading: "lazy",
decoding: "async", decoding: "async",
}, },
}, },
], ],
}; };
if (alt) {
parent.children[index] = {
type: "element",
tagName: "figure",
properties: {},
children: [
pictureNode,
{
type: "element",
tagName: "figcaption",
properties: {},
children: [{ type: "text", value: alt }],
},
],
};
} else {
parent.children[index] = pictureNode;
}
}); });
}; };
} }