You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
-**`src/main.mjs`** — ES module entry; loads **`src/bootstrap.mjs`**.
6
6
-**`src/bootstrap.mjs`** — Loads data, hash routing for `#/visit`, `#/data`, `#/modes`, and legacy `#/parking` / `#/planner` → `#/visit` redirects; owns the modes page and data explorer UI.
7
-
- **`src/visit/visit.mjs`** — **Parking-for-events** main app at `#/visit`: the goal is to help users **find parking when attending events** at downtown venues—pick a **venue**, see **DASH** routes/stops and nearby garages/lots, and compare costs with **event** pricing preferred in popups when the data includes it (see Parking data → **`pricing`** order). Leaflet map with **DASH** shuttle polylines/stops from `appData.busRoutes`, plus parking pins from `appData.parking` **garages and lots only** (public garages/lots, OSM private garages/lots, and Ellis `ellisGarages` / `ellisLots`—no meters, bike racks, or micromobility). Pins are limited to within **0.75 mi** (Haversine) of a DASH stop on the map. With **no** venue selected (bare **`#/visit`** with no slug), map **`fitBounds`** frames **all listed destinations** plus the **DASH** route geometry (stops + polyline vertices)—not parking pins—so the shuttle loop stays on-screen without zooming out to the full parking set. With **`#/visit/<destination-slug>`** (or legacy **`finish=`** / **`venue=`** / **`destination=`** / **`dest=`** in the query) and **no** **`park=`**, **`fitBounds`** uses **visible parking pins and the selected venue** (candidate picks plus the red finish pin). With **`park=`** set, **`fitBounds`** frames **that parking pick, the venue, and — when the trip uses DASH — the full shuttle leg (board → alight along the loop)** so every trip step stays on-screen. Category toggles and `location=` use ids **`public-garage`**, **`public-lot`**, **`private-garage`**, **`private-lot`** only (mapped to `garages` / `lots` / `osmGarages` / `osmLots` in JSON); Ellis **`ellisGarages` / `ellisLots`** pins appear when the matching private toggle is on and use **`ellis-garage` / `ellis-lot`** in **`park=`** URLs. Legacy **`location=ellis-garage`** / **`ellis-lot`** or **`cats=ellisGarages`** / **`ellisLots`** map onto **`private-garage` / `private-lot`**; legacy `location=garages` etc. and old `cats=` still parse. Legacy **`#/parking?…`** URLs are rewritten to **`#/visit[/slug]?…`** on load (and **`start=`** → **`park=`**). Optional **`maxEvening=<dollars>`** caps evening parking cost: hides pins whose inferred evening rate (pricing **`evening`**, else public ramp/lot **`events`** fallback) parses to a dollar amount above the cap. With **`maxEvening`** omitted, the default cap is **$40** (slider **40**; param omitted for a short **`#/visit`** link). **`0`–`45`** in **`$5`** steps are spelled in the URL when not **40**; **`maxEvening=50`** (or snapped **≥50**, legacy **≥100**) means **any price** (no cap). Pins with **no** pricing tier fields (`evening`, `events`, `hourly`, `rate`, `daily`) are hidden while any finite **`pay`** cap is in effect; prose tiers without `$` amounts but recognized as free evenings/weekends count as **free**; other prose without dollars (still “some data”) stays visible unless **`pay`** is **free-only** (`0`). Optional **`maxWalk=<miles>`** — when a **venue** is selected (path slug or legacy query keys), hides pins whose grid-walk distance (N–S + E–W miles at mid-latitude, not a diagonal shortcut) to the **nearest DASH stop** exceeds that cap; **`maxWalk=0`** (or **`0.0`**) is treated internally as **~100 ft** for that filter (slider **No distance** — walk overlays and auto **pick** stay off); **`maxWalk` omitted** means **0.8 mi** (default; omitted from **`#/visit`** for short links); other **`0.1`**–**`1.5`** in **0.1** steps spell in the URL; minute hints use **`data/config.json`** **`parkingRoutePace.walkMinutesPerMile`** (about **2.5 mph** by default).
7
+
- **`src/visit/visit.mjs`** — **Parking-for-events** main app at `#/visit`: the goal is to help users **find parking when attending events** at downtown venues—pick a **venue**, see **DASH** routes/stops and nearby garages/lots, and compare costs with **event** pricing preferred in popups when the data includes it (see Parking data → **`pricing`** order). Leaflet map with **DASH** shuttle polylines/stops from `appData.busRoutes`, plus parking pins from `appData.parking` **garages and lots only** (public garages/lots, OSM private garages/lots, and Ellis `ellisGarages` / `ellisLots`—no meters, bike racks, or micromobility). Pins are limited to within **0.75 mi** (Haversine) of a DASH stop on the map. With **no** venue selected (bare **`#/visit`** with no slug), map **`fitBounds`** frames **all listed destinations** plus the **DASH** route geometry (stops + polyline vertices)—not parking pins—so the shuttle loop stays on-screen without zooming out to the full parking set. With **`#/visit/<destination-slug>`** (or legacy **`finish=`** / **`venue=`** / **`destination=`** / **`dest=`** in the query) and **no** **`park=`**, **`fitBounds`** uses **visible parking pins and the selected venue** (candidate picks plus the red finish pin). With **`park=`** set, **`fitBounds`** frames **that parking pick, the venue, and — when the trip uses DASH — the full shuttle leg (board → alight along the loop)** so every trip step stays on-screen. Category toggles and `location=` use ids **`public-garage`**, **`public-lot`**, **`private-garage`**, **`private-lot`** only (mapped to `garages` / `lots` / `osmGarages` / `osmLots` in JSON); Ellis **`ellisGarages` / `ellisLots`** pins appear when the matching private toggle is on and use **`ellis-garage` / `ellis-lot`** in **`park=`** URLs. Legacy **`location=ellis-garage`** / **`ellis-lot`** or **`cats=ellisGarages`** / **`ellisLots`** map onto **`private-garage` / `private-lot`**; legacy `location=garages` etc. and old `cats=` still parse. Legacy **`#/parking?…`** URLs are rewritten to **`#/visit[/slug]?…`** on load (and **`start=`** → **`park=`**). Optional **`maxEvening=<dollars>`** caps evening parking cost: hides pins whose inferred evening rate (pricing **`evening`**, else public ramp/lot **`events`** fallback) parses to a dollar amount above the cap. With **`maxEvening`** omitted, the default cap is **$40** (slider **40**; param omitted for a short **`#/visit`** link). **`0`–`45`** in **`$5`** steps are spelled in the URL when not **40**; **`maxEvening=50`** (or snapped **≥50**, legacy **≥100**) means **any price** (no cap). Pins with **no** pricing tier fields (`evening`, `events`, `hourly`, `rate`, `daily`) are hidden while any finite **`pay`** cap is in effect; prose tiers without `$` amounts but recognized as free evenings/weekends count as **free**; other prose without dollars (still “some data”) stays visible unless **`pay`** is **free-only** (`0`). Optional **`maxWalk=<miles>`** — when a **venue** is selected (path slug or legacy query keys), hides pins whose grid-walk distance (N–S + E–W miles at mid-latitude, not a diagonal shortcut) to the **nearest DASH stop** exceeds that cap; **`maxWalk=0`** (or **`0.0`**) is treated internally as **~100 ft** for that filter (slider **No distance** — walk overlays and auto **pick** stay off); **`maxWalk` omitted** means **0.8 mi** (default; omitted from **`#/visit`** for short links); other **`0.1`**–**`1.5`** in **0.1** steps spell in the URL; **`walk=2`** (or snapped **`≥2`**, same for legacy **`maxWalk`**) means **any distance** (no cap; slider **Any distance**); minute hints use **`data/config.json`** **`parkingRoutePace.walkMinutesPerMile`** (about **2.5 mph** by default).
8
8
9
9
Each parking pin opens a **popup** with **Plan to park here** / **Clear parking selection**: choosing a spot sets **`park=<category>:<lat>,<lng>`** (6 dp; legacy tilde form still parses; legacy **`start=`**, **`spot=`**) and the **green** pin; clearing removes **`park=`** for that spot; the venue uses a **red** pin; reset clears **`park=`**. **`park=`** is added to the URL **only** when the user taps **Plan to park here** (or opens a shared link that already includes **`park=`** / legacy **`start=`** / **`spot=`**). Sliders, destination, and category filters **do not** put **`park=`** in the hash; without it, the map still surfaces up to **3** muted-green recommendation pins on load and when overlays refresh using the same ranking rules — each glyph reflects the pin's role: a **★ star** marks the {@link compareParkingMarkersForRecommendation} **best** pick (also drives the walk overlay and route panel), a **walking-person** glyph marks the pin that puts the **most total foot-miles** on the user (walk-to-DASH-stop **+** walk-from-alight-to-venue for multimodal trips, otherwise the door-to-door grid walk — pins whose endpoints sit on DASH stops have small total walks even when their grid distance from the venue is large) within the active **`pay`** + **`walk`** filters, and a **`$`** sign marks the **most expensive** pin **by the displayed popup price** within those same filters. The dollar-sign rank deliberately uses the price the user sees in the popup (e.g. **`events: "$8–9"`** for GR public spots) rather than the underlying **`evening`** ceiling that drives the **`pay`** cap (often **`$51`** posted overnight max for the same spots) so the **`$`** pin matches the priciest line on screen. Each role picks its top candidate from the pool **excluding pins already taken by an earlier role** (priority **best** > **farthest** > **expensive**), so when one pin happens to win two ranks (e.g. GLC Live's **Area 8 Lot** is both the recommendation winner _and_ the farthest grid-walk in the pool) the **farthest** glyph falls through to the **next-farthest** pin instead of collapsing — each role only goes empty when the pool has no remaining pin for it. Tapping any suggestion commits **`park=`** to the URL like before. **How pins rank** (when **venue** is set and DASH stops exist); for the **auto-recommended** green pick (slot **#1**), **`public-garage` / `public-lot`** sort before **`private-garage` / `private-lot` / `ellis-garage` / `ellis-lot`** (city inventory before third-party sources), then distance / DASH / price as below: pins inferred as **free** ($0 evening/event ceiling) are excluded from the automatic **pick** pool whenever **any other** eligible visible pin has a **paid** (> $0) ceiling (so default **`#/visit`** favors farther paid lots); when **every** pin that passes **`pay`** is free (e.g. a tight **`pay`** cap), free pins remain in the pool. If max walk to the nearest DASH stop is **at most 0.5 mi**, prefer pins whose estimated trip **uses DASH** (multimodal overlay beats straight-line walk) over door-to-door-only pins; among multimodal picks use **farther** grid-walk miles from the venue first (then walk-to-stop / paid-tier / dollars like generous walk). Among **only** door-to-door pins, use **closest** to the venue first, then highest inferred evening/event dollars, then longest walk to DASH. If max walk is **over 0.5 mi**, use **distance before cost**—**farthest** grid-walk miles from the **venue** among pins within the walk-to-DASH cap (farther paid lots), **then** among ties **longest** walk to the nearest DASH stop, **then** pins with a **known paid** rate over free-evening or unknown/ambiguous pricing, **then** higher inferred dollars among ties. When **`pay`** is **any price** (max slider / no cap), the recommendation **never** uses a pin whose cost is **unknown** or **ambiguous-only** if **any** visible pin has a **parseable dollar** ceiling; only when **no** pin has known dollars does it fall back to unknown vs ambiguous. With **short-walk** rules and **any price**, door-to-door-only ties rank by highest inferred dollars before longest walk to DASH. With a **finite** **`pay`** cap under short-walk rules, known dollars rank above unknown or ambiguous before distance within the door-to-door pool. If there are no DASH stops, longest walk to the **venue** substitutes for walk-to-stop in tie-breaks under cost-first rules. When the **`walk`** slider is at index **0** (`walk=0`), pins farther than **~100 ft** from the nearest DASH stop are hidden (**`park=`** is still omitted — no green parking pick). Pins farther than the max-walk cap are hidden when **venue** is set and DASH data exists (**including** **`walk=0`**). Overlap paint order is **`PARKING_CATEGORY_PAINT_ORDER`** (public garage / purple above Ellis and private garage / orange; Ellis lots stack with private lots / yellow).
0 commit comments