feat: amber indicator during post-close wind-down buffer
All checks were successful
Build and Deploy / Build & Push (push) Successful in 2m22s

Parks in the 1-hour buffer after scheduled close now show amber instead
of green: the dot on the desktop calendar turns yellow, and the mobile
card badge changes from "Open today" (green) to "Closing" (amber).

- getOperatingStatus() replaces isWithinOperatingWindow's inline logic,
  returning "open" | "closing" | "closed"; isWithinOperatingWindow now
  delegates to it so all callers are unchanged
- closingParkIds[] is computed server-side and threaded through
  HomePageClient → WeekCalendar/MobileCardList → ParkRow/ParkCard
- New --color-closing-* CSS variables mirror the green palette in amber

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Josh Wright
2026-04-05 09:06:45 -04:00
parent 090f4d876d
commit 53297a7cff
7 changed files with 57 additions and 14 deletions

View File

@@ -27,6 +27,12 @@
--color-open-text: #4ade80;
--color-open-hours: #bbf7d0;
/* ── Closing — amber (post-close buffer, rides still winding down) ───────── */
--color-closing-bg: #1a1100;
--color-closing-border: #d97706;
--color-closing-text: #fbbf24;
--color-closing-hours: #fde68a;
/* ── Passholder preview — vivid cyan ─────────────────────────────────────── */
--color-ph-bg: #051518;
--color-ph-border: #22d3ee;

View File

@@ -1,7 +1,7 @@
import { HomePageClient } from "@/components/HomePageClient";
import { PARKS } from "@/lib/parks";
import { openDb, getDateRange } from "@/lib/db";
import { getTodayLocal, isWithinOperatingWindow } from "@/lib/env";
import { getTodayLocal, isWithinOperatingWindow, getOperatingStatus } from "@/lib/env";
import { fetchLiveRides } from "@/lib/scrapers/queuetimes";
import { QUEUE_TIMES_IDS } from "@/lib/queue-times-map";
import { readParkMeta, getCoasterSet } from "@/lib/park-meta";
@@ -62,12 +62,21 @@ export default async function HomePage({ searchParams }: PageProps) {
let rideCounts: Record<string, number> = {};
let coasterCounts: Record<string, number> = {};
let closingParkIds: string[] = [];
if (weekDates.includes(today)) {
const openTodayParks = PARKS.filter((p) => {
const dayData = data[p.id]?.[today];
if (!dayData?.isOpen || !QUEUE_TIMES_IDS[p.id] || !dayData.hoursLabel) return false;
return isWithinOperatingWindow(dayData.hoursLabel, p.timezone);
});
closingParkIds = openTodayParks
.filter((p) => {
const dayData = data[p.id]?.[today];
return dayData?.hoursLabel
? getOperatingStatus(dayData.hoursLabel, p.timezone) === "closing"
: false;
})
.map((p) => p.id);
const results = await Promise.all(
openTodayParks.map(async (p) => {
const coasterSet = getCoasterSet(p.id, parkMeta);
@@ -94,6 +103,7 @@ export default async function HomePage({ searchParams }: PageProps) {
data={data}
rideCounts={rideCounts}
coasterCounts={coasterCounts}
closingParkIds={closingParkIds}
hasCoasterData={hasCoasterData}
scrapedCount={scrapedCount}
/>