From f03411a8be501f3f192d240a93375aa6371756fc Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Sat, 9 May 2026 23:01:26 +0800 Subject: [PATCH] feat: mobile hero background with gradient overlay on game details page --- app/game/[id]/game-page-client.tsx | 565 +++++++++++++++++------------ 1 file changed, 326 insertions(+), 239 deletions(-) diff --git a/app/game/[id]/game-page-client.tsx b/app/game/[id]/game-page-client.tsx index dbd157a..8c10444 100644 --- a/app/game/[id]/game-page-client.tsx +++ b/app/game/[id]/game-page-client.tsx @@ -252,6 +252,278 @@ function generatePresetName(preset: Preset): string { return parts.join(" · ") } +function HeroInfo({ + game, + stats, + session, + counts, + coverImage, + imgError, + handleImgError, + platformSupport, + protonDbUrl, + steamDbUrl, + gameId, + formatDate, + Badge, +}: { + game: Game + stats: StatsResponse | null + session: { user?: { id?: string } } | null + counts: Counts + coverImage: string | null + imgError: boolean + handleImgError: () => void + platformSupport: PlatformSupport[] + protonDbUrl: string | null + steamDbUrl: string | null + gameId: string + formatDate: (value: string | null) => string + Badge: React.ComponentType<{ icon: React.ElementType; value: number; label: string }> +}) { + return ( + <> + {/* Title row */} +
+

+ {game.title} +

+ {stats?.isRawPerformer && ( + + + Raw Performer + + )} + {stats?.isPoorPerformance && ( + + ⚠ Poor Performance + + )} + + {/* Playability badge */} + {game.playabilityStatus && ( + + )} + + {/* Anti-cheat badge */} + {platformSupport?.some((p) => p.antiCheatRelevant) && ( + p.antiCheatRelevant)?.antiCheatStatus ?? "unknown" + } + antiCheatName={ + platformSupport.find((p) => p.antiCheatRelevant)?.antiCheatName + } + /> + )} + + {/* Steam review score */} + {game.steamReviewScore != null && ( + + + + + {game.steamReviewScore}% Positive + {game.steamReviewSentiment && ( + ({game.steamReviewSentiment.replace(/_/g, ' ')}) + )} + + )} +
+ + {/* Subtitle */} +
+ {game.developer && {game.developer}} + {game.developer && game.publisher && ( + · + )} + {game.publisher && {game.publisher}} + {game.genres && game.genres.length > 0 && ( + <> + · + + {game.genres.slice(0, 3).join(", ")} + + + )} +
+ + {/* Stats badges */} +
+ + + + {game.metascore !== undefined && + game.metascore !== null && ( + + ★ {game.metascore} + + )} +
+ + {/* Metadata pills */} +
+ {game.releaseDate && ( + + {game.releaseDate} + + )} + {game.isFree && ( + + Free to Play + + )} + {game.priceCurrent != null && !game.isFree && game.priceCurrency && ( + + {new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceCurrent / 100)} + + )} + {game.priceCurrent != null && !game.isFree && game.priceInitial != null && game.priceInitial > game.priceCurrent && game.priceCurrency && ( + + {new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceInitial / 100)} + + )} + {game.metacriticScore != null && ( + + ★ {game.metacriticScore}/100 + + )} + {game.onlineMultiplayerStatus && ( + + {game.onlineMultiplayerStatus} + + )} + {game.platforms && ( + + {game.platforms.windows && } + {game.platforms.mac && } + {game.platforms.linux && } + + )} + {game.steamAppId !== null && ( + + AppID {game.steamAppId} + + )} +
+ + {/* External links */} +
+ {game.storeUrl && ( + + + Steam + + + )} + {protonDbUrl && ( + + ProtonDB + + + )} + {steamDbUrl && ( + + SteamDB + + + )} +
+ + {/* DB stats row */} + {stats && ( +
+ + + {stats.summary.versionCount} versions + + · + + + {stats.summary.verifiedCount} verified + + {game.lastSync && ( + <> + · + + + Last sync{" "} + {formatDate(game.lastSync)} + + + )} +
+ )} + {stats && ( +
+ + {session?.user && game.source !== "steam" && ( + + + Edit Game + + )} + {session && ( + + + Add Benchmark + + )} + {game.source !== "steam" && ( + + )} +
+ )} + + ) +} + export function GamePageClient({ game, counts, @@ -460,7 +732,45 @@ export function GamePageClient({ transition={{ duration: 0.4 }} className='px-4 md:px-[10svw] pt-6' > -
+ {/* Mobile hero — full-bleed background */} +
+ {coverImage && !imgError ? ( +
+ +
+
+ ) : ( +
+ )} +
+ +
+
+ + {/* Desktop hero — side-by-side layout */} +
{/* Cover image */}
{coverImage && !imgError ? ( @@ -480,246 +790,23 @@ export function GamePageClient({
)}
- {/* Info */}
- {/* Title row */} -
-

- {game.title} -

- {stats?.isRawPerformer && ( - - - Raw Performer - - )} - {stats?.isPoorPerformance && ( - - ⚠ Poor Performance - - )} - - {/* Playability badge */} - {game.playabilityStatus && ( - - )} - - {/* Anti-cheat badge */} - {platformSupport?.some((p) => p.antiCheatRelevant) && ( - p.antiCheatRelevant)?.antiCheatStatus ?? "unknown" - } - antiCheatName={ - platformSupport.find((p) => p.antiCheatRelevant)?.antiCheatName - } - /> - )} - - {/* Steam review score */} - {game.steamReviewScore != null && ( - - - - - {game.steamReviewScore}% Positive - {game.steamReviewSentiment && ( - ({game.steamReviewSentiment.replace(/_/g, ' ')}) - )} - - )} -
- - {/* Subtitle */} -
- {game.developer && {game.developer}} - {game.developer && game.publisher && ( - · - )} - {game.publisher && {game.publisher}} - {game.genres && game.genres.length > 0 && ( - <> - · - - {game.genres.slice(0, 3).join(", ")} - - - )} -
- - {/* Stats badges */} -
- - - - {game.metascore !== undefined && - game.metascore !== null && ( - - ★ {game.metascore} - - )} -
- - {/* Metadata pills */} -
- {game.releaseDate && ( - - {game.releaseDate} - - )} - {game.isFree && ( - - Free to Play - - )} - {game.priceCurrent != null && !game.isFree && game.priceCurrency && ( - - {new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceCurrent / 100)} - - )} - {game.priceCurrent != null && !game.isFree && game.priceInitial != null && game.priceInitial > game.priceCurrent && game.priceCurrency && ( - - {new Intl.NumberFormat("en-US", { style: "currency", currency: game.priceCurrency }).format(game.priceInitial / 100)} - - )} - {game.metacriticScore != null && ( - - ★ {game.metacriticScore}/100 - - )} - {game.onlineMultiplayerStatus && ( - - {game.onlineMultiplayerStatus} - - )} - {game.platforms && ( - - {game.platforms.windows && } - {game.platforms.mac && } - {game.platforms.linux && } - - )} - {game.steamAppId !== null && ( - - AppID {game.steamAppId} - - )} -
- - {/* External links */} -
- {game.storeUrl && ( - - - Steam - - - )} - {protonDbUrl && ( - - ProtonDB - - - )} - {steamDbUrl && ( - - SteamDB - - - )} -
- - {/* DB stats row */} - {stats && ( -
- - - {stats.summary.versionCount} versions - - · - - - {stats.summary.verifiedCount} verified - - {game.lastSync && ( - <> - · - - - Last sync{" "} - {formatDate(game.lastSync)} - - - )} -
- )} - {stats && ( -
- - {session?.user && game.source !== "steam" && ( - - - Edit Game - - )} - {session && ( - - - Add Benchmark - - )} - {game.source !== "steam" && ( - - )} -
- )} +