Add Open Graph preview image (1200x630 card) site-wide

Shared voxvera.org links now render a real image card, not just a text
summary. Adds site/og-card.jpg (1200x630, ~90KB, derived from the
"say something… voxvera.org" custom art) and wires og:image +
twitter:image + image dimensions/alt on the home, board, and safety
pages, bumping twitter:card to summary_large_image.

Per-flyer previews remain out of scope (fragment URLs are invisible to
servers; this stays a purely static site). Test asserts all three pages
declare the og:image and that the asset is served as JPEG. Full suite
378 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-11 22:27:03 -04:00
1 parent 18fa382632
commit 6fe9069f82
6 files changed
+39 -9

No files matched your search

+7 -6
View File
@@ -315,12 +315,13 @@ should follow the board's trust model.
disposable keys, signer apps). Linked from the editor and the board. Aimed at
the activist/whistleblower audience the aesthetic invites — being honest about
limits matters more than any feature.
- **Link previews / Open Graph — partial, by design.** Static site-wide OG +
Twitter-card meta are on the home, board, and safety pages, so a shared
`voxvera.org` link renders a real title/description instead of nothing.
**Per-flyer previews are a deliberate non-goal:** the poster `naddr` lives in
the URL `#fragment` (invisible to servers), and a static host can't render
per-flyer `<meta>` without server-side code — which is out of scope by choice
- **Link previews / Open Graph — shipped (site-wide).** Static OG +
Twitter-card meta are on the home, board, and safety pages, including a
**1200×630 preview image** (`site/og-card.jpg`, `summary_large_image`), so a
shared `voxvera.org` link renders a real title, description, and image card.
**Per-flyer previews remain a deliberate non-goal:** the poster `naddr` lives
in the URL `#fragment` (invisible to servers), and a static host can't render
per-flyer `<meta>`/image without server-side code — out of scope by choice
(this stays a free, purely static site). Revisit only if that constraint ever
changes.
- **Publish transparency — ✅ done.** The publish confirmation modal now reports
+14
View File
@@ -121,6 +121,20 @@ test.describe("VoxVera static client", () => {
expect(await res.text()).toContain("<svg");
});
test("all pages declare the Open Graph preview image, and it is served", async ({ page }) => {
for (const path of ["/", "/board.html", "/safety.html"]) {
await page.goto(path);
const ogImage = await page.locator('meta[property="og:image"]').getAttribute("content");
expect(ogImage, `${path} og:image`).toBe("https://voxvera.org/og-card.jpg");
const twCard = await page.locator('meta[name="twitter:card"]').getAttribute("content");
expect(twCard, `${path} twitter:card`).toBe("summary_large_image");
}
// The card asset itself is served and is a JPEG.
const res = await page.request.get("/og-card.jpg");
expect(res.status()).toBe(200);
expect(res.headers()["content-type"] || "").toContain("jpeg");
});
test("print media hides app chrome and keeps the flyer", async ({ page }, testInfo) => {
await page.goto("/");
await page.emulateMedia({ media: "print" });
+6 -1
View File
@@ -15,9 +15,14 @@
<meta property="og:title" content="VoxVera — Bulletin Board">
<meta property="og:description" content="Recent VoxVera flyers published to the Nostr relays, filtered by your web of trust.">
<meta property="og:url" content="https://voxvera.org/board">
<meta name="twitter:card" content="summary">
<meta property="og:image" content="https://voxvera.org/og-card.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="VoxVera — say something. voxvera.org">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="VoxVera — Bulletin Board">
<meta name="twitter:description" content="Recent VoxVera flyers published to the Nostr relays, filtered by your web of trust.">
<meta name="twitter:image" content="https://voxvera.org/og-card.jpg">
</head>
<body class="board-page">
<header class="topbar">
+6 -1
View File
@@ -12,9 +12,14 @@
<meta property="og:title" content="VoxVera — printable, censorship-resistant flyers">
<meta property="og:description" content="Create printable flyers backed by decentralized Nostr events. Anonymous by default, and no single host can quietly take them down.">
<meta property="og:url" content="https://voxvera.org/">
<meta name="twitter:card" content="summary">
<meta property="og:image" content="https://voxvera.org/og-card.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="VoxVera — say something. voxvera.org">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="VoxVera — printable, censorship-resistant flyers">
<meta name="twitter:description" content="Create printable flyers backed by decentralized Nostr events. Anonymous by default, and no single host can quietly take them down.">
<meta name="twitter:image" content="https://voxvera.org/og-card.jpg">
</head>
<body>
<header class="topbar">
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

+6 -1
View File
@@ -14,9 +14,14 @@
<meta property="og:title" content="VoxVera — Safety & privacy">
<meta property="og:description" content="What VoxVera protects, what it does not, and how to stay safer when publishing flyers.">
<meta property="og:url" content="https://voxvera.org/safety">
<meta name="twitter:card" content="summary">
<meta property="og:image" content="https://voxvera.org/og-card.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="VoxVera — say something. voxvera.org">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="VoxVera — Safety & privacy">
<meta name="twitter:description" content="What VoxVera protects, what it does not, and how to stay safer when publishing flyers.">
<meta name="twitter:image" content="https://voxvera.org/og-card.jpg">
</head>
<body class="safety-page">
<header class="topbar">