feat: replace the marketing site's Open Graph and Twitter card with a top-left 1.91:1 crop of the new dashboard export, and derive og:image type, width and height from the real image so blog covers stop declaring 1280x640 jpeg

This commit is contained in:
Matthew Meszaros
2026-09-19 18:45:55 +02:00
parent d8a3e70450
commit d855abfaa3
4 changed files with 24 additions and 8 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

After

Width:  |  Height:  |  Size: 304 KiB

+3 -2
View File
@@ -9,8 +9,9 @@
* web-app-manifest-192x192.png
* web-app-manifest-512x512.png
*
* The 1200x600 OG / Twitter card (public/og-image.jpg) is exported from the
* Figma Branding file (the "Social" frame), not generated here.
* The 1920x1008 OG / Twitter card (public/og-image.jpg) is a top-left crop of
* the 1920x1080 Figma "Social" frame export, not generated here. The crop is
* to 1.91:1 (1200x630 x1.6), so the frame's top-left never gets cut.
*
* Run with: node scripts/gen-icons.mjs
*/
+3 -1
View File
@@ -22,6 +22,8 @@ const canonical = new URL(Astro.url.pathname, Astro.site ?? 'https://warmbly.com
// Per-post social/share image: use the post cover when set, else the site card.
const shareImage = cover ?? '/og-image.jpg';
const shareImageAbsolute = new URL(shareImage, Astro.site ?? 'https://warmbly.com').toString();
// Covers in public/blog are all exported at 1200x600; the site card is 1920x1008.
const shareImageSize = cover ? { w: 1200, h: 600 } : { w: 1920, h: 1008 };
const articleJsonLd = {
'@context': 'https://schema.org',
@@ -61,7 +63,7 @@ const neighbors = [
next ? { label: 'Up next', post: next } : null,
].filter(Boolean) as { label: string; post: BlogPost }[];
---
<Layout title={`${title} | Warmbly Blog`} description={description} ogImage={shareImage} ogType="article" jsonLd={[articleJsonLd, breadcrumbJsonLd]}>
<Layout title={`${title} | Warmbly Blog`} description={description} ogImage={shareImage} ogImageWidth={shareImageSize.w} ogImageHeight={shareImageSize.h} {...(cover ? { ogImageAlt: title } : {})} ogType="article" jsonLd={[articleJsonLd, breadcrumbJsonLd]}>
<!-- TOP BAR: sticky under the site header, carries the reading progress -->
<div class="sticky top-14 z-30 bg-white/90 backdrop-blur-md border-b border-[color:var(--border)]">
<div class="container-page py-3 flex items-center justify-between text-[11.5px] font-mono">
+18 -5
View File
@@ -8,6 +8,10 @@ interface Props {
title: string;
description?: string;
ogImage?: string;
/** Real pixel size of ogImage; scrapers render the card before fetching it. */
ogImageWidth?: number;
ogImageHeight?: number;
ogImageAlt?: string;
/** og:type — 'website' for most pages, 'article' for Learn essays */
ogType?: string;
/** Extra structured data injected per-page (e.g. BlogPosting, SoftwareApplication) */
@@ -21,6 +25,9 @@ const {
title,
description = 'Warmbly is the deliverability platform for cold email. Warm your inboxes, send at scale, keep your reputation clean.',
ogImage = '/og-image.jpg',
ogImageWidth = 1920,
ogImageHeight = 1008,
ogImageAlt = 'The Warmbly dashboard, showing the unified inbox across connected mailboxes',
ogType = 'website',
jsonLd,
noIndex = false,
@@ -42,6 +49,12 @@ const posthogUiHost = import.meta.env.PUBLIC_POSTHOG_UI_HOST ?? 'https://us.post
const siteOrigin = (Astro.site ?? new URL('https://warmbly.com')).toString().replace(/\/$/, '');
const canonical = new URL(Astro.url.pathname, Astro.site ?? 'https://warmbly.com').toString();
const ogImageAbsolute = new URL(ogImage, Astro.site ?? 'https://warmbly.com').toString();
// Blog covers are .webp; declaring them as jpeg makes some scrapers skip the card.
const ogImageType = ogImage.endsWith('.webp')
? 'image/webp'
: ogImage.endsWith('.png')
? 'image/png'
: 'image/jpeg';
// Schema.org Organization payload, sourced from the real company record.
const organizationJsonLd = {
@@ -125,10 +138,10 @@ const websiteJsonLd = {
<meta property="og:locale" content="en_US" />
<meta property="og:image" content={ogImageAbsolute} />
<meta property="og:image:secure_url" content={ogImageAbsolute} />
<meta property="og:image:type" content="image/jpeg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:image:alt" content="Warmbly: the open-source cold email platform" />
<meta property="og:image:type" content={ogImageType} />
<meta property="og:image:width" content={String(ogImageWidth)} />
<meta property="og:image:height" content={String(ogImageHeight)} />
<meta property="og:image:alt" content={ogImageAlt} />
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image" />
@@ -137,7 +150,7 @@ const websiteJsonLd = {
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={ogImageAbsolute} />
<meta name="twitter:image:alt" content="Warmbly: the open-source cold email platform" />
<meta name="twitter:image:alt" content={ogImageAlt} />
<!-- Crawler hints -->
<meta name="robots" content={noIndex ? 'noindex,nofollow' : 'index,follow,max-image-preview:large,max-snippet:-1'} />