feat: Add comprehensive SEO implementation

- Add robots.txt with admin/API blocking
- Add dynamic sitemap.xml with static pages and genre pages
- Implement full meta tags (Open Graph, Twitter Cards, Canonical, Alternates)
- Add SEO helper functions for domain detection and URL generation
- Add generateMetadata to all pages (homepage, about, genre, special)
- Support automatic domain detection for hoerdle.de and hördle.de
- Add SEO configuration to lib/config.ts
This commit is contained in:
Hördle Bot
2025-12-01 19:28:43 +01:00
parent 03129a5611
commit 20c8ad7eaf
10 changed files with 349 additions and 5 deletions

View File

@@ -6,6 +6,8 @@ import { PrismaClient } from '@prisma/client';
import { notFound } from 'next/navigation';
import { getLocalizedValue } from '@/lib/i18n';
import { getTranslations } from 'next-intl/server';
import { generateBaseMetadata } from '@/lib/metadata';
import type { Metadata } from 'next';
export const dynamic = 'force-dynamic';
@@ -15,6 +17,32 @@ interface PageProps {
params: Promise<{ locale: string; genre: string }>;
}
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { locale, genre } = await params;
const decodedGenre = decodeURIComponent(genre);
// Fetch genre to get localized name
const allGenres = await prisma.genre.findMany();
const currentGenre = allGenres.find(g => getLocalizedValue(g.name, locale) === decodedGenre);
if (!currentGenre || !currentGenre.active) {
return await generateBaseMetadata(locale, genre);
}
const genreName = getLocalizedValue(currentGenre.name, locale);
const genreSubtitle = getLocalizedValue(currentGenre.subtitle, locale);
const title = locale === 'de'
? `${genreName} - Hördle`
: `${genreName} - Hördle`;
const description = genreSubtitle || (locale === 'de'
? `Spiele Hördle im Genre ${genreName} und errate Songs aus kurzen Audio-Clips!`
: `Play Hördle in the ${genreName} genre and guess songs from short audio clips!`);
return await generateBaseMetadata(locale, genre, title, description);
}
export default async function GenrePage({ params }: PageProps) {
const { locale, genre } = await params;
const decodedGenre = decodeURIComponent(genre);