From 6ae9b7b9d2b9d2736f6a872dab9723c7048d7dae Mon Sep 17 00:00:00 2001 From: Jaeyoun Nam Date: Thu, 23 Jul 2026 12:03:34 -0700 Subject: [PATCH] fix(landing): use blog metadata for social previews --- apps/landing/src/features/blog/images.ts | 26 +++---------------- .../src/features/blog/share-image.test.ts | 24 +++++++++++++++++ apps/landing/src/features/blog/share-image.ts | 5 ++++ apps/landing/src/layouts/BaseLayout.astro | 2 ++ apps/landing/src/layouts/types.ts | 1 + apps/landing/src/pages/blog/[postSlug].astro | 5 ++-- 6 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 apps/landing/src/features/blog/share-image.test.ts create mode 100644 apps/landing/src/features/blog/share-image.ts diff --git a/apps/landing/src/features/blog/images.ts b/apps/landing/src/features/blog/images.ts index 7c1e5b27..98ea5794 100644 --- a/apps/landing/src/features/blog/images.ts +++ b/apps/landing/src/features/blog/images.ts @@ -5,29 +5,7 @@ import { ONEQUERY } from "@/shared/seo/constants"; import type { SeoImage } from "@/shared/seo/constants"; import { toAbsoluteSiteUrl } from "@/shared/seo/schema"; -import type { BlogPost, BlogPostSummary } from "./types"; - -const BLOG_SHARE_IMAGE = { - MAX_RATIO: 2.2, - MIN_RATIO: 1.45, - MIN_WIDTH: 1200, -} as const; - -function isPreferredShareImage(image: ImageMetadata) { - const ratio = image.width / image.height; - - return ( - image.width >= BLOG_SHARE_IMAGE.MIN_WIDTH && - ratio >= BLOG_SHARE_IMAGE.MIN_RATIO && - ratio <= BLOG_SHARE_IMAGE.MAX_RATIO - ); -} - -export function getPreferredBlogShareImage(post: Pick) { - return isPreferredShareImage(post.coverImage.src) - ? post.coverImage.src - : undefined; -} +import type { BlogPostSummary } from "./types"; export async function getBlogShareImage( image: ImageMetadata | undefined, @@ -65,3 +43,5 @@ export async function getBlogShareImagesBySlug( ) ); } + +export { getBlogShareImageSource } from "./share-image"; diff --git a/apps/landing/src/features/blog/share-image.test.ts b/apps/landing/src/features/blog/share-image.test.ts new file mode 100644 index 00000000..7671668e --- /dev/null +++ b/apps/landing/src/features/blog/share-image.test.ts @@ -0,0 +1,24 @@ +import type { ImageMetadata } from "astro"; +import { describe, expect, it } from "vitest"; + +import { getBlogShareImageSource } from "./share-image"; + +describe("getBlogShareImageSource", () => { + it("uses a square blog thumbnail as the social share image", () => { + const thumbnail = { + format: "png", + height: 1254, + src: "/images/hunting-web-bugs-with-jam-and-agents-icon.png", + width: 1254, + } as ImageMetadata; + + expect( + getBlogShareImageSource({ + coverImage: { + alt: "OneQuery connected to Jam", + src: thumbnail, + }, + }) + ).toBe(thumbnail); + }); +}); diff --git a/apps/landing/src/features/blog/share-image.ts b/apps/landing/src/features/blog/share-image.ts new file mode 100644 index 00000000..b5c84f87 --- /dev/null +++ b/apps/landing/src/features/blog/share-image.ts @@ -0,0 +1,5 @@ +import type { BlogPost } from "./types"; + +export function getBlogShareImageSource(post: Pick) { + return post.coverImage.src; +} diff --git a/apps/landing/src/layouts/BaseLayout.astro b/apps/landing/src/layouts/BaseLayout.astro index 880e0136..2aa6d632 100644 --- a/apps/landing/src/layouts/BaseLayout.astro +++ b/apps/landing/src/layouts/BaseLayout.astro @@ -60,6 +60,7 @@ const { robots = "index, follow, max-image-preview:large", structuredData = DEFAULT_STRUCTURED_DATA, title = DEFAULT_TITLE, + ogTitle = title, twitterTitle = title, } = Astro.props; --- @@ -87,6 +88,7 @@ const { openGraph={{ locale: "en_US", siteName: ONEQUERY.NAME, + title: ogTitle, type: ogType, }} robots={robots} diff --git a/apps/landing/src/layouts/types.ts b/apps/landing/src/layouts/types.ts index 6214667c..baf8ed8c 100644 --- a/apps/landing/src/layouts/types.ts +++ b/apps/landing/src/layouts/types.ts @@ -10,6 +10,7 @@ export interface PageMetadata { imageWidth?: number; keywords?: string | null; metaTags?: MetaTag[]; + ogTitle?: string; ogType?: "article" | "website"; robots?: string; structuredData?: StructuredData | StructuredData[] | null; diff --git a/apps/landing/src/pages/blog/[postSlug].astro b/apps/landing/src/pages/blog/[postSlug].astro index ea490e8c..582e4b8d 100644 --- a/apps/landing/src/pages/blog/[postSlug].astro +++ b/apps/landing/src/pages/blog/[postSlug].astro @@ -10,7 +10,7 @@ import { } from "@/features/blog/collection"; import { getBlogShareImage, - getPreferredBlogShareImage, + getBlogShareImageSource, } from "@/features/blog/images"; import { ONEQUERY } from "@/shared/seo/constants"; import { @@ -36,7 +36,7 @@ const { Content, headings, remarkPluginFrontmatter } = await render(entry); const post = toBlogPost(entry, { headings, remarkPluginFrontmatter }); const postSummaries = await getBlogPostSummaries(); const shareImage = await getBlogShareImage( - getPreferredBlogShareImage(post), + getBlogShareImageSource(post), Astro.site ); const canonicalUrl = createCanonicalUrl(`/blog/${post.slug}`, Astro.site); @@ -77,6 +77,7 @@ const articleMetaTags = [ imageWidth={shareImage.width} keywords={getBlogPostKeywords(post)} metaTags={articleMetaTags} + ogTitle={post.title} ogType="article" structuredData={structuredData} title={title}