Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/samgutentag/sbburgerweek/llms.txt

Use this file to discover all available pages before exploring further.

The map is a static site with no build step, served directly from GitHub Pages. There is no bundler, no npm, and no server-side rendering. Optional backend features — click tracking, analytics, and restaurant hours — use Cloudflare and Google Cloud services, all on free tiers. Every integration degrades gracefully: removing or nulling out a config key simply disables that feature without breaking anything else.
The entire static site works without the Worker, Google Places API, or GitHub Actions. Set THEME.trackUrl and THEME.cfAnalyticsToken to null in config.js and the map functions as a fully offline-capable, read-only restaurant directory.

Static site layer

The core of the project is a handful of plain files served from the repo root:
FileRole
index.htmlPage shell — declares the OG tags, favicon, analytics snippet, and loads all scripts
app.jsAll map logic: Leaflet setup, marker rendering, sidebar, search, filtering, deep linking, popups, modals
style.cssAll styles including the responsive mobile drawer layout
config.jsExports the THEME object — single source of truth for event identity, dates, integrations, and map defaults
data-YYYY.jsProduction restaurant data with full menu items (e.g. data-2026.js)
data.jsSkeleton restaurant data with empty menuItems arrays — shown before dataLiveDate
track.jsLightweight event tracker — defines window.track(action, label) using navigator.sendBeacon
index.html decides at runtime which data file to load based on THEME.dataLiveDate: before that date it loads data.js (skeleton); on or after it loads data-YYYY.js (full data). Add ?year=9999 to the URL during development to force the skeleton view. The Leaflet map and MarkerCluster plugin are loaded from CDN. There is no local copy of any dependency.

Embed and stats pages

Two additional subdirectories extend the main site: /embed/map — A compact, embeddable version of the map intended for iframing on local news sites or blogs. It shares config.js and the data files (via ../../ relative paths) but has its own independent embed.js and embed.css. Changes to app.js or style.css do not propagate to the embed. Key differences:
Main siteEmbed
Sidebar width360px280px
Mobile breakpoint768px600px
JSapp.jsembed/map/embed.js
CSSstyle.cssembed/map/embed.css
HeaderFull nav headerCompact bar with “Open full map” link
/embed — A showcase page with copy-paste iframe instructions for publishers. /stats — The live engagement dashboard. stats/stats.js queries the Worker’s GET endpoints (GET /, GET /?hourly=true, GET /?upvotes=true, GET /?rum=true) and renders a leaderboard ranked by engagement score, a trends chart, and device/browser breakdowns. After the event concludes, the stats page falls back to pre-committed snapshot files in snapshots/ instead of querying the Worker.

Cloudflare Worker

The Worker lives in workers/track/index.js and is deployed with Wrangler. It serves two roles:
  1. Event ingestion (POST /) — Receives JSON payloads from track.js (via sendBeacon) and writes them to the Cloudflare Analytics Engine dataset (sbburgerweek). Each data point stores the action in blob1 and the label in blob2.
  2. Stats queries (GET /) — Runs SQL queries against Analytics Engine and returns aggregated results used by the /stats page. The full set of GET endpoints is documented in Worker API.
The Worker configuration in wrangler.toml declares the Analytics Engine dataset binding (TRACKER) and two plain [vars]: ACCOUNT_ID and RUM_SITE_TAG. Secrets (CF_API_TOKEN, ADMIN_TOKEN) are set separately via wrangler secret put and never appear in the committed config file.
name = "sbburgerweek-track"
main = "index.js"
compatibility_date = "2024-01-01"

[vars]
ACCOUNT_ID = "95bdaad9a0525e9a9af474a004504732"
RUM_SITE_TAG = "4a7b8d80cde44aaeae633e477756e567"

[[analytics_engine_datasets]]
binding = "TRACKER"
dataset = "sbburgerweek"
When forking, replace ACCOUNT_ID with your own Cloudflare account ID and rename the dataset to match your new event.

GitHub Actions

Two workflows in .github/workflows/ handle automated data collection during the event: fetch-hours.yml — Runs on a daily cron schedule during event week. Calls the Google Places API (fields=opening_hours) for each restaurant using place-ids.json as input, then auto-commits the updated hours.json to the repo if anything changed. The map loads hours.json at runtime to show today’s hours and open/closed badges. The schedule is commented out in the repo by default — uncomment it and update the date range before your event. snapshot-tracking.yml — Runs hourly during event week. Queries the Cloudflare Analytics Engine SQL API directly using CF_ACCOUNT_ID and CF_API_TOKEN GitHub Secrets, and commits a JSON snapshot to snapshots/tracking-YYYY-MM-DD.json. This preserves engagement data beyond Analytics Engine’s 90-day retention window. Like fetch-hours.yml, the cron schedule is commented out by default. Both workflows also support manual dispatch from the GitHub Actions tab, which is useful for testing before the event and for running final snapshots on wind-down day.

CDN dependencies

The project loads all JavaScript and map tile dependencies from public CDNs — there is no local copy of any library and no build step:
DependencySourcePurpose
LeafletCDNInteractive map rendering, markers, popups, zoom controls
Leaflet.markerclusterCDNClusters nearby markers at low zoom levels
CARTO basemap tiles{s}.basemaps.cartocdn.comLight-gray map tile layer (no API key required)

Architecture diagram

Build docs developers (and LLMs) love