diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx
index 9971fb0..b7065a2 100644
--- a/apps/web/src/app/[locale]/page.tsx
+++ b/apps/web/src/app/[locale]/page.tsx
@@ -1,7 +1,28 @@
-export default function HomePage() {
+import { getGames } from "@/lib/api";
+import { HeroSection } from "@/components/home/HeroSection";
+import { LatestGames } from "@/components/home/LatestGames";
+import { DonationCTA } from "@/components/home/DonationCTA";
+
+export default async function HomePage({
+ params,
+}: {
+ params: Promise<{ locale: string }>;
+}) {
+ const { locale } = await params;
+
+ let games: any[] = [];
+ try {
+ const res = await getGames(locale);
+ games = res.data;
+ } catch {
+ // Strapi not running yet — render page without games
+ }
+
return (
-
- Project Afterlife
-
+ <>
+
+
+
+ >
);
}
diff --git a/apps/web/src/components/home/DonationCTA.tsx b/apps/web/src/components/home/DonationCTA.tsx
new file mode 100644
index 0000000..3270f46
--- /dev/null
+++ b/apps/web/src/components/home/DonationCTA.tsx
@@ -0,0 +1,23 @@
+import { useTranslations } from "next-intl";
+import Link from "next/link";
+import { useLocale } from "next-intl";
+
+export function DonationCTA() {
+ const t = useTranslations("donate");
+ const locale = useLocale();
+
+ return (
+
+
+
{t("title")}
+
{t("description")}
+
+ {t("patreon")}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/home/HeroSection.tsx b/apps/web/src/components/home/HeroSection.tsx
new file mode 100644
index 0000000..b7e5fa2
--- /dev/null
+++ b/apps/web/src/components/home/HeroSection.tsx
@@ -0,0 +1,54 @@
+"use client";
+
+import { useTranslations } from "next-intl";
+import { motion } from "framer-motion";
+import Link from "next/link";
+import { useLocale } from "next-intl";
+
+export function HeroSection() {
+ const t = useTranslations("home");
+ const locale = useLocale();
+
+ return (
+
+
+
+
+ {t("hero_title")}
+
+
+ {t("hero_subtitle")}
+
+
+
+ {t("view_all")}
+
+
+ {t("donate_cta")}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/home/LatestGames.tsx b/apps/web/src/components/home/LatestGames.tsx
new file mode 100644
index 0000000..499f73f
--- /dev/null
+++ b/apps/web/src/components/home/LatestGames.tsx
@@ -0,0 +1,34 @@
+import { useTranslations } from "next-intl";
+import Link from "next/link";
+import type { Game } from "@afterlife/shared";
+import { GameCard } from "../shared/GameCard";
+
+interface LatestGamesProps {
+ games: Game[];
+ locale: string;
+}
+
+export function LatestGames({ games, locale }: LatestGamesProps) {
+ const t = useTranslations("home");
+
+ if (games.length === 0) return null;
+
+ return (
+
+
+
{t("latest_games")}
+
+ {t("view_all")} →
+
+
+
+ {games.slice(0, 6).map((game) => (
+
+ ))}
+
+
+ );
+}
diff --git a/apps/web/src/components/shared/GameCard.tsx b/apps/web/src/components/shared/GameCard.tsx
new file mode 100644
index 0000000..c70d55e
--- /dev/null
+++ b/apps/web/src/components/shared/GameCard.tsx
@@ -0,0 +1,46 @@
+import Link from "next/link";
+import Image from "next/image";
+import type { Game } from "@afterlife/shared";
+
+interface GameCardProps {
+ game: Game;
+ locale: string;
+}
+
+export function GameCard({ game, locale }: GameCardProps) {
+ const statusColors = {
+ online: "bg-green-500",
+ maintenance: "bg-yellow-500",
+ coming_soon: "bg-blue-500",
+ };
+
+ return (
+
+
+ {game.coverImage && (
+
+ )}
+
+
+
+ {game.genre}
+
+
+ {game.title}
+
+
+ {game.releaseYear} – {game.shutdownYear}
+
+
+
+
+ );
+}