josh e48038c399
Some checks failed
Build and Deploy / Build & Push (push) Failing after 22s
feat: UI redesign with park detail pages and ride status
Visual overhaul:
- Warmer color system with amber accent for Today, better text hierarchy
- Row hover highlighting, sticky column shadow on horizontal scroll
- Closed cells replaced with dot (·) instead of "Closed" text
- Regional grouping (Northeast/Southeast/Midwest/Texas & South/West)
- Two-row header with park count badge and WeekNav on separate lines
- Amber "Today" button in WeekNav when off current week
- Mobile card layout (< 1024px) with 7-day grid per park; table on desktop
- Skeleton loading state via app/loading.tsx

Park detail pages (/park/[id]):
- Month calendar view with ← → navigation via ?month= param
- Live ride status fetched from Six Flags API (cached 1h)
- Ride hours only shown when they differ from park operating hours
- Fallback to nearest upcoming open day when today is dropped by API,
  including cross-month fallback for end-of-month edge case

Data layer:
- Park type gains region field; parks.ts exports groupByRegion()
- db.ts gains getParkMonthData() for single-park month queries
- sixflags.ts gains scrapeRidesForDay() returning RidesFetchResult
  with rides, dataDate, isExact, and parkHoursLabel

Removed: CalendarGrid.tsx, MonthNav.tsx (dead code)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:53:06 -04:00
2026-04-03 22:06:54 -04:00

Six Flags Super Calendar

A week-by-week calendar showing operating hours for all Six Flags Entertainment Group theme parks — including the former Cedar Fair parks. Data is scraped from the Six Flags internal API and stored locally in SQLite.

Parks

24 theme parks across the US, Canada, and Mexico:

Six Flags branded — Great Adventure (NJ), Magic Mountain (CA), Great America (IL), Over Georgia, Over Texas, St. Louis, Fiesta Texas (TX), New England (MA), Discovery Kingdom (CA), Mexico, Great Escape (NY), Darien Lake (NY), Frontier City (OK)

Former Cedar Fair — Cedar Point (OH), Knott's Berry Farm (CA), Canada's Wonderland (ON), Carowinds (NC), Kings Dominion (VA), Kings Island (OH), Valleyfair (MN), Worlds of Fun (MO), Michigan's Adventure (MI), Dorney Park (PA), California's Great America (CA)

Tech Stack

  • Next.js 15 (App Router, Server Components, standalone output)
  • Tailwind CSS v4 (@theme {} CSS variables, no config file)
  • SQLite via better-sqlite3 — persisted in /app/data/parks.db
  • Playwright — one-time headless browser run to discover each park's internal API ID
  • Six Flags CloudFront APIhttps://d18car1k0ff81h.cloudfront.net/operating-hours/park/{id}?date=YYYYMM

Local Development

Prerequisites

  • Node.js 22+
  • npm

Setup

npm install
npx playwright install chromium

Seed the database

Run once to discover each park's internal API ID (opens a headless browser per park):

npm run discover

Then scrape operating hours for the full year:

npm run scrape

To force a full re-scrape (ignores the 7-day staleness window):

npm run scrape:force

Run the dev server

npm run dev

Open http://localhost:3000. Navigate weeks with the / buttons or pass ?week=YYYY-MM-DD directly.


Deployment

Docker (standalone)

The app uses Next.js standalone output. The SQLite database is stored in a Docker volume at /app/data.

Run

docker compose up -d

Seed the database inside the container

The production image includes Playwright and Chromium, so discovery and scraping can be run directly against the running container's volume.

# Discover API IDs for all parks (one-time, opens headless browser per park)
docker compose exec web npm run discover

# Scrape operating hours for the full year
docker compose exec web npm run scrape

Or as one-off containers against the named volume:

docker run --rm -v sixflagssupercalendar_park_data:/app/data \
  gitea.thewrightserver.net/josh/sixflagssupercalendar:latest \
  npm run discover

docker run --rm -v sixflagssupercalendar_park_data:/app/data \
  gitea.thewrightserver.net/josh/sixflagssupercalendar:latest \
  npm run scrape

CI/CD (Gitea Actions)

The pipeline is defined at .gitea/workflows/deploy.yml.

Trigger: Push to main

Steps:

  1. Checkout code
  2. Log in to the Gitea container registry
  3. Build and tag the image as :latest and :<short-sha>
  4. Push both tags

Required configuration in Gitea

Type Name Value
Variable REGISTRY Registry hostname — gitea.thewrightserver.net
Secret REGISTRY_TOKEN A Gitea access token with package:write scope

Set these under Repository → Settings → Actions → Variables / Secrets.

Upstream remote

git remote add origin https://gitea.thewrightserver.net/josh/SixFlagsSuperCalendar.git
git push -u origin main

Data Refresh

The scrape job skips any park+month combination scraped within the last 7 days. To keep data current, run npm run scrape (or scrape:force) on a schedule — weekly is sufficient for a season calendar.

Parks and months not yet in the database show a placeholder in the UI. Parks with no hours data on a given day show "Closed".

Description
No description provided
Readme 731 KiB
Languages
TypeScript 93.7%
CSS 3.2%
Dockerfile 1.8%
Shell 1%
JavaScript 0.3%