Revert Orchid Sunset palette; restyle location-picker map (#24)
* Revert "Merge pull request #22 from griffemi/fem-orchid-palette" This reverts commitf7d16238f2, reversing changes made to34e4fed1f0. * 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 --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
01e5f48257
commit
34dd577545
5 changed files with 93 additions and 66 deletions
|
|
@ -330,12 +330,12 @@ function scrollTableToToday(host, today, hasFc) {
|
|||
// Tier css class -> literal color (mirrors style.css; needed because the chart is
|
||||
// rasterized to PNG, where CSS variables aren't available).
|
||||
const TIER_COLORS = {
|
||||
"rec-hot": "#7d1a49", "very-hot": "#db2777", "hot": "#f472b6", "warm": "#f9a8d4",
|
||||
"normal": "#f0dce8",
|
||||
"cool": "#cbb6f7", "cold": "#9b6ef0", "very-cold": "#6d28d9", "rec-cold": "#3b0764",
|
||||
"dry": "#cbb26a",
|
||||
"wet-1": "#f3e8ff", "wet-2": "#e9d5ff", "wet-3": "#d8b4fe", "wet-4": "#c084fc", "wet-5": "#a855f7",
|
||||
"wet-6": "#9333ea", "wet-7": "#7e22ce", "wet-8": "#6b21a8", "wet-9": "#4c1d95",
|
||||
"rec-hot": "#8f0e20", "very-hot": "#dd6b52", "hot": "#ef9351", "warm": "#f6c18a",
|
||||
"normal": "#4a9d5b",
|
||||
"cool": "#92c5de", "cold": "#4393c3", "very-cold": "#2166ac", "rec-cold": "#0a2f6b",
|
||||
"dry": "#c9a24a",
|
||||
"wet-1": "#d9f0d3", "wet-2": "#b7e2b1", "wet-3": "#8fd18f", "wet-4": "#5cba9f", "wet-5": "#35a1c0",
|
||||
"wet-6": "#2b8cbe", "wet-7": "#226bb3", "wet-8": "#164a97", "wet-9": "#08306b",
|
||||
};
|
||||
|
||||
// Percentile grade scale, low -> high. Names are deliberately *relative* to each
|
||||
|
|
@ -381,18 +381,18 @@ function chartPalette() {
|
|||
const css = getComputedStyle(document.documentElement);
|
||||
const v = (name, f) => (css.getPropertyValue(name).trim() || f);
|
||||
const dark = matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
const hi = v("--very-hot", "#db2777"); // daily-high series = warm tier magenta
|
||||
const lo = v("--cold", "#9b6ef0"); // daily-low series = cool tier violet
|
||||
const hi = v("--very-hot", "#dd6b52"); // daily-high series = warm tier red
|
||||
const lo = v("--cold", "#4393c3"); // daily-low series = cool tier blue
|
||||
return {
|
||||
surface: v("--surface-2", dark ? "#1e242c" : "#eef1f5"),
|
||||
ink: v("--text", dark ? "#e7ecf2" : "#1a2029"),
|
||||
muted: v("--muted", dark ? "#9aa6b2" : "#5b6673"),
|
||||
grid: v("--border", dark ? "#2a323c" : "#dde3ea"),
|
||||
accent: v("--accent", "#ec4899"),
|
||||
accent: v("--accent", "#f0803c"),
|
||||
hi, lo,
|
||||
// Distinct line/point accents for the three added series; the graded fan
|
||||
// behind them still uses the shared diverging tier colors (same as temps).
|
||||
feels: v("--accent", "#ec4899"), // "feels like" = magenta accent
|
||||
feels: v("--accent", "#f0803c"), // "feels like" = orange accent
|
||||
humid: "#2ea9bf", // humidity = cyan
|
||||
wind: "#5aa9a3", // wind speed = teal
|
||||
gust: "#8f86d8", // wind gust = periwinkle
|
||||
|
|
@ -648,11 +648,11 @@ function precipChart(days, n, xFor, C) {
|
|||
// "Days since last rain" dry-streak color: rain days are blue; each dry day warms
|
||||
// from a light base toward dark red, saturating at 14 consecutive dry days.
|
||||
// (Mirrors the calendar's dry-streak ramp.)
|
||||
const DRY_BASE = [247, 214, 226], DRY_MAX = [125, 26, 73], DRY_CAP = 14;
|
||||
const DRY_BASE = [247, 217, 176], DRY_MAX = [122, 13, 26], DRY_CAP = 14;
|
||||
const lerpRgb = (a, b, t) => `rgb(${a.map((x, i) => Math.round(x + (b[i] - x) * t)).join(",")})`;
|
||||
function drynessColor(dsr) {
|
||||
if (dsr == null) return "";
|
||||
if (dsr === 0) return "#6d28d9"; // measurable rain that day
|
||||
if (dsr === 0) return "#2b7bba"; // measurable rain that day
|
||||
return lerpRgb(DRY_BASE, DRY_MAX, Math.min(dsr, DRY_CAP) / DRY_CAP);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,26 +4,26 @@
|
|||
// intentionally re-declares the small shared tier constants so it stays independent
|
||||
// of app.js (the map page).
|
||||
|
||||
// 9-step diverging temperature scale ("Orchid Sunset": violet -> blush -> magenta).
|
||||
// 9-step diverging temperature scale (cold navy -> green -> hot red).
|
||||
const TIER_COLORS = {
|
||||
"rec-hot": "#7d1a49", "very-hot": "#db2777", "hot": "#f472b6", "warm": "#f9a8d4",
|
||||
"normal": "#f0dce8",
|
||||
"cool": "#cbb6f7", "cold": "#9b6ef0", "very-cold": "#6d28d9", "rec-cold": "#3b0764",
|
||||
"rec-hot": "#8f0e20", "very-hot": "#dd6b52", "hot": "#ef9351", "warm": "#f6c18a",
|
||||
"normal": "#4a9d5b",
|
||||
"cool": "#92c5de", "cold": "#4393c3", "very-cold": "#2166ac", "rec-cold": "#0a2f6b",
|
||||
};
|
||||
// 9-step rain-intensity ramp (rain-day percentile): light lilac -> orchid -> deep violet.
|
||||
// 9-step rain-intensity ramp (rain-day percentile): light green -> teal -> dark navy.
|
||||
const PRECIP_COLORS = {
|
||||
"wet-1": "#f3e8ff", "wet-2": "#e9d5ff", "wet-3": "#d8b4fe", "wet-4": "#c084fc", "wet-5": "#a855f7",
|
||||
"wet-6": "#9333ea", "wet-7": "#7e22ce", "wet-8": "#6b21a8", "wet-9": "#4c1d95",
|
||||
"wet-1": "#d9f0d3", "wet-2": "#b7e2b1", "wet-3": "#8fd18f", "wet-4": "#5cba9f", "wet-5": "#35a1c0",
|
||||
"wet-6": "#2b8cbe", "wet-7": "#226bb3", "wet-8": "#164a97", "wet-9": "#08306b",
|
||||
};
|
||||
|
||||
// "Days since last rain" dry-streak color: rain days are blue; each dry day warms
|
||||
// from a light base toward dark red, saturating at 14 consecutive dry days.
|
||||
const DRY_BASE = [247, 214, 226], DRY_MAX = [125, 26, 73], DRY_CAP = 14;
|
||||
const DRY_BASE = [247, 217, 176], DRY_MAX = [122, 13, 26], DRY_CAP = 14;
|
||||
const lerpRgb = (a, b, t) =>
|
||||
`rgb(${a.map((x, i) => Math.round(x + (b[i] - x) * t)).join(",")})`;
|
||||
function drynessColor(dsr) {
|
||||
if (dsr == null) return "";
|
||||
if (dsr === 0) return "#6d28d9"; // measurable rain that day
|
||||
if (dsr === 0) return "#2b7bba"; // measurable rain that day
|
||||
return lerpRgb(DRY_BASE, DRY_MAX, Math.min(dsr, DRY_CAP) / DRY_CAP);
|
||||
}
|
||||
// low -> high percentile scale, per metric (temp vs precip use different classes)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@
|
|||
// so the page stays independent of app.js.
|
||||
|
||||
const TIER_COLORS = {
|
||||
"rec-hot": "#7d1a49", "very-hot": "#db2777", "hot": "#f472b6", "warm": "#f9a8d4",
|
||||
"normal": "#f0dce8",
|
||||
"cool": "#cbb6f7", "cold": "#9b6ef0", "very-cold": "#6d28d9", "rec-cold": "#3b0764",
|
||||
"rec-hot": "#8f0e20", "very-hot": "#dd6b52", "hot": "#ef9351", "warm": "#f6c18a",
|
||||
"normal": "#4a9d5b",
|
||||
"cool": "#92c5de", "cold": "#4393c3", "very-cold": "#2166ac", "rec-cold": "#0a2f6b",
|
||||
};
|
||||
const PRECIP_COLORS = {
|
||||
"wet-1": "#f3e8ff", "wet-2": "#e9d5ff", "wet-3": "#d8b4fe", "wet-4": "#c084fc", "wet-5": "#a855f7",
|
||||
"wet-6": "#9333ea", "wet-7": "#7e22ce", "wet-8": "#6b21a8", "wet-9": "#4c1d95",
|
||||
"wet-1": "#d9f0d3", "wet-2": "#b7e2b1", "wet-3": "#8fd18f", "wet-4": "#5cba9f", "wet-5": "#35a1c0",
|
||||
"wet-6": "#2b8cbe", "wet-7": "#226bb3", "wet-8": "#164a97", "wet-9": "#08306b",
|
||||
};
|
||||
const DRY_COLOR = "#cbb26a";
|
||||
const DRY_COLOR = "#c9a24a";
|
||||
|
||||
// Temps go through the shared unit formatter; the rest are unit-agnostic.
|
||||
const fmtTemp = (v) => window.Thermograph.fmtTemp(v);
|
||||
|
|
|
|||
|
|
@ -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: "© 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: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> © <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
|
||||
|
|
|
|||
|
|
@ -5,32 +5,31 @@
|
|||
--border: #2a323c;
|
||||
--text: #e7ecf2;
|
||||
--muted: #9aa6b2;
|
||||
--accent: #ec4899;
|
||||
--accent: #f0803c;
|
||||
|
||||
/* temperature grades: 9-step diverging cold -> neutral -> hot ("Orchid Sunset").
|
||||
Cool end = violet/lavender, warm end = rose/magenta; rec-* are the "Near Record"
|
||||
danger tiers — deliberately dark/saturated. */
|
||||
--rec-cold: #3b0764;
|
||||
--very-cold: #6d28d9;
|
||||
--cold: #9b6ef0;
|
||||
--cool: #cbb6f7;
|
||||
--normal: #f0dce8; /* middle of the diverging temp scale = soft blush (see light-theme override) */
|
||||
--warm: #f9a8d4;
|
||||
--hot: #f472b6;
|
||||
--very-hot: #db2777;
|
||||
--rec-hot: #7d1a49;
|
||||
/* temperature grades: 9-step diverging cold -> green -> hot (colorblind-safe).
|
||||
rec-* are the "Near Record" danger tiers — deliberately dark/saturated. */
|
||||
--rec-cold: #0a2f6b;
|
||||
--very-cold: #2166ac;
|
||||
--cold: #4393c3;
|
||||
--cool: #92c5de;
|
||||
--normal: #4a9d5b; /* middle of the diverging temp scale = green */
|
||||
--warm: #f6c18a;
|
||||
--hot: #ef9351;
|
||||
--very-hot: #dd6b52;
|
||||
--rec-hot: #8f0e20;
|
||||
|
||||
/* precipitation: "dry" + 9 rain-intensity tiers, light lilac -> orchid -> deep violet */
|
||||
--dry: #cbb26a;
|
||||
--wet-1: #f3e8ff;
|
||||
--wet-2: #e9d5ff;
|
||||
--wet-3: #d8b4fe;
|
||||
--wet-4: #c084fc;
|
||||
--wet-5: #a855f7; /* middle of the rain scale */
|
||||
--wet-6: #9333ea;
|
||||
--wet-7: #7e22ce;
|
||||
--wet-8: #6b21a8;
|
||||
--wet-9: #4c1d95;
|
||||
/* precipitation: "dry" + 9 rain-intensity tiers, light green -> teal -> dark navy */
|
||||
--dry: #c9a24a;
|
||||
--wet-1: #d9f0d3;
|
||||
--wet-2: #b7e2b1;
|
||||
--wet-3: #8fd18f;
|
||||
--wet-4: #5cba9f;
|
||||
--wet-5: #35a1c0; /* middle of the rain scale */
|
||||
--wet-6: #2b8cbe;
|
||||
--wet-7: #226bb3;
|
||||
--wet-8: #164a97;
|
||||
--wet-9: #08306b;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
|
|
@ -41,11 +40,6 @@
|
|||
--border: #dde3ea;
|
||||
--text: #1a2029;
|
||||
--muted: #5b6673;
|
||||
/* The soft-blush middle tiers vanish on a white surface — darken them just
|
||||
enough to stay legible as swatches, cell fills, and grade text. */
|
||||
--normal: #c05a8a;
|
||||
--warm: #ef7fbe;
|
||||
--cool: #a98bf0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,12 +161,12 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
|
|||
display: flex; align-items: center; gap: 13px;
|
||||
width: 100%; margin: 0 0 20px; padding: 14px 16px; min-height: 60px;
|
||||
border: none; border-radius: 13px; text-decoration: none;
|
||||
color: #2a0716; background: linear-gradient(135deg, #f472b6, #db2777);
|
||||
box-shadow: 0 4px 16px rgba(219, 39, 119, .3);
|
||||
color: #1a1206; background: linear-gradient(135deg, #f79556, #ea722c);
|
||||
box-shadow: 0 4px 16px rgba(240, 128, 60, .3);
|
||||
transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
|
||||
}
|
||||
.cta-cal:hover { transform: translateY(-1px); box-shadow: 0 7px 22px rgba(219, 39, 119, .42); filter: brightness(1.04); }
|
||||
.cta-cal:active { transform: translateY(0); box-shadow: 0 3px 10px rgba(219, 39, 119, .34); }
|
||||
.cta-cal:hover { transform: translateY(-1px); box-shadow: 0 7px 22px rgba(240, 128, 60, .42); filter: brightness(1.04); }
|
||||
.cta-cal:active { transform: translateY(0); box-shadow: 0 3px 10px rgba(240, 128, 60, .34); }
|
||||
.cta-cal:focus-visible { outline: 3px solid var(--text); outline-offset: 2px; }
|
||||
.cta-cal-icon { font-size: 26px; line-height: 1; flex-shrink: 0; }
|
||||
.cta-cal-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
||||
|
|
@ -200,7 +194,7 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
|
|||
.chart-toggle button.active[data-metric="wind"] { background: #5aa9a3; color: #08201e; }
|
||||
.chart-toggle button.active[data-metric="gust"] { background: #8f86d8; color: #100c26; }
|
||||
.chart-toggle button.active[data-metric="precip"] { background: var(--wet-6); color: #fff; }
|
||||
.chart-toggle button.active[data-metric="dry"] { background: #cbb26a; color: #241a04; }
|
||||
.chart-toggle button.active[data-metric="dry"] { background: #c9a24a; color: #241a04; }
|
||||
.chart-legend {
|
||||
display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; color: var(--muted); margin-bottom: 8px;
|
||||
}
|
||||
|
|
@ -705,7 +699,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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue