Skip to content

[codex] Add Chattanooga and Bend city config#90

Merged
kwiens merged 8 commits into
mainfrom
feat/chattanooga-bend-config
Jun 21, 2026
Merged

[codex] Add Chattanooga and Bend city config#90
kwiens merged 8 commits into
mainfrom
feat/chattanooga-bend-config

Conversation

@kwiens

@kwiens kwiens commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Summary

Adds stored city configuration for Chattanooga and Bend without forking the app. The active city is selected with NEXT_PUBLIC_CITY_ID, defaulting to Chattanooga, so future forks can still specialize behavior by swapping or overriding config.

Changes

  • Adds src/data/cities/* modules for shared city data, Chattanooga data, and Bend starter data.
  • Updates map/site config to support chattanooga and bend city records.
  • Adds Bend GBFS support using Veo free-bike status while preserving Chattanooga station-status support.
  • Gates sidebar sections and marker layers when a city has no local routes/resources yet.
  • Keeps curated Chattanooga MTB behavior working and registers OSM popup handling after curated trail handlers so curated trail selection wins when layers overlap.

Review Fixes

  • Includes the city data module in the patch so src/data/geo_data.ts resolves in a clean checkout.
  • Moves OSM popup registration after curated trail hit handlers.

Verification

  • pnpm test:run passed.
  • pnpm lint passed with existing Biome warnings only.
  • pnpm dev served / with the Chattanooga manifest.
  • NEXT_PUBLIC_CITY_ID=bend pnpm dev served /, rendered Bend content on /about, and returned the Bend manifest.

kwiens added 6 commits June 20, 2026 20:32
Attach the OpenStreetMap US trails vector tileset at runtime (mirroring the
MTB tileset pattern) and expose it as a 'Nationwide trails' toggle in the MTB
tab. Filters the OSM 'trail' layer to bike-relevant ways (bicycle permitted,
mtb:scale present, or cycleway) and colors lines by mtb:scale difficulty with
a white casing. Hidden by default; toggles independently via the layer-toggle
event. Attribution and zoom bounds come from the TileJSON automatically.
Render the trail_poi source-layer as a single symbol layer (minzoom 12) using
built-in Maki sprite icons: trailhead parking (amenity=parking) and information
points (tourism=information). Shares the 'Nationwide trails' toggle via
setOsmTrailsVisible. No custom sprite/spreet step needed.
Merge origin/main (OSS hygiene phases 1–2) into the branch and add trail
interactivity plus PR review fixes:

- Clickable trails: a transparent wide hit layer (OSM_TRAILS_HIT_LAYER_ID) makes
  the thin lines tappable; clicking opens a popup built from the feature's OSM
  tags (name, type, difficulty, surface, bike access) with a "View on
  OpenStreetMap" link. OSM values are HTML-escaped (user-generated content).
- Filter fix (review): the mtb:scale / cycleway branch now excludes ways that
  deny bikes (bicycle=no/private) or restrict access (access=no/private);
  explicit bicycle=yes/designated/permissive still wins.
- Early-toggle fix (review): remember desired visibility in a ref and replay it
  after the layers attach, so toggling before style load isn't lost.
- Fix missing OSM_TRAILS_HIT_LAYER_ID export that broke the production build.

Tests: 343 pass (added popup-builder + filter-exclusion + hit-layer coverage).
Restyle the click popup: a colored difficulty badge (easy/intermediate/
advanced/expert from mtb:scale, raw scale no longer shown), the trail type as a
subtitle, and aligned surface/bikes/operator rows above the OpenStreetMap link.
Split the popup builder into osmTrailType/osmTrailDifficulty/osmTrailDetailRows
and add osm-trail-* styles in map.css.
Correctness:
- Curated trails win over OSM popups: OSM hit layer now inserts beneath the
  curated MTB layers (beforeId) and both click handlers bail on
  e.defaultPrevented, so a click in both datasets no longer fires twice.
- Lazy Mapbox token in add_trail_elevation.py: resolved on first tile fetch, not
  at import, so validate_trails.py can import the decoder helpers without a token.
- Difficulty badge and line color now derive from one shared MTB_SCALE_RATING map
  (covers +/- scale refinements), so e.g. mtb:scale=4+ is Expert in both.
- Escape/encode the OSM "View on OpenStreetMap" href (defense-in-depth).
- Compute-then-dispatch the osmTrails toggle so React StrictMode's double-invoked
  setState updater can't double-fire the layer-toggle event.

Cleanup:
- OSM line layers gated to minzoom 9 (nationwide geometry was rendering from z8).
- Reuse the shared escapeXml; drop the duplicate escapeHtml.
- Extract MapLayersSection + ToggleRow; both tabs' "Map Layers" rows reuse them.
- Collapse the three near-identical line addLayer blocks into a base spec + loop;
  POI icon / trail color are now typed expression consts.
- OsmTrailProps is an interface; titleCase is Unicode-aware (\p{L}).
@vercel

vercel Bot commented Jun 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
bikemap Ready Ready Preview Jun 21, 2026 4:34pm

Request Review

@kwiens
kwiens marked this pull request as ready for review June 21, 2026 16:04
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…-config

# Conflicts:
#	src/components/Map.tsx
#	src/components/MapMarkers.tsx
#	src/components/sidebar/BikeRentalList.tsx
#	src/data/gbfs.ts
#	src/utils/map.ts

@kwiens kwiens left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CR 👍

@kwiens
kwiens merged commit a448b1f into main Jun 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant