From 4df698ba1a51cd986de8a319f8da90fba5d5e340 Mon Sep 17 00:00:00 2001 From: Alex Patterson Date: Thu, 22 Oct 2026 00:26:01 -0400 Subject: [PATCH] fix(site): serve responsive Retina srcset images and enable author portal (#774) --- apps/site/src/components/Avatar.astro | 9 +-- apps/site/src/components/ContentCard.astro | 6 +- apps/site/src/components/CoverImage.astro | 29 ++++++-- apps/site/src/components/CoverMedia.astro | 10 ++- apps/site/src/components/HomeSection.astro | 5 +- .../components/portable-text/PtYouTube.astro | 71 ++++++++++++++----- .../site/src/pages/api/guest-portal/update.ts | 5 +- .../site/src/pages/guest-portal/[token].astro | 21 ++++-- 8 files changed, 115 insertions(+), 41 deletions(-) diff --git a/apps/site/src/components/Avatar.astro b/apps/site/src/components/Avatar.astro index 7a1df277c..3b5e89c6f 100644 --- a/apps/site/src/components/Avatar.astro +++ b/apps/site/src/components/Avatar.astro @@ -20,10 +20,11 @@ const { height = 48, } = Astro.props; -const src = Astro.locals.sanity - .urlForImage(coverImage ?? undefined) - ?.width(width) - .height(height) +const builder = Astro.locals.sanity.urlForImage(coverImage ?? undefined); +const src = builder + ?.width(width * 2) + .height(height * 2) + .quality(82) .url(); // stegaClean: href is an attribute; zero-width characters break the URL. diff --git a/apps/site/src/components/ContentCard.astro b/apps/site/src/components/ContentCard.astro index cfe4e8ee1..066f5e4df 100644 --- a/apps/site/src/components/ContentCard.astro +++ b/apps/site/src/components/ContentCard.astro @@ -28,8 +28,9 @@ const people = [ @@ -37,6 +38,7 @@ const people = [ )} diff --git a/apps/site/src/components/CoverImage.astro b/apps/site/src/components/CoverImage.astro index 75c875a9e..943e32ced 100644 --- a/apps/site/src/components/CoverImage.astro +++ b/apps/site/src/components/CoverImage.astro @@ -8,6 +8,7 @@ interface Props { width?: number; height?: number; quality?: number; + sizes?: string; /** Above-the-fold images opt out of lazy loading. */ priority?: boolean; class?: string; @@ -18,18 +19,37 @@ const { fallbackAlt = "CodingCat.dev tutorial cover image", width = 1920, height = 1080, - quality = 80, + quality = 82, + sizes = "(max-width: 768px) 100vw, (max-width: 1280px) 50vw, 960px", priority = false, class: className = "w-full h-auto aspect-video rounded-md", } = Astro.props; -const src = Astro.locals.sanity - .urlForImage(image ?? undefined) +const builder = Astro.locals.sanity.urlForImage(image ?? undefined); +const aspect = height / width; + +const src = builder ?.width(width) .height(height) .quality(quality) .url(); +const responsiveWidths = [320, 480, 640, 960, 1280, 1600, 1920].filter( + (w) => w <= width, +); +if (!responsiveWidths.includes(width)) { + responsiveWidths.push(width); +} +const srcset = builder + ? responsiveWidths + .map((w) => { + const h = Math.round(w * aspect); + const u = builder.width(w).height(h).quality(quality).url(); + return `${u} ${w}w`; + }) + .join(", ") + : undefined; + // stegaClean: alt lands in an attribute, where stega's zero-width characters // would be read out verbatim by screen readers. const rawAlt = stegaClean((image as { alt?: string } | null)?.alt); @@ -42,13 +62,14 @@ const alt = rawAlt && rawAlt.trim().length > 0 ? rawAlt : fallbackAlt; {alt} ) : (
diff --git a/apps/site/src/components/CoverMedia.astro b/apps/site/src/components/CoverMedia.astro index f31bc3bd2..01315f2a6 100644 --- a/apps/site/src/components/CoverMedia.astro +++ b/apps/site/src/components/CoverMedia.astro @@ -54,8 +54,14 @@ const youtubeUrl = stegaClean(youtube);
) : youtubeUrl ? ( - + ) : ( - + ) } diff --git a/apps/site/src/components/HomeSection.astro b/apps/site/src/components/HomeSection.astro index f63ad522f..15b39da2e 100644 --- a/apps/site/src/components/HomeSection.astro +++ b/apps/site/src/components/HomeSection.astro @@ -43,8 +43,9 @@ const { title, description, items, muted = false } = Astro.props; )} diff --git a/apps/site/src/components/portable-text/PtYouTube.astro b/apps/site/src/components/portable-text/PtYouTube.astro index 2c0a504c7..fabdb3175 100644 --- a/apps/site/src/components/portable-text/PtYouTube.astro +++ b/apps/site/src/components/portable-text/PtYouTube.astro @@ -1,39 +1,74 @@ --- import { stegaClean } from "@sanity/client/stega"; +import type { SanityImageSource } from "@sanity/image-url"; import type { Props as PtProps } from "astro-portabletext/types"; import { youtubeId } from "@/lib/youtube"; type YouTubeNode = { _type: "youtube"; youtube?: string }; -type Props = PtProps; +type Props = PtProps & { + coverImage?: (SanityImageSource & { alt?: string }) | null; + priority?: boolean; +}; -const { node } = Astro.props; +const { node, coverImage, priority = false } = Astro.props; const id = youtubeId(stegaClean(node.youtube)); + +const builder = Astro.locals.sanity.urlForImage(coverImage ?? undefined); +const sanitySrc = builder?.width(1920).height(1080).quality(82).url(); +const sanitySrcset = builder + ? [480, 640, 960, 1280, 1600, 1920] + .map((w) => { + const h = Math.round((w * 9) / 16); + return `${builder.width(w).height(h).quality(82).url()} ${w}w`; + }) + .join(", ") + : undefined; +const rawAlt = stegaClean((coverImage as { alt?: string } | null)?.alt); +const alt = rawAlt && rawAlt.trim().length > 0 ? rawAlt : ""; --- { id && (
- - + {sanitySrc ? ( - + ) : ( + + + + + )}