ai-chatbot/apps/editor/app/layout.tsx
Aymeric Rabot 9a0f83a1ec
feat: SEO improvements, OG image endpoint, favicon, and metadata (#104)
- Add dynamic OG image generation endpoint (/og) adapted from monorepo
- Replace favicon with monorepo version, remove unused icon.svg
- Add seo.ts config, robots.ts, sitemap.ts for better search indexing
- Add per-page metadata (editor, viewer, settings, profile, community)
- Remove stale package-lock.json that caused ENOWORKSPACES errors with Next.js
- Add OG fonts (Geist Regular, Plus Jakarta Sans SemiBold)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-19 13:38:34 -05:00

82 lines
2.1 KiB
TypeScript

import type { Metadata } from 'next'
import localFont from 'next/font/local'
import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'
import { VercelToolbar } from '@vercel/toolbar/next'
import { UsernameGate } from '@/features/community/components/username-gate'
import { siteConfig } from './seo'
import './globals.css'
const geistSans = localFont({
src: './fonts/GeistVF.woff',
variable: '--font-geist-sans',
})
const geistMono = localFont({
src: './fonts/GeistMonoVF.woff',
variable: '--font-geist-mono',
})
export const metadata: Metadata = {
metadataBase: new URL(siteConfig.url),
title: {
default: siteConfig.name,
template: '%s | Pascal Editor',
},
description: siteConfig.description,
applicationName: siteConfig.name,
keywords: [...siteConfig.keywords],
authors: [{ name: 'Pascal', url: 'https://pascal.app' }],
creator: 'Pascal',
publisher: 'Pascal',
alternates: {
canonical: '/',
},
icons: [{ rel: 'icon', url: '/favicon.ico' }],
openGraph: {
title: siteConfig.name,
description: siteConfig.description,
url: siteConfig.url,
siteName: siteConfig.name,
images: [{ url: siteConfig.ogImage, alt: 'Pascal Editor' }],
locale: 'en_US',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: siteConfig.name,
description: siteConfig.description,
creator: siteConfig.twitterHandle,
images: [siteConfig.ogImage],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-image-preview': 'large',
'max-snippet': -1,
'max-video-preview': -1,
},
},
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
const shouldShowToolbar = process.env.NODE_ENV === 'development'
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
<UsernameGate>{children}</UsernameGate>
<Analytics />
<SpeedInsights />
{shouldShowToolbar && <VercelToolbar />}
</body>
</html>
)
}