feat: show live open ride count in park name cell
- Fetch Queue-Times ride counts for parks open today (5min cache) - Only shown within 1h before open to 1h after scheduled close - Count displayed on the right of the park name/location cell (desktop) and below the open badge (mobile) - Whole park cell is now a clickable link - Hover warms the park cell background; no row-wide highlight Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,9 +8,10 @@ interface MobileCardListProps {
|
||||
weekDates: string[];
|
||||
data: Record<string, Record<string, DayData>>;
|
||||
today: string;
|
||||
rideCounts?: Record<string, number>;
|
||||
}
|
||||
|
||||
export function MobileCardList({ grouped, weekDates, data, today }: MobileCardListProps) {
|
||||
export function MobileCardList({ grouped, weekDates, data, today, rideCounts }: MobileCardListProps) {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 20, paddingTop: 14 }}>
|
||||
{Array.from(grouped.entries()).map(([region, parks]) => (
|
||||
@@ -50,6 +51,7 @@ export function MobileCardList({ grouped, weekDates, data, today }: MobileCardLi
|
||||
weekDates={weekDates}
|
||||
parkData={data[park.id] ?? {}}
|
||||
today={today}
|
||||
openRideCount={rideCounts?.[park.id]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -7,11 +7,12 @@ interface ParkCardProps {
|
||||
weekDates: string[]; // 7 dates YYYY-MM-DD, Sun–Sat
|
||||
parkData: Record<string, DayData>;
|
||||
today: string;
|
||||
openRideCount?: number;
|
||||
}
|
||||
|
||||
const DOW = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
||||
|
||||
export function ParkCard({ park, weekDates, parkData, today }: ParkCardProps) {
|
||||
export function ParkCard({ park, weekDates, parkData, today, openRideCount }: ParkCardProps) {
|
||||
const openDays = weekDates.filter((d) => parkData[d]?.isOpen && parkData[d]?.hoursLabel);
|
||||
const isOpenToday = openDays.includes(today);
|
||||
|
||||
@@ -21,12 +22,11 @@ export function ParkCard({ park, weekDates, parkData, today }: ParkCardProps) {
|
||||
data-park={park.name.toLowerCase()}
|
||||
style={{ textDecoration: "none", display: "block" }}
|
||||
>
|
||||
<div style={{
|
||||
<div className="park-card" style={{
|
||||
background: "var(--color-surface)",
|
||||
border: "1px solid var(--color-border)",
|
||||
borderRadius: 12,
|
||||
overflow: "hidden",
|
||||
transition: "border-color 120ms ease",
|
||||
}}>
|
||||
{/* ── Card header ───────────────────────────────────────────────────── */}
|
||||
<div style={{
|
||||
@@ -54,6 +54,7 @@ export function ParkCard({ park, weekDates, parkData, today }: ParkCardProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 5, flexShrink: 0 }}>
|
||||
{isOpenToday ? (
|
||||
<div style={{
|
||||
background: "var(--color-open-bg)",
|
||||
@@ -64,7 +65,6 @@ export function ParkCard({ park, weekDates, parkData, today }: ParkCardProps) {
|
||||
fontWeight: 700,
|
||||
color: "var(--color-open-text)",
|
||||
whiteSpace: "nowrap",
|
||||
flexShrink: 0,
|
||||
letterSpacing: "0.03em",
|
||||
}}>
|
||||
Open today
|
||||
@@ -79,11 +79,21 @@ export function ParkCard({ park, weekDates, parkData, today }: ParkCardProps) {
|
||||
fontWeight: 500,
|
||||
color: "var(--color-text-muted)",
|
||||
whiteSpace: "nowrap",
|
||||
flexShrink: 0,
|
||||
}}>
|
||||
Closed today
|
||||
</div>
|
||||
)}
|
||||
{isOpenToday && openRideCount !== undefined && (
|
||||
<div style={{
|
||||
fontSize: "0.65rem",
|
||||
color: "var(--color-open-hours)",
|
||||
fontWeight: 500,
|
||||
textAlign: "right",
|
||||
}}>
|
||||
{openRideCount} open
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Open days list ────────────────────────────────────────────────── */}
|
||||
|
||||
@@ -10,6 +10,7 @@ interface WeekCalendarProps {
|
||||
weekDates: string[]; // 7 dates, YYYY-MM-DD, Sun–Sat
|
||||
data: Record<string, Record<string, DayData>>; // parkId → date → DayData
|
||||
grouped?: Map<Region, Park[]>; // pre-grouped parks (if provided, renders region headers)
|
||||
rideCounts?: Record<string, number>; // parkId → open ride count for today
|
||||
}
|
||||
|
||||
const DOW = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
@@ -163,12 +164,14 @@ function ParkRow({
|
||||
weekDates,
|
||||
parsedDates,
|
||||
parkData,
|
||||
rideCounts,
|
||||
}: {
|
||||
park: Park;
|
||||
parkIdx: number;
|
||||
weekDates: string[];
|
||||
parsedDates: ReturnType<typeof parseDate>[];
|
||||
parkData: Record<string, DayData>;
|
||||
rideCounts?: Record<string, number>;
|
||||
}) {
|
||||
const rowBg = parkIdx % 2 === 0 ? "var(--color-bg)" : "var(--color-surface)";
|
||||
return (
|
||||
@@ -181,7 +184,7 @@ function ParkRow({
|
||||
position: "sticky",
|
||||
left: 0,
|
||||
zIndex: 5,
|
||||
padding: "10px 14px",
|
||||
padding: 0,
|
||||
borderBottom: "1px solid var(--color-border)",
|
||||
borderRight: "1px solid var(--color-border)",
|
||||
whiteSpace: "nowrap",
|
||||
@@ -189,14 +192,27 @@ function ParkRow({
|
||||
background: rowBg,
|
||||
transition: "background 120ms ease",
|
||||
}}>
|
||||
<Link href={`/park/${park.id}`} className="park-name-link">
|
||||
<span style={{ fontWeight: 500, fontSize: "0.85rem", lineHeight: 1.2 }}>
|
||||
{park.name}
|
||||
</span>
|
||||
<Link href={`/park/${park.id}`} className="park-name-link" style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "10px 14px",
|
||||
gap: 10,
|
||||
}}>
|
||||
<div>
|
||||
<span style={{ fontWeight: 500, fontSize: "0.85rem", lineHeight: 1.2, color: "var(--color-text)" }}>
|
||||
{park.name}
|
||||
</span>
|
||||
<div style={{ fontSize: "0.7rem", color: "var(--color-text-muted)", marginTop: 2 }}>
|
||||
{park.location.city}, {park.location.state}
|
||||
</div>
|
||||
</div>
|
||||
{rideCounts?.[park.id] !== undefined && (
|
||||
<div style={{ fontSize: "0.65rem", color: "var(--color-open-hours)", fontWeight: 500, whiteSpace: "nowrap", flexShrink: 0 }}>
|
||||
{rideCounts[park.id]} open
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
<div style={{ fontSize: "0.7rem", color: "var(--color-text-muted)", marginTop: 2 }}>
|
||||
{park.location.city}, {park.location.state}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
{weekDates.map((date, i) => (
|
||||
@@ -210,7 +226,7 @@ function ParkRow({
|
||||
);
|
||||
}
|
||||
|
||||
export function WeekCalendar({ parks, weekDates, data, grouped }: WeekCalendarProps) {
|
||||
export function WeekCalendar({ parks, weekDates, data, grouped, rideCounts }: WeekCalendarProps) {
|
||||
const today = getTodayLocal();
|
||||
const parsedDates = weekDates.map(parseDate);
|
||||
|
||||
@@ -324,6 +340,7 @@ export function WeekCalendar({ parks, weekDates, data, grouped }: WeekCalendarPr
|
||||
weekDates={weekDates}
|
||||
parsedDates={parsedDates}
|
||||
parkData={data[park.id] ?? {}}
|
||||
rideCounts={rideCounts}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
|
||||
Reference in New Issue
Block a user