Files
highland_games_website/app/games/[slug]/page.tsx
T
Mathew 0c88206a23
Deploy to VPS / deploy (push) Has been cancelled
(Update) Update projet + todo
2026-06-22 23:32:18 +02:00

199 lines
6.5 KiB
TypeScript

import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { games, getGame } from "@/lib/games";
import { getPostsByGame } from "@/lib/devblog";
import { SITE_URL } from "@/lib/site";
function formatDate(date: string) {
return new Date(date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
}
type Props = { params: Promise<{ slug: string }> };
export function generateStaticParams() {
return games.map((g) => ({ slug: g.slug }));
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const game = getGame(slug);
if (!game) return {};
return {
title: game.title,
description: game.tagline,
};
}
const statusLabel: Record<string, string> = {
"in-development": "IN DEVELOPMENT",
released: "RELEASED",
"coming-soon": "COMING SOON",
};
export default async function GamePage({ params }: Props) {
const { slug } = await params;
const game = getGame(slug);
if (!game) notFound();
const relatedPosts = getPostsByGame(slug).slice(0, 3);
const jsonLd = {
"@context": "https://schema.org",
"@type": "VideoGame",
name: game.title,
description: game.description,
genre: game.genres,
publisher: {
"@type": "Organization",
name: "Highland Games Studio",
url: SITE_URL,
},
url: `${SITE_URL}/games/${game.slug}`,
};
return (
<article className="pt-24 pb-24">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* HERO */}
<section className="relative aspect-[21/9] sm:aspect-[21/8] bg-surface border-b border-border overflow-hidden">
<div className="absolute inset-0 flex items-center justify-center">
<Image
src="/image/Studio/Logo Flat.png"
alt=""
width={220}
height={148}
className="opacity-20"
/>
</div>
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/40 to-transparent" />
<div className="absolute bottom-0 left-0 right-0 px-6 lg:px-10 pb-10">
<div className="max-w-6xl mx-auto">
<p className="font-display text-xs tracking-[0.3em] text-accent mb-2">
{statusLabel[game.status]}
</p>
<h1 className="font-display text-5xl sm:text-7xl lg:text-8xl tracking-wider leading-[0.95]">
{game.title.toUpperCase()}
</h1>
<p className="mt-4 text-lg sm:text-xl text-foreground-muted max-w-2xl">
{game.tagline}
</p>
{game.steamUrl && (
<a
href={game.steamUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-block mt-6 px-8 py-3 bg-accent text-background font-display tracking-widest text-sm hover:bg-foreground hover:scale-[1.03] transition duration-200"
>
WISHLIST ON STEAM
</a>
)}
</div>
</div>
</section>
{/* CONTENT */}
<div className="max-w-6xl mx-auto px-6 lg:px-10 mt-16 grid lg:grid-cols-3 gap-12">
<div className="lg:col-span-2">
<h2 className="font-display text-3xl tracking-wider mb-6">ABOUT</h2>
<p className="text-foreground-muted leading-relaxed text-lg">
{game.description}
</p>
</div>
<aside className="space-y-8">
<div>
<h3 className="font-display text-xs tracking-[0.3em] text-accent mb-3">
GENRES
</h3>
<div className="flex flex-wrap gap-2">
{game.genres.map((g) => (
<span
key={g}
className="text-xs tracking-widest uppercase border border-border px-3 py-1.5"
>
{g}
</span>
))}
</div>
</div>
{game.releaseWindow && (
<div>
<h3 className="font-display text-xs tracking-[0.3em] text-accent mb-3">
RELEASE
</h3>
<p className="text-foreground">{game.releaseWindow}</p>
</div>
)}
{game.steamUrl && (
<Link
href={game.steamUrl}
className="block px-6 py-3 bg-accent text-background font-display tracking-widest text-sm text-center hover:bg-foreground hover:scale-[1.03] transition duration-200"
>
WISHLIST ON STEAM
</Link>
)}
</aside>
</div>
{relatedPosts.length > 0 && (
<section className="max-w-6xl mx-auto px-6 lg:px-10 mt-24">
<div className="flex items-baseline justify-between mb-8">
<div>
<p className="font-display text-xs tracking-[0.3em] text-accent mb-2">
DEVBLOG
</p>
<h2 className="font-display text-3xl sm:text-4xl tracking-wider">
LATEST ARTICLES
</h2>
</div>
<Link
href="/devblog"
className="hidden sm:inline-block font-display text-xs tracking-widest text-foreground-muted hover:text-accent transition-colors"
>
ALL POSTS
</Link>
</div>
<div className="space-y-1">
{relatedPosts.map((post) => (
<Link
key={post.slug}
href={`/devblog/${post.slug}`}
className="group block py-6 border-t border-border hover:border-accent transition-colors"
>
<div className="flex flex-col sm:flex-row sm:items-baseline sm:justify-between gap-2 mb-2">
<h3 className="font-display text-xl sm:text-2xl tracking-wider group-hover:text-accent transition-colors">
{post.title.toUpperCase()}
</h3>
<time
dateTime={post.date}
className="text-xs tracking-widest text-foreground-muted shrink-0"
>
{formatDate(post.date)}
</time>
</div>
{post.excerpt && (
<p className="text-foreground-muted leading-relaxed max-w-2xl">
{post.excerpt}
</p>
)}
</Link>
))}
</div>
</section>
)}
</article>
);
}