// Events index — two directions. // Direction A · Calendar view (two-month grid + filter row + featured strip) // Direction B · List view (grouped by month, big rows) // // Both follow the Events stream (Pine palette anchor, Hot Pink as the // one-per-page pop). The page is Events-led, so the single pink CTA is // "Buy tickets" on Plains Songbook — the season's main ticketed action. const EI = { paper: "#FBF7EE", warmPaper: "#F5F0E2", stone: "#E8E2D3", navy: "#01234B", ink: "#1F1B2E", mute: "#6B6577", pine: "#2F7A2E", pineDeep: "#1A461A", pineForest: "#0F2E10", pineLifted: "#4FA13A", meadow: "#78BE4D", leaf: "#BFE0A5", whisper: "#EBF3DF", pink: "#EB4D86", // the Events pop yellow: "#F3CF03", council: "#45217A", artists: "#01234B", }; function EventsNav({ active = "events" }) { const items = [ { label: "What's on", stream: "events", path: "#/events", active: active === "events" }, { label: "Artists", stream: "artists", path: "#/artists" }, { label: "Programs", stream: "council", path: "#/about" }, { label: "News", stream: "news", path: "#/news" }, { label: "Visit", stream: "council", path: "#/about" }, ]; return (
Home Browse artists
); } function EventsFooter() { return ( ); } function EventsHero({ subtitle, count, mostWantedCta }) { return (
Events & Learning · {subtitle}

What's on this season.

{count} events through summer 2026 — drop-in days, classes, openings, and one ticketed concert. Everything is free or pay-what-you-can unless marked.

{/* THE one Hot Pink pop CTA */} {mostWantedCta} Add to calendar (.ics)
); } function FilterBar() { const filterKinds = [ { label: "All", count: 14, active: true }, { label: "Drop-in", count: 6 }, { label: "Class", count: 3 }, { label: "Talk", count: 2 }, { label: "Ticketed", count: 2 }, { label: "Opening", count: 1 }, ]; return (
Search
Search by title or venue…
Showing May – Jul 2026 Change
Kind
{filterKinds.map((f) => ( {f.label} {f.count} ))}
); } // ════════════════════════════════════════════════════════════════ // Direction A — Calendar (two months side by side) // ════════════════════════════════════════════════════════════════ function EventsIndexA() { return (
{/* Toggle: Calendar / List */}
14 events · 2 ticketed · 1 series
{/* Two-month grid */}
{/* Legend */}
{Object.entries(KIND_STYLE).map(([k, s]) => ( {s.label} ))} Featured · ticketed
{/* Highlighted upcoming strip — featured + next two */}

Coming up this season

Subscribe to the calendar
e.id === "songbook")} /> e.id === "spring-os")} /> e.id === "qw-party")} />
); } function ViewToggle({ active }) { return (
{[ { id: "calendar", label: "Calendar" }, { id: "list", label: "List" }, ].map((v) => ( {v.label} ))}
); } // Manually laid out — May 1 = Friday (col 5, week 1), Jun 1 = Monday (col 1) // 0-indexed cols: Sun=0 Mon=1 Tue=2 Wed=3 Thu=4 Fri=5 Sat=6 const MAY_2026 = [ [null,null,null,null,null,1,2], [3,4,5,6,7,8,9], [10,11,12,13,14,15,16], [17,18,19,20,21,22,23], [24,25,26,27,28,29,30], [31,null,null,null,null,null,null], ]; const JUN_2026 = [ [null,1,2,3,4,5,6], [7,8,9,10,11,12,13], [14,15,16,17,18,19,20], [21,22,23,24,25,26,27], [28,29,30,null,null,null,null], [null,null,null,null,null,null,null], ]; function CalendarMonth({ name, days }) { const [monthName, year] = name.split(" "); const monthNum = ["January","February","March","April","May","June","July","August","September","October","November","December"].indexOf(monthName) + 1; const monthIso = `${year}-${String(monthNum).padStart(2, "0")}`; const headerLabels = ["S", "M", "T", "W", "T", "F", "S"]; return (

{monthName} {year}

{/* Weekday header */}
{headerLabels.map((l, i) => (
{l}
))}
{/* Day cells */}
{days.flat().map((d, i) => ( ))}
); } function CalendarCell({ day, iso }) { const events = iso ? (EVENTS_BY_DATE[iso] || []) : []; if (!day) { return
; } return (
{day}
{events.slice(0, 2).map((e) => { const s = KIND_STYLE[e.kind]; const featured = e.featured && e.kind === "ticketed"; return (
{e.title}
); })} {events.length > 2 && (
+{events.length - 2} more
)}
); } function FeaturedEventCard({ event }) { if (!event) return null; const d = shortDate(event.date); return (
Featured · {KIND_STYLE[event.kind].label}
{d.day}
{d.mo} · {event.weekday}

{event.title}

{event.short}

When {event.time} · Where {event.venue}
Buy tickets
); } function CompactEventCard({ event }) { if (!event) return null; const d = shortDate(event.date); const s = KIND_STYLE[event.kind]; return (
{s.label}
{d.day}
{d.mo} · {event.weekday}

{event.title}

{event.short}

{event.cost} Details
); } // ════════════════════════════════════════════════════════════════ // Direction B — List (grouped by month, big rows) // ════════════════════════════════════════════════════════════════ function EventsIndexB() { const byMonth = {}; EVENTS.forEach(e => { const d = shortDate(e.date); const key = `${d.monthFull} ${d.year}`; (byMonth[key] = byMonth[key] || []).push(e); }); const months = Object.keys(byMonth); return (
14 events · Sorted by date
{months.map((m, mi) => (

{m.split(" ")[0]}

{m.split(" ")[1]} {byMonth[m].length} events
{byMonth[m].map((e, i) => )}
))} {/* Bottom pager — "load more" pattern */}
Showing all 14 events through Oct 2026
Look further ahead →
); } function EventListRow({ event }) { const d = shortDate(event.date); const s = KIND_STYLE[event.kind]; const isPinkCta = event.id === "songbook"; // the page's one pop return (
{d.day}
{d.mo} · {event.weekday}
{s.label} {event.featured && ( Featured )} {event.medium}

{event.title}

{event.short}

{event.time}
{event.venue}
{event.cost}
{isPinkCta ? "Buy tickets" : (event.kind === "class" ? "Sign up" : (event.cost.toLowerCase().includes("free") ? "RSVP" : "Details"))}
); } window.EventsIndexA = EventsIndexA; window.EventsIndexB = EventsIndexB;