15 — Components
Club Directory
Filterable club directory with conference grouping, crest logos, record stats, and points. Data-source agnostic — drop in a static array or wire to Airtable with no component changes.
1 — ClubDirectory — Live Component
Fully interactive — filter by conference. Auto-sorted by points (W×3 + D×1) descending. 10 clubs across NC and SC.
10CLUBS· sorted by points
tsx
import { ClubDirectory } from "@/components/cpsl/clubs"
import { CLUBS } from "@/lib/clubs"
// Static data — swap for an Airtable fetch with no component changes:
// const clubs = await fetchClubsFromAirtable()
<ClubDirectory clubs={CLUBS} onClubClick={(club) => router.push(`/clubs/${club.id}`)} />2 — ClubCard — All Variants
Conference determines the left accent colour and badge — blue for East, crimson for West. Pass onClick to enable hover state and pointer cursor.
East Conference
West Conference
tsx
import { ClubCard } from "@/components/cpsl/clubs"
<ClubCard
club={{
id: "charlotte-fc",
name: "Charlotte FC",
location: "Charlotte, NC",
logoSlug: "charlotte-fc", // → /public/logos/charlotte-fc.svg
conference: "East",
record: { wins: 12, draws: 3, losses: 2 },
director: "Marcus Webb",
}}
onClick={() => router.push("/clubs/charlotte-fc")}
/>3 — Component API
Club (data shape)
interface Club {
id: string
name: string
location: string
logoSlug: string // /public/logos/{slug}.svg
conference: "East" | "West"
record: {
wins: number
draws: number
losses: number
}
director: string
}ClubDirectory props
<ClubDirectory
clubs={Club[]} // any Club array
onClubClick={(club) => {}} // optional
/>
// Built-in:
// Filter: ALL / EAST / WEST
// Sort: pts desc (W×3 + D×1)ClubCard props
<ClubCard
club={Club}
onClick={() => {}} // enables hover + pointer
/>Logo convention
// Logos live in /public/logos/ // Named after club.logoSlug: // "charlotte-fc" → /logos/charlotte-fc.svg // "durham-united" → /logos/durham-united.svg // // Airtable: store logoSlug as a text field. // Keep SVGs in /public/logos/ alongside code. // Never store logos as Airtable attachments // (URLs expire every few hours).