Restyle location-picker map: themed CARTO basemap + branded pin

Replace the plain gray OpenStreetMap raster in the location picker with a
theme-aware CARTO basemap (no API key): sleek "dark matter" tiles under the
dark theme, colorful "voyager" tiles under the light theme, so the map
matches whichever is active. Swap Leaflet's default blue marker for an
accent-colored teardrop pin (the same glyph the Find button uses), and theme
the zoom controls + attribution to sit in the app's surfaces.

- mappicker.js: theme-aware CARTO tileLayer (retina, CARTO attribution);
  L.divIcon "mp-pin" used for the marker
- style.css: .mp-pin styling, themed .leaflet-bar / attribution, map shadow

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B3Q2EkHHnTUX2BfhV5q1Zc
This commit is contained in:
Emi Griffith 2026-07-11 01:10:15 -07:00
parent 4b23fda4ec
commit dade6c3cb4
2 changed files with 38 additions and 5 deletions

View file

@ -9,7 +9,7 @@
// itself is created lazily the first time the picker opens (and reused after), so
// pages that never open it pay nothing.
(function () {
let overlay, mapEl, map, marker, pin = null, onPickCb = null;
let overlay, mapEl, map, marker, pin = null, onPickCb = null, pinIcon = null;
let searchForm, searchInput, sugEl, confirmBtn, hintEl;
const PIN_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>`;
@ -93,7 +93,7 @@
function setPin(lat, lon, zoom) {
pin = { lat, lon };
if (marker) marker.setLatLng([lat, lon]);
else marker = L.marker([lat, lon]).addTo(map);
else marker = L.marker([lat, lon], pinIcon ? { icon: pinIcon } : undefined).addTo(map);
map.setView([lat, lon], zoom || map.getZoom());
confirmBtn.disabled = false;
hintEl.textContent = "Pin set — confirm below, or tap elsewhere to move it.";
@ -117,10 +117,23 @@
overlay.hidden = false;
if (!map) {
map = L.map(mapEl, { worldCopyJump: true }).setView([44.5, -95], 4);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 18, attribution: "&copy; OpenStreetMap contributors",
map = L.map(mapEl, { worldCopyJump: true, zoomControl: true }).setView([44.5, -95], 4);
// Themed CARTO basemap (no key needed) instead of the plain gray OSM raster:
// sleek "dark matter" tiles under the app's dark theme, colorful "voyager"
// tiles under the light theme, so the picker matches whichever is active.
const dark = matchMedia("(prefers-color-scheme: dark)").matches;
const tiles = dark
? "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png"
: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png";
L.tileLayer(tiles, {
subdomains: "abcd", maxZoom: 20, detectRetina: true,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="https://carto.com/attributions">CARTO</a>',
}).addTo(map);
// Branded accent teardrop pin (the same glyph the Find button uses), styled
// in style.css — replaces Leaflet's default blue raster marker.
pinIcon = L.divIcon({
className: "mp-pin", html: PIN_ICON, iconSize: [32, 32], iconAnchor: [16, 30],
});
map.on("click", (e) => setPin(e.latlng.lat, e.latlng.lng));
}
// Leaflet measures the container on creation; it's zero-sized while hidden, so

View file

@ -680,7 +680,27 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
.mp-map {
flex: 1 1 auto; min-height: 300px; margin: 4px 16px; z-index: 0;
border-radius: 12px; overflow: hidden; border: 1px solid var(--border);
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .25), 0 6px 18px rgba(0, 0, 0, .25);
}
.mp-map .leaflet-container { background: var(--surface-2); }
/* Branded accent teardrop pin (an L.divIcon wrapping the Find-button glyph),
replacing Leaflet's default blue raster marker. */
.mp-pin { background: none; border: none; filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45)); }
.mp-pin svg { width: 32px; height: 32px; display: block; }
.mp-pin path { fill: var(--accent); stroke: rgba(0, 0, 0, .35); stroke-width: 1.25; }
.mp-pin circle { fill: #fff; stroke: none; }
/* Theme the Leaflet zoom buttons + attribution to sit in the app's surfaces
instead of Leaflet's stock white chrome. */
.mp-map .leaflet-bar { border: none; box-shadow: 0 2px 8px rgba(0, 0, 0, .3); }
.mp-map .leaflet-bar a {
background: var(--surface); color: var(--text); border-bottom-color: var(--border);
}
.mp-map .leaflet-bar a:hover { background: var(--surface-2); color: var(--accent); }
.mp-map .leaflet-control-attribution {
background: color-mix(in srgb, var(--surface) 80%, transparent);
color: var(--muted); backdrop-filter: blur(2px); border-top-left-radius: 6px;
}
.mp-map .leaflet-control-attribution a { color: var(--accent); }
.mp-foot {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
padding: 12px 16px 16px; flex-wrap: wrap;