diff --git a/app/[...slug]/opengraph-image.tsx b/app/[...slug]/opengraph-image.tsx new file mode 100644 index 00000000..15335d2b --- /dev/null +++ b/app/[...slug]/opengraph-image.tsx @@ -0,0 +1,107 @@ +import { ImageResponse } from "next/og" +import { getPostByPath, getAllPosts } from "@/lib/posts" + +export const contentType = "image/png" +export const size = { width: 1200, height: 630 } + +export async function generateStaticParams() { + const posts = await getAllPosts() + return posts.map((post) => ({ + slug: post.path.replace(/^\//, "").split("/"), + })) +} + +// Google Fonts から Noto Sans JP を読み込む +async function loadGoogleFont(text: string): Promise { + try { + const url = `https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&text=${encodeURIComponent(text)}` + const css = await (await fetch(url)).text() + const match = css.match(/src: url\((.+?)\) format\('woff2'\)/) + if (!match) return null + return fetch(match[1]).then((res) => res.arrayBuffer()) + } catch { + return null + } +} + +export default async function OGImage({ + params, +}: { + params: Promise<{ slug: string[] }> +}) { + const { slug } = await params + const postPath = "/" + slug.join("/") + const post = await getPostByPath(postPath) + + const title = post?.title || "jaxx2104.info" + + // タイトルに含まれる文字 + サイト名の文字でフォントを読み込む + const fontData = await loadGoogleFont(title + "jaxx2104.info") + + return new ImageResponse( + ( +
+
+
30 ? 48 : 56, + fontWeight: 700, + color: "#1a1a1a", + textAlign: "center", + lineHeight: 1.4, + maxWidth: "100%", + wordBreak: "break-word", + }} + > + {title} +
+
+ jaxx2104.info +
+
+
+ ), + { + ...size, + ...(fontData && { + fonts: [ + { + name: "Noto Sans JP", + data: fontData, + style: "normal" as const, + weight: 700 as const, + }, + ], + }), + } + ) +} diff --git a/app/[...slug]/page.tsx b/app/[...slug]/page.tsx index d298e7db..ed339fa5 100644 --- a/app/[...slug]/page.tsx +++ b/app/[...slug]/page.tsx @@ -34,7 +34,6 @@ export async function generateMetadata({ const title = `${post.title} | jaxx2104.info` const description = post.content?.split(/\n/)[0] || "" const url = `${siteUrl}${post.path}` - const imageUrl = post.thumbnail ? `${siteUrl}${post.thumbnail}` : undefined return { title, @@ -45,17 +44,11 @@ export async function generateMetadata({ url, siteName: "jaxx2104.info", type: "article", - ...(imageUrl && { - images: [{ url: imageUrl }], - }), }, twitter: { - card: imageUrl ? "summary_large_image" : "summary", + card: "summary_large_image", title, description, - ...(imageUrl && { - images: [imageUrl], - }), }, } }