From a8cf518bf16da7b07c514b4ebc9fc91dc378fa66 Mon Sep 17 00:00:00 2001 From: Alex Patterson Date: Thu, 22 Oct 2026 20:26:52 -0400 Subject: [PATCH] fix(site): prevent 16:9 rect cropping on inline Portable Text images and constrain prose width --- apps/site/src/components/CoverMedia.astro | 22 +++++++++- .../portable-text/PortableTextContent.astro | 2 +- .../components/portable-text/PtImage.astro | 41 ++++++++++++++----- apps/site/src/pages/author/[slug].astro | 3 ++ apps/site/src/pages/guest/[slug].astro | 3 ++ apps/site/src/pages/podcast/[slug].astro | 2 +- apps/site/src/pages/post/[slug].astro | 2 +- apps/site/src/pages/sponsor/[slug].astro | 3 ++ 8 files changed, 63 insertions(+), 15 deletions(-) diff --git a/apps/site/src/components/CoverMedia.astro b/apps/site/src/components/CoverMedia.astro index 01315f2a6..41edd0e59 100644 --- a/apps/site/src/components/CoverMedia.astro +++ b/apps/site/src/components/CoverMedia.astro @@ -12,10 +12,21 @@ interface Props { image?: (SanityImageSource & { alt?: string }) | null; video?: { asset?: { _ref?: string } } | null; youtube?: string | null; + width?: number; + height?: number; + sizes?: string; class?: string; } -const { image, video, youtube, class: className } = Astro.props; +const { + image, + video, + youtube, + width, + height, + sizes = "(max-width: 1280px) 100vw, 1280px", + class: className, +} = Astro.props; /** * Sanity file refs are `file-{hash}-{ext}`. The Next version read the project @@ -62,6 +73,13 @@ const youtubeUrl = stegaClean(youtube); isInline={false} /> ) : ( - + ) } diff --git a/apps/site/src/components/portable-text/PortableTextContent.astro b/apps/site/src/components/portable-text/PortableTextContent.astro index acdbf3ab9..4622f183c 100644 --- a/apps/site/src/components/portable-text/PortableTextContent.astro +++ b/apps/site/src/components/portable-text/PortableTextContent.astro @@ -62,7 +62,7 @@ const components = { { value && value.length > 0 && ( -
+
) diff --git a/apps/site/src/components/portable-text/PtImage.astro b/apps/site/src/components/portable-text/PtImage.astro index ce19eac70..7c704fa83 100644 --- a/apps/site/src/components/portable-text/PtImage.astro +++ b/apps/site/src/components/portable-text/PtImage.astro @@ -13,11 +13,31 @@ type Props = PtProps; const { node } = Astro.props; -const src = Astro.locals.sanity - .urlForImage(node) - ?.width(1920) - .height(1080) - .url(); +// Parse intrinsic dimensions from Sanity asset _ref ("image--x-") +// so we never pass a forced 16:9 .height(1080) to @sanity/image-url (which causes +// @sanity/image-url to inject ?rect=... and crop tall/square images like memes or diagrams). +const assetRef = stegaClean( + (node as { asset?: { _ref?: string } })?.asset?._ref, +); +const dimMatch = assetRef?.match(/-(\d+)x(\d+)-[a-z0-9]+$/i); +const intrinsicWidth = dimMatch ? Number(dimMatch[1]) : 1200; +const intrinsicHeight = dimMatch ? Number(dimMatch[2]) : 675; + +const builder = Astro.locals.sanity.urlForImage(node); +const maxWidth = Math.min(intrinsicWidth, 1600); +const src = builder?.width(maxWidth).quality(82).url(); + +const responsiveWidths = [480, 640, 800, 960, 1200, 1600].filter( + (w) => w <= maxWidth, +); +if (!responsiveWidths.includes(maxWidth)) { + responsiveWidths.push(maxWidth); +} +const srcset = builder + ? responsiveWidths + .map((w) => `${builder.width(w).quality(82).url()} ${w}w`) + .join(", ") + : undefined; const alt = stegaClean(node.alt) ?? ""; const caption = node.caption; @@ -25,13 +45,14 @@ const caption = node.caption; { src && ( -
+
{alt}
diff --git a/apps/site/src/pages/guest/[slug].astro b/apps/site/src/pages/guest/[slug].astro index e24f32108..0d398f35c 100644 --- a/apps/site/src/pages/guest/[slug].astro +++ b/apps/site/src/pages/guest/[slug].astro @@ -75,6 +75,9 @@ const relatedPodcasts = (person.related?.podcast ?? []) as ContentListItem[];
diff --git a/apps/site/src/pages/podcast/[slug].astro b/apps/site/src/pages/podcast/[slug].astro index 7f1451016..dc3a5ef83 100644 --- a/apps/site/src/pages/podcast/[slug].astro +++ b/apps/site/src/pages/podcast/[slug].astro @@ -214,7 +214,7 @@ const faqNode = faqSchema(extractFaqsFromPortableText(podcast.content)); { podcast.transcript?.summary && ( -
+

Episode Summary

{podcast.transcript.summary} diff --git a/apps/site/src/pages/post/[slug].astro b/apps/site/src/pages/post/[slug].astro index 0579ec562..5fe45de5b 100644 --- a/apps/site/src/pages/post/[slug].astro +++ b/apps/site/src/pages/post/[slug].astro @@ -157,7 +157,7 @@ const faqNode = faqSchema(extractFaqsFromPortableText(post.content)); { post.transcript?.summary && ( -

+

Video Summary

{post.transcript.summary} diff --git a/apps/site/src/pages/sponsor/[slug].astro b/apps/site/src/pages/sponsor/[slug].astro index e5f362ec4..173f5bb25 100644 --- a/apps/site/src/pages/sponsor/[slug].astro +++ b/apps/site/src/pages/sponsor/[slug].astro @@ -66,6 +66,9 @@ const relatedPodcasts = (sponsor.related?.podcast ?? []) as ContentListItem[];