mirror of
https://github.com/10h30/blog-balodeplao.git
synced 2026-05-12 15:21:15 +09:00
feat: introduce Picture component for optimized image handling across posts and hero sections
This commit is contained in:
@@ -3,6 +3,7 @@ import Tags from "@/components/ui/Tags.astro";
|
|||||||
import Categories from "@/components/ui/Categories.astro";
|
import Categories from "@/components/ui/Categories.astro";
|
||||||
import { type CollectionEntry, render } from "astro:content";
|
import { type CollectionEntry, render } from "astro:content";
|
||||||
import { toR2Url } from "@/utils/r2";
|
import { toR2Url } from "@/utils/r2";
|
||||||
|
import Picture from "@/components/ui/Picture.astro";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
post: CollectionEntry<"blog">;
|
post: CollectionEntry<"blog">;
|
||||||
@@ -23,10 +24,11 @@ const readingTime = remarkPluginFrontmatter?.minutesRead
|
|||||||
<div class="relative h-48 w-full overflow-hidden">
|
<div class="relative h-48 w-full overflow-hidden">
|
||||||
{
|
{
|
||||||
coverImage && (
|
coverImage && (
|
||||||
<img
|
<Picture
|
||||||
src={coverImage}
|
src={coverImage}
|
||||||
alt={post.data.title}
|
alt={post.data.title}
|
||||||
class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
|
class="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
|
||||||
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ? (
|
||||||
|
<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
|
||||||
|
src={src}
|
||||||
|
alt={alt}
|
||||||
|
class={className}
|
||||||
|
fetchpriority={fetchpriority}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import Headline from "@/components/ui/Headline.astro";
|
|||||||
import Button from "@/components/ui/Button.astro";
|
import Button from "@/components/ui/Button.astro";
|
||||||
import { Icon } from "astro-icon/components";
|
import { Icon } from "astro-icon/components";
|
||||||
import { toR2Url } from "@/utils/r2";
|
import { toR2Url } from "@/utils/r2";
|
||||||
|
import Picture from "@/components/ui/Picture.astro";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
title = await Astro.slots.render("title"),
|
title = await Astro.slots.render("title"),
|
||||||
@@ -33,11 +34,10 @@ const heroImage = toR2Url(bgImage);
|
|||||||
{
|
{
|
||||||
heroImage && (
|
heroImage && (
|
||||||
<Fragment slot="bg">
|
<Fragment slot="bg">
|
||||||
<img
|
<Picture
|
||||||
fetchpriority="high"
|
|
||||||
src={heroImage}
|
src={heroImage}
|
||||||
alt=""
|
alt=""
|
||||||
aria-hidden="true"
|
fetchpriority="high"
|
||||||
class="absolute inset-0 h-full w-full object-cover"
|
class="absolute inset-0 h-full w-full object-cover"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-black/55" aria-hidden="true" />
|
<div class="absolute inset-0 bg-black/55" aria-hidden="true" />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Schema from "@/components/seo/Schema.astro";
|
|||||||
import Tags from "@/components/ui/Tags.astro";
|
import Tags from "@/components/ui/Tags.astro";
|
||||||
import Categories from "@/components/ui/Categories.astro";
|
import Categories from "@/components/ui/Categories.astro";
|
||||||
import { toR2Url } from "@/utils/r2";
|
import { toR2Url } from "@/utils/r2";
|
||||||
|
import Picture from "@/components/ui/Picture.astro";
|
||||||
|
|
||||||
import { getCollection, render } from "astro:content";
|
import { getCollection, render } from "astro:content";
|
||||||
|
|
||||||
@@ -74,10 +75,11 @@ const metadata = {
|
|||||||
{
|
{
|
||||||
coverImage && (
|
coverImage && (
|
||||||
<div class="reveal relative mb-8 h-96 w-full overflow-hidden rounded-xl shadow-lg">
|
<div class="reveal relative mb-8 h-96 w-full overflow-hidden rounded-xl shadow-lg">
|
||||||
<img
|
<Picture
|
||||||
src={coverImage}
|
src={coverImage}
|
||||||
alt={title}
|
alt={title}
|
||||||
class="h-full w-full object-cover"
|
class="h-full w-full object-cover"
|
||||||
|
fetchpriority="high"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user