Skip to content

Commit ef573cf

Browse files
feat: update social-share image handling to use PNG format and optimize for LinkedIn/X/Facebook
1 parent fe358e8 commit ef573cf

4 files changed

Lines changed: 17 additions & 4 deletions

File tree

public/og-default.png

61.3 KB
Loading

src/components/Seo.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface Props {
2424
const {
2525
title,
2626
description = SITE.description,
27-
image = '/og-default.svg',
27+
image = '/og-default.png',
2828
type = 'website',
2929
canonical,
3030
noindex = false,

src/pages/post/[slug].astro

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Icon from '@/components/Icon.astro';
1212
import SeriesNav from '@/components/SeriesNav.astro';
1313
import ReaderNotes from '@/components/ReaderNotes.astro';
1414
import Faqs from '@/components/Faqs.astro';
15-
import { Image } from 'astro:assets';
15+
import { Image, getImage } from 'astro:assets';
1616
import { getPosts, formatDate, readingTime, categoryUrl, getSeriesParts } from '@/lib/content';
1717
import { getSeriesForPost } from '@/data/series';
1818
import { getVideoByYoutubeId } from '@/data/videos';
@@ -31,6 +31,13 @@ const { title, description, author, pubDate, updatedDate, category, tags, heroIm
3131
const url = new URL(`/post/${post.id}`, SITE.url).href;
3232
const mdUrl = `/post/${post.id}.md`;
3333
34+
// Social-share image: optimize the post's heroImage to a 1200-wide raster and make it absolute,
35+
// so LinkedIn/X/Facebook render the post's own card (they reject SVG and require absolute URLs).
36+
// Falls back to the branded /og-default.png in Seo.astro when a post has no heroImage.
37+
const ogImage = heroImage
38+
? new URL((await getImage({ src: heroImage, width: 1200, format: 'png' })).src, SITE.url).href
39+
: undefined;
40+
3441
// Multi-part series navigation (prev/next + jump menu), driven by src/data/series.ts.
3542
const series = getSeriesForPost(post.id);
3643
const seriesParts = series ? await getSeriesParts(series, post.id) : null;
@@ -90,6 +97,7 @@ const jsonLd = [
9097
title={title}
9198
description={description}
9299
type="article"
100+
image={ogImage}
93101
contained={false}
94102
jsonLd={jsonLd}
95103
>

src/pages/video/[slug].astro

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import DocActions from '@/components/DocActions.astro';
66
import TableOfContents from '@/components/TableOfContents.astro';
77
import ReportIssue from '@/components/ReportIssue.astro';
88
import Icon from '@/components/Icon.astro';
9-
import { VIDEOS, getPlaylist, watchUrl, videosInPlaylist, playlistNeighbors } from '@/data/videos';
9+
import { VIDEOS, getPlaylist, watchUrl, videosInPlaylist, playlistNeighbors, thumbnail } from '@/data/videos';
1010
import { getTranscript } from '@/lib/transcripts';
1111
import { SITE } from '@/config';
1212
@@ -39,13 +39,17 @@ const { prev, next } = primaryPlaylist
3939
const url = new URL(`/video/${video.slug}`, SITE.url).href;
4040
const mdUrl = `/video/${video.slug}.md`;
4141
42+
// Social-share image: the YouTube maxres thumbnail (absolute raster URL) so LinkedIn/X/Facebook
43+
// render the video's own card instead of falling back to the branded /og-default.png.
44+
const ogImage = thumbnail(video.youtubeId, 'max');
45+
4246
const jsonLd = [
4347
{
4448
'@context': 'https://schema.org',
4549
'@type': 'VideoObject',
4650
name: video.title,
4751
description: video.description,
48-
thumbnailUrl: `https://i.ytimg.com/vi/${video.youtubeId}/maxresdefault.jpg`,
52+
thumbnailUrl: ogImage,
4953
uploadDate: video.publishedAt ? new Date(video.publishedAt).toISOString() : undefined,
5054
contentUrl: watchUrl(video.youtubeId),
5155
embedUrl: `https://www.youtube.com/embed/${video.youtubeId}`,
@@ -68,6 +72,7 @@ const headings = [...baseHeadings, ...transcriptHeadings.filter((h) => h.depth =
6872
title={video.title}
6973
description={video.description}
7074
type="video.other"
75+
image={ogImage}
7176
contained={false}
7277
jsonLd={jsonLd}
7378
>

0 commit comments

Comments
 (0)