(Feat) Init WebSite
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
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";
|
||||
|
||||
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: "https://highlandgamesstudio.com",
|
||||
},
|
||||
url: `https://highlandgamesstudio.com/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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import type { Metadata } from "next";
|
||||
import { games } from "@/lib/games";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Games",
|
||||
description: "Games crafted by Highland Games Studio.",
|
||||
};
|
||||
|
||||
const statusLabel: Record<string, string> = {
|
||||
"in-development": "IN DEVELOPMENT",
|
||||
released: "RELEASED",
|
||||
"coming-soon": "COMING SOON",
|
||||
};
|
||||
|
||||
export default function GamesPage() {
|
||||
return (
|
||||
<div className="pt-32 pb-24 px-6 lg:px-10">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<p className="font-display text-sm tracking-[0.3em] text-accent mb-4">
|
||||
— OUR WORLDS
|
||||
</p>
|
||||
<h1 className="font-display text-5xl sm:text-6xl lg:text-7xl tracking-wider leading-[0.95] mb-16">
|
||||
GAMES
|
||||
</h1>
|
||||
|
||||
<div className="grid gap-8">
|
||||
{games.map((game) => (
|
||||
<Link
|
||||
key={game.slug}
|
||||
href={`/games/${game.slug}`}
|
||||
className="group relative aspect-[16/9] sm:aspect-[21/9] bg-surface border border-border overflow-hidden block hover:border-accent transition-colors"
|
||||
>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Image
|
||||
src="/image/Studio/Logo Flat.png"
|
||||
alt=""
|
||||
width={140}
|
||||
height={94}
|
||||
className="opacity-15 group-hover:opacity-25 group-hover:scale-105 transition-all duration-700"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-8 bg-gradient-to-t from-background via-background/80 to-transparent">
|
||||
<p className="font-display text-xs tracking-[0.3em] text-accent mb-2">
|
||||
{statusLabel[game.status]}
|
||||
</p>
|
||||
<h2 className="font-display text-3xl sm:text-4xl tracking-wider mb-3">
|
||||
{game.title.toUpperCase()}
|
||||
</h2>
|
||||
<p className="text-foreground-muted max-w-2xl">
|
||||
{game.tagline}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user