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 && (
-

)
}
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 ? (
+
+
+
+
+ ) : (
+

+ )
+}
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 && (
-
diff --git a/src/pages/[...slug].astro b/src/pages/[...slug].astro
index 2b5fd39..e3d042d 100644
--- a/src/pages/[...slug].astro
+++ b/src/pages/[...slug].astro
@@ -4,6 +4,7 @@ import Schema from "@/components/seo/Schema.astro";
import Tags from "@/components/ui/Tags.astro";
import Categories from "@/components/ui/Categories.astro";
import { toR2Url } from "@/utils/r2";
+import Picture from "@/components/ui/Picture.astro";
import { getCollection, render } from "astro:content";
@@ -74,10 +75,11 @@ const metadata = {
{
coverImage && (
-
)