diff --git a/app/game/[id]/game-page-client.tsx b/app/game/[id]/game-page-client.tsx index 51ea5b4..da9fe77 100644 --- a/app/game/[id]/game-page-client.tsx +++ b/app/game/[id]/game-page-client.tsx @@ -3,361 +3,383 @@ import { useCallback, useState } from "react" import Image from "next/image" import { - Gamepad2Icon, - MessageSquareIcon, - SettingsIcon, - TrendingUpIcon, - ExternalLinkIcon, - ClockIcon, + Gamepad2Icon, + MessageSquareIcon, + SettingsIcon, + TrendingUpIcon, + ExternalLinkIcon, + ClockIcon, } from "lucide-react" interface Game { - id: string - steamAppId: number | null - title: string - description: string | null - developer: string | null - publisher: string | null - genres: string[] | null - headerImage: string | null - capsuleImage: string | null - storeUrl: string | null - source: string - lastSync: string | null - syncStatus: string | null - createdAt: string + id: string + steamAppId: number | null + title: string + description: string | null + developer: string | null + publisher: string | null + genres: string[] | null + headerImage: string | null + capsuleImage: string | null + storeUrl: string | null + source: string + lastSync: string | null + syncStatus: string | null + createdAt: string } interface Counts { - benchmarks: number - presets: number - comments: number + benchmarks: number + presets: number + comments: number } interface PlatformSupport { - id: string - gameId: string - hardwareSlug: string - isSupported: boolean - protonStatus: string + id: string + gameId: string + hardwareSlug: string + isSupported: boolean + protonStatus: string } const TABS = [ - { key: "overview", label: "Overview", icon: Gamepad2Icon }, - { key: "benchmarks", label: "Benchmarks", icon: TrendingUpIcon }, - { key: "presets", label: "Presets", icon: SettingsIcon }, - { key: "comments", label: "Comments", icon: MessageSquareIcon }, + { key: "overview", label: "Overview", icon: Gamepad2Icon }, + { key: "benchmarks", label: "Benchmarks", icon: TrendingUpIcon }, + { key: "presets", label: "Presets", icon: SettingsIcon }, + { key: "comments", label: "Comments", icon: MessageSquareIcon }, ] as const type TabKey = (typeof TABS)[number]["key"] export function GamePageClient({ - game, - counts, - platformSupport, + game, + counts, + platformSupport, }: { - game: Game - counts: Counts - platformSupport: PlatformSupport[] + game: Game + counts: Counts + platformSupport: PlatformSupport[] }) { - const [activeTab, setActiveTab] = useState("overview") - const [imgError, setImgError] = useState(false) - const handleImgError = useCallback(() => setImgError(true), []) + const [activeTab, setActiveTab] = useState("overview") + const [imgError, setImgError] = useState(false) + const handleImgError = useCallback(() => setImgError(true), []) - const headerImage = game.capsuleImage || game.headerImage + const headerImage = game.capsuleImage || game.headerImage - return ( -
- {/* Hero */} -
- {headerImage && !imgError ? ( - {game.title} - ) : ( -
- -
- )} -
+ return ( +
+ {/* Hero */} +
+ {headerImage && !imgError ? ( + {game.title} + ) : ( +
+ +
+ )} +
-
-
-

- {game.title} -

-
- {game.developer && {game.developer}} - {game.developer && game.publisher && ( - - )} - {game.publisher && {game.publisher}} - {game.genres && game.genres.length > 0 && ( - <> - - - {game.genres.join(", ")} - - - )} +
+
+

+ {game.title} +

+
+ {game.developer && {game.developer}} + {game.developer && game.publisher && ( + + )} + {game.publisher && {game.publisher}} + {game.genres && game.genres.length > 0 && ( + <> + + + {game.genres.join(", ")} + + + )} +
+
+
-
-
-
- {/* Stats bar */} -
-
- - - - {game.storeUrl && ( - - - Store - - )} -
-
+ {/* Stats bar */} +
+
+ + + + {game.storeUrl && ( + + + Store + + )} +
+
- {/* Tabs */} -
-
-
- {TABS.map((tab) => { - const Icon = tab.icon - const isActive = activeTab === tab.key - return ( - - ) - })} -
+ {/* Tabs */} +
+
+
+ {TABS.map((tab) => { + const Icon = tab.icon + const isActive = activeTab === tab.key + return ( + + ) + })} +
- {/* Tab content */} -
- {activeTab === "overview" && ( - - )} - {activeTab === "benchmarks" && } - {activeTab === "presets" && } - {activeTab === "comments" && } -
-
-
-
- ) + {/* Tab content */} +
+ {activeTab === "overview" && ( + + )} + {activeTab === "benchmarks" && ( + + )} + {activeTab === "presets" && ( + + )} + {activeTab === "comments" && ( + + )} +
+
+
+
+ ) } function StatBadge({ - icon: Icon, - value, - label, + icon: Icon, + value, + label, }: { - icon: React.ElementType - value: number - label: string + icon: React.ElementType + value: number + label: string }) { - return ( -
- - {value} - {label} -
- ) + return ( +
+ + {value} + {label} +
+ ) } function OverviewTab({ - game, - platformSupport, + game, + platformSupport, }: { - game: Game - platformSupport: PlatformSupport[] + game: Game + platformSupport: PlatformSupport[] }) { - return ( -
- {game.description && ( -
-

- About -

-

- {game.description} -

-
- )} - - {/* Platform Support */} - {platformSupport.length > 0 && ( -
-

- Platform Support -

-
- {platformSupport.map((ps) => ( -
- - {ps.hardwareSlug.replace(/-/g, " ")} - -
- - {ps.isSupported ? "Supported" : "Unsupported"} - - - {ps.protonStatus} - + return ( +
+ {game.description && ( +
+

+ About +

+

+ {game.description} +

-
- ))} -
-
- )} + )} - {/* Metadata */} -
-

- Details -

-
- - {game.steamAppId && ( - - )} - - {game.lastSync && ( - - )} + {/* Platform Support */} + {platformSupport.length > 0 && ( +
+

+ Platform Support +

+
+ {platformSupport.map((ps) => ( +
+ + {ps.hardwareSlug.replace(/-/g, " ")} + +
+ + {ps.isSupported + ? "Supported" + : "Unsupported"} + + + {ps.protonStatus} + +
+
+ ))} +
+
+ )} + + {/* Metadata */} +
+

+ Details +

+
+ + {game.steamAppId && ( + + )} + + {game.lastSync && ( + + )} +
+
-
-
- ) + ) } function MetaItem({ - label, - value, - icon: Icon, + label, + value, + icon: Icon, }: { - label: string - value: string - icon?: React.ElementType + label: string + value: string + icon?: React.ElementType }) { - return ( -
- - {label} - - - {Icon && } - {value} - -
- ) + return ( +
+ + {label} + + + {Icon && } + {value} + +
+ ) } function formatDate(value: string | null): string { - if (!value) return "—" - return new Date(value).toLocaleDateString() + if (!value) return "—" + return new Date(value).toLocaleDateString() } function BenchmarksTab({ count }: { count: number }) { - if (count === 0) { + if (count === 0) { + return ( +
+ +

No benchmarks yet

+
+ ) + } return ( -
- -

No benchmarks yet

-
+
+ +

+ {count} benchmark{count !== 1 ? "s" : ""} — coming soon +

+
) - } - return ( -
- -

- {count} benchmark{count !== 1 ? "s" : ""} — coming soon -

-
- ) } function PresetsTab({ count }: { count: number }) { - if (count === 0) { + if (count === 0) { + return ( +
+ +

No presets yet

+
+ ) + } return ( -
- -

No presets yet

-
+
+ +

+ {count} preset{count !== 1 ? "s" : ""} — coming soon +

+
) - } - return ( -
- -

- {count} preset{count !== 1 ? "s" : ""} — coming soon -

-
- ) } function CommentsTab({ count }: { count: number }) { - if (count === 0) { + if (count === 0) { + return ( +
+ +

No comments yet

+
+ ) + } return ( -
- -

No comments yet

-
+
+ +

+ {count} comment{count !== 1 ? "s" : ""} — coming soon +

+
) - } - return ( -
- -

- {count} comment{count !== 1 ? "s" : ""} — coming soon -

-
- ) }