diff --git a/frontend/app/bands/page.tsx b/frontend/app/bands/page.tsx new file mode 100644 index 0000000..62d77a2 --- /dev/null +++ b/frontend/app/bands/page.tsx @@ -0,0 +1,21 @@ +import { Metadata } from "next" +import { BandsGrid } from "@/components/bands/bands-grid" + +export const metadata: Metadata = { + title: "Bands | Fediversion", + description: "Browse all bands in the Fediversion archive" +} + +export default function BandsPage() { + return ( +
+
+

Bands

+

+ Select a band to explore their archive of shows, songs, and performances. +

+
+ +
+ ) +} diff --git a/frontend/components/bands/bands-grid.tsx b/frontend/components/bands/bands-grid.tsx new file mode 100644 index 0000000..c62ed0c --- /dev/null +++ b/frontend/components/bands/bands-grid.tsx @@ -0,0 +1,108 @@ +"use client" + +import { useEffect, useState } from "react" +import Link from "next/link" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { getApiUrl } from "@/lib/api-config" +import { Loader2, ChevronRight, Music, Calendar, MapPin, ListMusic } from "lucide-react" + +interface Vertical { + id: number + name: string + slug: string + description: string | null + color: string | null + show_count?: number + song_count?: number + venue_count?: number +} + +export function BandsGrid() { + const [verticals, setVerticals] = useState([]) + const [loading, setLoading] = useState(true) + + useEffect(() => { + async function fetchVerticals() { + try { + const res = await fetch(`${getApiUrl()}/verticals`) + if (res.ok) { + const data = await res.json() + setVerticals(data) + } + } catch (error) { + console.error("Failed to fetch verticals", error) + } finally { + setLoading(false) + } + } + fetchVerticals() + }, []) + + if (loading) { + return ( +
+ +
+ ) + } + + return ( +
+ {verticals.map((vertical) => ( + + + +
+
+
+ {vertical.name.substring(0, 2).toUpperCase()} +
+ + {vertical.name} + +
+ +
+
+ + {vertical.description && ( +

+ {vertical.description} +

+ )} +
+ e.stopPropagation()} + > + + Shows + + e.stopPropagation()} + > + + Songs + + e.stopPropagation()} + > + + Venues + +
+
+
+ + ))} +
+ ) +} diff --git a/frontend/components/layout/navbar.tsx b/frontend/components/layout/navbar.tsx index c60b357..d261be1 100644 --- a/frontend/components/layout/navbar.tsx +++ b/frontend/components/layout/navbar.tsx @@ -17,6 +17,7 @@ import { useAuth } from "@/contexts/auth-context" import { useVertical } from "@/contexts/vertical-context" const browseLinks = [ + { href: "/bands", label: "Bands" }, { href: "/shows", label: "Shows" }, { href: "/venues", label: "Venues" }, { href: "/songs", label: "Songs" }, @@ -55,7 +56,7 @@ export function Navbar() { {browseLinks.map((link) => ( - + {link.label} ))}