Skip to content

Commit b0e0ca3

Browse files
authored
fix(site): prevent 16:9 rect cropping on inline Portable Text images and constrain prose width (#781)
1 parent dcaea72 commit b0e0ca3

8 files changed

Lines changed: 63 additions & 15 deletions

File tree

‎apps/site/src/components/CoverMedia.astro‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,21 @@ interface Props {
1212
image?: (SanityImageSource & { alt?: string }) | null;
1313
video?: { asset?: { _ref?: string } } | null;
1414
youtube?: string | null;
15+
width?: number;
16+
height?: number;
17+
sizes?: string;
1518
class?: string;
1619
}
1720
18-
const { image, video, youtube, class: className } = Astro.props;
21+
const {
22+
image,
23+
video,
24+
youtube,
25+
width,
26+
height,
27+
sizes = "(max-width: 1280px) 100vw, 1280px",
28+
class: className,
29+
} = Astro.props;
1930
2031
/**
2132
* Sanity file refs are `file-{hash}-{ext}`. The Next version read the project
@@ -62,6 +73,13 @@ const youtubeUrl = stegaClean(youtube);
6273
isInline={false}
6374
/>
6475
) : (
65-
<CoverImage image={image} priority sizes="(max-width: 1280px) 100vw, 1280px" class={className} />
76+
<CoverImage
77+
image={image}
78+
width={width}
79+
height={height}
80+
priority
81+
sizes={sizes}
82+
class={className}
83+
/>
6684
)
6785
}

‎apps/site/src/components/portable-text/PortableTextContent.astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const components = {
6262

6363
{
6464
value && value.length > 0 && (
65-
<div class:list={["prose dark:prose-invert max-w-none", className]}>
65+
<div class:list={["prose dark:prose-invert max-w-4xl", className]}>
6666
<PortableText value={value} components={components} />
6767
</div>
6868
)

‎apps/site/src/components/portable-text/PtImage.astro‎

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,46 @@ type Props = PtProps<ImageNode>;
1313
1414
const { node } = Astro.props;
1515
16-
const src = Astro.locals.sanity
17-
.urlForImage(node)
18-
?.width(1920)
19-
.height(1080)
20-
.url();
16+
// Parse intrinsic dimensions from Sanity asset _ref ("image-<hash>-<width>x<height>-<ext>")
17+
// so we never pass a forced 16:9 .height(1080) to @sanity/image-url (which causes
18+
// @sanity/image-url to inject ?rect=... and crop tall/square images like memes or diagrams).
19+
const assetRef = stegaClean(
20+
(node as { asset?: { _ref?: string } })?.asset?._ref,
21+
);
22+
const dimMatch = assetRef?.match(/-(\d+)x(\d+)-[a-z0-9]+$/i);
23+
const intrinsicWidth = dimMatch ? Number(dimMatch[1]) : 1200;
24+
const intrinsicHeight = dimMatch ? Number(dimMatch[2]) : 675;
25+
26+
const builder = Astro.locals.sanity.urlForImage(node);
27+
const maxWidth = Math.min(intrinsicWidth, 1600);
28+
const src = builder?.width(maxWidth).quality(82).url();
29+
30+
const responsiveWidths = [480, 640, 800, 960, 1200, 1600].filter(
31+
(w) => w <= maxWidth,
32+
);
33+
if (!responsiveWidths.includes(maxWidth)) {
34+
responsiveWidths.push(maxWidth);
35+
}
36+
const srcset = builder
37+
? responsiveWidths
38+
.map((w) => `${builder.width(w).quality(82).url()} ${w}w`)
39+
.join(", ")
40+
: undefined;
2141
2242
const alt = stegaClean(node.alt) ?? "";
2343
const caption = node.caption;
2444
---
2545

2646
{
2747
src && (
28-
<figure class="not-prose my-8">
48+
<figure class="not-prose my-8 flex flex-col items-center">
2949
<img
30-
class="w-full h-auto rounded-md shadow-md"
50+
class="h-auto w-auto max-w-full max-h-[80dvh] rounded-md shadow-md"
3151
src={src}
32-
width={1920}
33-
height={1080}
34-
sizes="100vw"
52+
srcset={srcset}
53+
width={intrinsicWidth}
54+
height={intrinsicHeight}
55+
sizes="(max-width: 896px) 100vw, 896px"
3556
alt={alt}
3657
loading="lazy"
3758
decoding="async"

‎apps/site/src/pages/author/[slug].astro‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ const relatedPodcasts = (person.related?.podcast ?? []) as ContentListItem[];
7575
<div class="shrink-0">
7676
<CoverMedia
7777
image={person.coverImage}
78+
width={256}
79+
height={256}
80+
sizes="128px"
7881
class="size-24 rounded-md object-cover md:size-32"
7982
/>
8083
</div>

‎apps/site/src/pages/guest/[slug].astro‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ const relatedPodcasts = (person.related?.podcast ?? []) as ContentListItem[];
7575
<div class="shrink-0">
7676
<CoverMedia
7777
image={person.coverImage}
78+
width={256}
79+
height={256}
80+
sizes="128px"
7881
class="size-24 rounded-md object-cover md:size-32"
7982
/>
8083
</div>

‎apps/site/src/pages/podcast/[slug].astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ const faqNode = faqSchema(extractFaqsFromPortableText(podcast.content));
214214

215215
{
216216
podcast.transcript?.summary && (
217-
<section class="my-8 rounded-xl border border-border bg-card/50 p-6">
217+
<section class="my-8 mx-auto max-w-4xl rounded-xl border border-border bg-card/50 p-6">
218218
<h2 class="mb-3 text-xl font-bold">Episode Summary</h2>
219219
<p class="leading-relaxed text-muted-foreground">
220220
{podcast.transcript.summary}

‎apps/site/src/pages/post/[slug].astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ const faqNode = faqSchema(extractFaqsFromPortableText(post.content));
157157

158158
{
159159
post.transcript?.summary && (
160-
<section class="my-8 rounded-xl border border-border bg-card/50 p-6">
160+
<section class="my-8 mx-auto max-w-4xl rounded-xl border border-border bg-card/50 p-6">
161161
<h2 class="mb-3 text-xl font-bold">Video Summary</h2>
162162
<p class="leading-relaxed text-muted-foreground">
163163
{post.transcript.summary}

‎apps/site/src/pages/sponsor/[slug].astro‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const relatedPodcasts = (sponsor.related?.podcast ?? []) as ContentListItem[];
6666
<div class="shrink-0">
6767
<CoverMedia
6868
image={sponsor.coverImage}
69+
width={256}
70+
height={256}
71+
sizes="128px"
6972
class="size-24 rounded-md object-cover md:size-32"
7073
/>
7174
</div>

0 commit comments

Comments
 (0)