The link preview used an old template with a blog description. The share image is now a screenshot of the real hero (scripts/render-share-image.mjs), served as Open Graph and Twitter image. Title and description come from one place and are used by the page, the previews and the structured data. Adds an apple touch icon and removes the old share-image template and its fonts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
1.9 KiB
TypeScript
78 lines
1.9 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { Inter, JetBrains_Mono, Newsreader } from "next/font/google";
|
|
import { Analytics } from "@/src/components/Analytics";
|
|
import { Footer } from "@/src/components/Footer";
|
|
import { Header } from "@/src/components/Header";
|
|
import { InteractiveElements } from "@/src/components/InteractiveElements";
|
|
import {
|
|
SITE_DESCRIPTION,
|
|
SITE_NAME,
|
|
SITE_TITLE,
|
|
SITE_URL,
|
|
} from "@/src/content/site";
|
|
import "./globals.css";
|
|
|
|
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
|
|
const jetbrainsMono = JetBrains_Mono({
|
|
subsets: ["latin"],
|
|
variable: "--font-jetbrains-mono",
|
|
display: "swap",
|
|
});
|
|
const newsreader = Newsreader({
|
|
subsets: ["latin"],
|
|
variable: "--font-newsreader",
|
|
style: "italic",
|
|
display: "swap",
|
|
});
|
|
|
|
export const metadata: Metadata = {
|
|
metadataBase: new URL(SITE_URL),
|
|
title: {
|
|
default: SITE_TITLE,
|
|
template: `%s | ${SITE_NAME}`,
|
|
},
|
|
description: SITE_DESCRIPTION,
|
|
applicationName: SITE_NAME,
|
|
authors: [{ name: SITE_NAME, url: SITE_URL }],
|
|
creator: SITE_NAME,
|
|
icons: {
|
|
icon: "/favicon.svg",
|
|
apple: "/apple-touch-icon.png",
|
|
},
|
|
// The images come from opengraph-image.png and twitter-image.png next to this file.
|
|
openGraph: {
|
|
type: "website",
|
|
url: "/",
|
|
siteName: SITE_NAME,
|
|
locale: "en_US",
|
|
title: SITE_TITLE,
|
|
description: SITE_DESCRIPTION,
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: SITE_TITLE,
|
|
description: SITE_DESCRIPTION,
|
|
},
|
|
};
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<html
|
|
lang="en"
|
|
className={`${inter.variable} ${newsreader.variable} ${jetbrainsMono.variable}`}
|
|
>
|
|
<body className="min-h-screen bg-white">
|
|
<Header />
|
|
<main>{children}</main>
|
|
<Footer />
|
|
<InteractiveElements />
|
|
<Analytics />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|