返回 CodeWhale
opengraph-image.tsx
根目录 / web / app / opengraph-image.tsx
1 import { readFile } from "node:fs/promises";
2 import { join } from "node:path";
3 import { ImageResponse } from "next/og";
4 import { IDENTITY_PHRASE, OG_ALT } from "@/lib/page-meta";
5
6 export const alt = OG_ALT;
7 export const size = { width: 1200, height: 630 };
8 export const contentType = "image/png";
9
10 // Read the brand SVGs when the image is generated, never at import time. This
11 // route is prerendered at build on Node, but its module is still evaluated
12 // inside the Cloudflare Worker whenever a page regenerates, and the Workers
13 // Node shim throws on fs.readFile. A top-level read here made every ISR
14 // regeneration on the site fail with a 500 and serve its build snapshot forever.
15 async function brandSvgs(): Promise<[string, string]> {
16 const [mark, wordmark] = await Promise.all([
17 readFile(join(process.cwd(), "public/whale/rest.svg")),
18 readFile(join(process.cwd(), "public/brand/wordmark-inverted.svg")),
19 ]);
20 return [mark.toString(), wordmark.toString()];
21 }
22
23 export default async function OpengraphImage() {
24 const [markSvg, wordmarkSvg] = await brandSvgs();
25 const markDataUrl = `data:image/svg+xml;base64,${Buffer.from(markSvg).toString("base64")}`;
26 const wordmarkDataUrl = `data:image/svg+xml;base64,${Buffer.from(wordmarkSvg).toString("base64")}`;
27
28 // The ocean: navy rising into the logo's blue, the whale in the logo
29 // gradient, the inverted wordmark, and the identity phrase once — the
30 // wordmark is the name, so no second "Codewhale" heading.
31 return new ImageResponse(
32 (
33 <div
34 style={{
35 width: "100%",
36 height: "100%",
37 display: "flex",
38 flexDirection: "column",
39 alignItems: "center",
40 justifyContent: "center",
41 gap: 34,
42 backgroundImage: "linear-gradient(180deg, #0a1d48 0%, #061431 55%, #0b48bb 100%)",
43 fontFamily: "sans-serif",
44 }}
45 >
46 <img src={markDataUrl} width={240} height={240} alt="" />
47 {/* The family wordmark is 1024x160 (6.4:1). */}
48 <img src={wordmarkDataUrl} width={532} height={83} alt="Codewhale" />
49 <div style={{ display: "flex", fontSize: 30, color: "#efeeeb", marginTop: 14 }}>
50 {IDENTITY_PHRASE}
51 </div>
52 </div>
53 ),
54 { ...size },
55 );
56 }
57
57 lines Plain Text