feat(web): dynamic OG + Twitter card images via next/og
app/opengraph-image.tsx (new): - next/og ImageResponse, 1200x630 PNG - Dark #0a0a0a background + cyan #00d4ff brand wordmark + headline + install command pill + terminal cursor - Google Fonts loadGoogleFont helper for Geist 400/700 + Geist Mono 500 (runtime fetch, Cloudflare Workers compatible) - Cache-Control: public, immutable, max-age=31536000 app/twitter-image.tsx (new): - Same shape as OG with Twitter-card alt text - Inherits twitter:card=summary_large_image from layout app/layout.tsx: - metadata.alternates.languages: explicit canonical URLs for en/ko/ ja/zh so search engines pick up hreflang - metadata.openGraph.alternateLocale: ko_KR, ja_JP, zh_CN - Drop manual openGraph.images / twitter.images: file-based metadata convention now auto-emits og:image:width, og:image:height, og:image:type, twitter:image:width, twitter:image:height - metadata.robots: max-image-preview=large, max-snippet=-1 (richer SERP previews) Verified: curl /opengraph-image returns 200, content-type image/png, 1200x630 PNG body. All 4 hreflang links present in <head>.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { Metadata } from "next"
|
||||
import type { JSX, ReactNode } from "react"
|
||||
import { GeistSans } from "geist/font/sans"
|
||||
import { GeistMono } from "geist/font/mono"
|
||||
import Script from "next/script"
|
||||
@@ -32,21 +33,31 @@ export const metadata: Metadata = {
|
||||
],
|
||||
authors: [{ name: "Yeongyu Kim", url: "https://github.com/code-yeongyu" }],
|
||||
creator: "Yeongyu Kim",
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
languages: {
|
||||
en: "/",
|
||||
ko: "/ko",
|
||||
ja: "/ja",
|
||||
zh: "/zh",
|
||||
},
|
||||
},
|
||||
openGraph: {
|
||||
type: "website",
|
||||
locale: "en_US",
|
||||
alternateLocale: ["ko_KR", "ja_JP", "zh_CN"],
|
||||
url: primarySiteUrl,
|
||||
siteName: "Oh My OpenAgent",
|
||||
title: "Oh My OpenAgent — The Best Agent Harness",
|
||||
description:
|
||||
"Meet Sisyphus: The batteries-included agent that codes like you. Multi-model orchestration, Team Mode, background agents, 54+ lifecycle hooks.",
|
||||
images: [{ url: "/images/hero.webp", width: 1024, height: 683, alt: "Oh My OpenAgent" }],
|
||||
// og:image is supplied by app/opengraph-image.tsx via Next.js file-based metadata convention.
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Oh My OpenAgent — The Best Agent Harness",
|
||||
description: "Meet Sisyphus: The batteries-included agent that codes like you.",
|
||||
images: ["/images/hero.webp"],
|
||||
// twitter:image is supplied by app/twitter-image.tsx via the file-based convention.
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
@@ -54,6 +65,8 @@ export const metadata: Metadata = {
|
||||
googleBot: {
|
||||
index: true,
|
||||
follow: true,
|
||||
"max-image-preview": "large",
|
||||
"max-snippet": -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -82,7 +95,7 @@ const jsonLd = {
|
||||
const gaMeasurementId = "G-S0QJFKT46Q"
|
||||
const gaTrackedDomain = "ohmyopenagent.com"
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function RootLayout({ children }: { readonly children: ReactNode }): JSX.Element {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
|
||||
Reference in New Issue
Block a user