Added a map card kind. It works with no API key: MapLibre GL + OpenStreetMap
tiles, geocoded via OSM Nominatim. If a Google key is configured it transparently
upgrades new cards to the Google Maps Embed API. First step toward Claude-style
place widgets.
Added
maplibre-gldependency.mapcard kind (lib/canvas-store.ts) with aproviderfield (maplibre|google) +components/cards/MapCard.tsx:- MapLibre/OSM (default) — interactive map centered on lat/lng with a
marker;
maplibre-glis lazy-imported in an effect (SSR-safe). Shows a "locating…" spinner while geocoding and a graceful "couldn't find" state. - Google — Embed API iframe (
place/search/view); placeholder if the key is unset. - Cloud persistence is automatic (generic
kind+datajsonb — no schema change).
- MapLibre/OSM (default) — interactive map centered on lat/lng with a
marker;
GET /api/geocode— free, keyless geocoding via OSM Nominatim (cached 24h, identifying User-Agent per their usage policy).- Two creation paths (
components/Canvas.tsx):- Paste/drop a Google Maps URL →
getMapEmbedparses/maps/place/…,/maps/search/…,?q=, and@lat,lng(routed ahead of the generic unfurl). Coordinates from@lat,lngskip geocoding. Short goo.gl links fall through to a link card. - Right-click → "Add map…" —
addMap(query)geocodes the place/address and drops a map card.
- Paste/drop a Google Maps URL →
- AI awareness (
app/api/ai/route.ts) —cardLabel/describeCarddescribemapcards so the assistant reasons over them.
Notes
- MapLibre uses OSM's public tile server + Nominatim — fine for dev / low volume; both have usage policies, so production should move to MapTiler/Carto/self-host.
- The Google upgrade key is optional and must be the public, referrer-restricted
key (it ships in the iframe URL). See
.env.example.