From 06dc8889b5e5f85db433be80c223629f8be118f2 Mon Sep 17 00:00:00 2001
From: fullsizemalt <106900403+fullsizemalt@users.noreply.github.com>
Date: Sun, 21 Dec 2025 15:44:09 -0800
Subject: [PATCH] feat: Add Heady Versions (performances) page
- /performances page with top-rated performance leaderboard
- Added to Browse dropdown in navbar
- Updated home page CTA to feature Heady Versions
- Medal icons for top 3 performances
---
frontend/app/page.tsx | 6 +-
frontend/app/performances/page.tsx | 142 ++++++++++++++++++++++++++
frontend/components/layout/navbar.tsx | 3 +
3 files changed, 148 insertions(+), 3 deletions(-)
create mode 100644 frontend/app/performances/page.tsx
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
index 15d343d..c3458e6 100644
--- a/frontend/app/page.tsx
+++ b/frontend/app/page.tsx
@@ -86,13 +86,13 @@ export default async function Home() {
The ultimate community archive for Goose history.
- Discover shows, rate performances, and connect with fans.
+ Discover shows, rate performances, and find the heady versions.
-
+
diff --git a/frontend/app/performances/page.tsx b/frontend/app/performances/page.tsx
new file mode 100644
index 0000000..1efed07
--- /dev/null
+++ b/frontend/app/performances/page.tsx
@@ -0,0 +1,142 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Trophy, Star, Calendar, MapPin, ExternalLink } from "lucide-react"
+import Link from "next/link"
+import { getApiUrl } from "@/lib/api-config"
+
+interface TopPerformance {
+ performance: {
+ id: number
+ position: number
+ set_name: string
+ notes?: string
+ youtube_link?: string
+ }
+ song: {
+ id: number
+ title: string
+ }
+ show: {
+ id: number
+ date: string
+ }
+ venue: {
+ id: number
+ name: string
+ city: string
+ state?: string
+ }
+ avg_score: number
+ rating_count: number
+}
+
+async function getTopPerformances(): Promise {
+ try {
+ const res = await fetch(`${getApiUrl()}/leaderboards/performances/top?limit=50`, {
+ cache: 'no-store'
+ })
+ if (!res.ok) return []
+ return res.json()
+ } catch (e) {
+ console.error('Failed to fetch top performances:', e)
+ return []
+ }
+}
+
+export default async function PerformancesPage() {
+ const performances = await getTopPerformances()
+
+ return (
+
+
+
+
+ Heady Versions
+
+
+ The top-rated performances as voted by the community
+