Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion sites/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"check:types": "astro check"
"check:types": "astro check",
"og": "node scripts/generate-og.mjs"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
Expand All @@ -27,6 +28,7 @@
"typescript": "^6.0.3"
},
"devDependencies": {
"@resvg/resvg-js": "^2.6.2",
"@types/react": "^19.2.16",
"@types/react-dom": "^19.2.3"
}
Expand Down
Binary file added sites/web/public/og.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions sites/web/public/og.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions sites/web/scripts/generate-og.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Rasterizes public/og.svg into public/og.png.
//
// Why this exists: SVG is not a valid Open Graph image format. Reddit,
// X/Twitter, Facebook, LinkedIn, Slack, Discord and iMessage all ignore an
// `og:image` that points at an SVG and fall back to a generic placeholder, so
// shared links show no preview. og.svg stays the editable source of truth and
// this script bakes it into the PNG that the meta tags actually reference.
//
// Fonts are vendored as TTFs (scripts/og-fonts) and loaded explicitly so the
// render is deterministic and on-brand (Geist + Fira Code) regardless of which
// fonts the build machine happens to have installed — resvg renders no text at
// all when it cannot resolve a font.
//
// Run after editing og.svg: pnpm --filter web og

import { readFileSync, readdirSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { Resvg } from '@resvg/resvg-js'

const here = dirname(fileURLToPath(import.meta.url))
const publicDir = join(here, '..', 'public')
const fontsDir = join(here, 'og-fonts')

const svg = readFileSync(join(publicDir, 'og.svg'), 'utf8')
const fontFiles = readdirSync(fontsDir)
.filter((f) => f.endsWith('.ttf'))
.map((f) => join(fontsDir, f))

const resvg = new Resvg(svg, {
// The SVG already declares width/height 1200x630; honor it 1:1.
fitTo: { mode: 'width', value: 1200 },
font: {
fontFiles,
loadSystemFonts: false,
defaultFontFamily: 'Geist',
},
})

const png = resvg.render().asPng()
const out = join(publicDir, 'og.png')
writeFileSync(out, png)

console.log(`Wrote ${out} (${png.length} bytes)`)
Binary file added sites/web/scripts/og-fonts/FiraCode-Regular.ttf
Binary file not shown.
Binary file added sites/web/scripts/og-fonts/Geist-Medium.ttf
Binary file not shown.
Binary file added sites/web/scripts/og-fonts/Geist-Regular.ttf
Binary file not shown.
10 changes: 9 additions & 1 deletion sites/web/src/layouts/Base.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ interface Props {
const {
title = 'react-call — your component can await',
description = 'createCallable turns any React component into something you can await. Dialogs, toasts, pickers, menus — any UI that conceptually returns a value to its caller.',
image = '/og.svg',
// Must be a raster format: Reddit, X, Facebook, LinkedIn, Slack, Discord and
// iMessage all ignore an SVG og:image. og.png is generated from og.svg via
// `pnpm --filter web og` — see sites/web/scripts/generate-og.mjs.
image = '/og.png',
type = 'website',
noindex = false,
} = Astro.props
Expand Down Expand Up @@ -57,13 +60,18 @@ const imageUrl = new URL(image, site).href
<meta property="og:description" content={description} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={imageUrl} />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content={title} />
<meta property="og:locale" content="en_US" />

<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={imageUrl} />
<meta name="twitter:image:alt" content={title} />

<!-- Sitemap -->
<link rel="sitemap" href="/sitemap-index.xml" />
Expand Down
Loading