Start the NPS Unigrid visual redesign
Black topbar banner with live map-center coordinates, a black header (with NPS pictogram) on waypoint popups, offline basemap wood/park colors unified with the online Liberty green, and the sidebar grouped into the planned Explorer / Offline hub / Navigation menu sections.
This commit is contained in:
1 parent
d1f2e7376e
commit
bc9ea58614
4 files changed
+112
-37
No files matched your search
+5
-2
@@ -916,9 +916,12 @@ function gpxFileUrl(path) {
|
||||
|
||||
// properties come straight from an uploaded GPX file — untrusted input —
|
||||
// so every value is escaped before landing in the popup's HTML.
|
||||
function popupHtml({ name, description, time, category, photos }) {
|
||||
function popupHtml({ name, description, time, category, photos, icon }) {
|
||||
const parts = [];
|
||||
if (name) parts.push(`<strong>${escapeHtml(name)}</strong>`);
|
||||
if (name) {
|
||||
const glyph = icon && POI_ICONS[icon] ? `<span class="gpx-popup__header-icon">${POI_ICONS[icon]}</span>` : "";
|
||||
parts.push(`<div class="gpx-popup__header"><strong>${escapeHtml(name)}</strong>${glyph}</div>`);
|
||||
}
|
||||
if (category) parts.push(`<p class="gpx-popup__category">${escapeHtml(category)}</p>`);
|
||||
if (photos?.length > 0) parts.push(formatPhotos(photos));
|
||||
if (description) parts.push(formatDescription(description));
|
||||
|
||||
+54
-29
@@ -22,22 +22,23 @@ const ZOOM = 13;
|
||||
const ONLINE_STYLE_URL = "https://tiles.openfreemap.org/styles/liberty";
|
||||
|
||||
// Recolors OpenFreeMap Liberty to the same NPS-inspired palette as
|
||||
// OFFLINE_THEME below — warm cream ground, brown/khaki land cover, green
|
||||
// reserved for parks, muted roads/boundaries — mapped onto Liberty's
|
||||
// OpenMapTiles layer ids instead of protomaps' theme roles (the two
|
||||
// schemas don't share layer names, so this is a separate hand-built
|
||||
// table, not a shared object). Only the layers that dominate the map's
|
||||
// overall color read are touched; labels, halos, rail, and minor
|
||||
// OFFLINE_THEME below — warm cream ground, muted roads/boundaries — mapped
|
||||
// onto Liberty's OpenMapTiles layer ids instead of protomaps' theme roles
|
||||
// (the two schemas don't share layer names, so this is a separate
|
||||
// hand-built table, not a shared object). Only the layers that dominate the
|
||||
// map's overall color read are touched; labels, halos, rail, and minor
|
||||
// overlays (cemetery/hospital/school/pitch/track shading, building
|
||||
// outlines) are left at Liberty's own defaults — same "not a full
|
||||
// recolor" scope as OFFLINE_THEME. Road casings have no protomaps-role
|
||||
// equivalent to reuse (offline roads don't get a separate outline), so
|
||||
// #c9a66b there is reasoned to fit the family rather than sourced from
|
||||
// anywhere real.
|
||||
//
|
||||
// wood/grass are deliberately left unpatched — Liberty's own green reads
|
||||
// better than this app's earlier brown/khaki recolor, and OFFLINE_THEME's
|
||||
// wood_a/scrub_a below were changed to match Liberty's green instead.
|
||||
const ONLINE_STYLE_PATCH = {
|
||||
background: { "background-color": "#f9f6ef" },
|
||||
landcover_wood: { "fill-color": "#c9bd9c" },
|
||||
landcover_grass: { "fill-color": "#d9cfb0" },
|
||||
landcover_sand: { "fill-color": "#f0e4c4" },
|
||||
water: { "fill-color": "#a3cedf" },
|
||||
park: { "fill-color": "#b3e378" },
|
||||
@@ -155,19 +156,25 @@ const OFFLINE_THEME = {
|
||||
background: "#f9f6ef", // real: Park Tiles' own background, hsl(40, 37%, 97%)
|
||||
earth: "#f9f6ef",
|
||||
water: "#a3cedf",
|
||||
// Brown/khaki, not green: in Park Tiles' own Imagery style, green is
|
||||
// specifically the protected-area/park color (below), not a general land
|
||||
// cover fill — actual forest there is just the aerial photo underneath,
|
||||
// which this offline style has no equivalent of. Using that same vivid
|
||||
// green for ordinary wood/scrub as well (an earlier version of this
|
||||
// theme did) made everything read as "green," not "brown with green
|
||||
// parks" — reversed here to match the real distinction.
|
||||
wood_a: "#c9bd9c",
|
||||
wood_b: "#bcae8a",
|
||||
scrub_a: "#d9cfb0",
|
||||
scrub_b: "#cfc29d",
|
||||
park_a: "#c8e2a0",
|
||||
park_b: "#b3e378", // real: Park Tiles' protected-area/park-point green
|
||||
// Matches OpenFreeMap Liberty's own wood/grass green (its landcover_wood
|
||||
// hsla(98,61%,72%,0.7) and landcover_grass rgba(176,213,154,1) at 0.3
|
||||
// opacity, blended over the cream background) — the online map's actual
|
||||
// look whenever ONLINE_STYLE_PATCH's brown/khaki recolor fails to apply
|
||||
// (see loadOnlineStyle's fetch fallback) turned out to be the look this
|
||||
// app's users actually want, so offline was changed to match it instead
|
||||
// of chasing the patch's own reliability.
|
||||
wood_a: "#c3e8ab",
|
||||
wood_b: "#a8d888",
|
||||
scrub_a: "#dcecc9",
|
||||
scrub_b: "#cfe3b8",
|
||||
// Close to wood_b, not the more saturated Park Tiles green: protomaps'
|
||||
// theme routes "forest"/"nature_reserve"/"protected_area" (e.g. the Malé
|
||||
// Karpaty CHKO boundary) through this same park_a/park_b pair as actual
|
||||
// named parks — Liberty's online style doesn't make that reserve-boundary
|
||||
// distinction at all, so a visibly different green here reads as an
|
||||
// offline-only blotch rather than a deliberate distinction.
|
||||
park_a: "#c3e8ab",
|
||||
park_b: "#a8d888",
|
||||
sand: "#f0e4c4",
|
||||
beach: "#f0e4c4",
|
||||
buildings: "#ded7cc",
|
||||
@@ -388,25 +395,43 @@ map.once("style.load", () => {
|
||||
map.addControl(new OverviewMapControl({}), "top-right");
|
||||
});
|
||||
|
||||
const coordsLabel = document.querySelector(".topbar__coords");
|
||||
const updateCoords = () => {
|
||||
const { lng, lat } = map.getCenter();
|
||||
coordsLabel.textContent = `${lat.toFixed(5)}, ${lng.toFixed(5)}`;
|
||||
};
|
||||
updateCoords();
|
||||
map.on("move", updateCoords);
|
||||
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
|
||||
// Grouped into the TODO's planned 4-module menu (Explorer / Offline hub /
|
||||
// Navigation / Camper & HW) ahead of that split actually happening —
|
||||
// Camper & HW has no sidebar item yet (leveling/solar/telemetry are all
|
||||
// still unbuilt), so it's left out rather than shown empty.
|
||||
const layerToggle = new LayerToggleControl(applyStyle);
|
||||
const profilePanel = new TrackProfilePanel(map);
|
||||
profilePanel.mount();
|
||||
|
||||
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Explorer"></div>`);
|
||||
new GpxPanelControl(map, profilePanel).mount(sidebar);
|
||||
|
||||
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Offline hub"></div>`);
|
||||
layerToggle.mount(sidebar);
|
||||
layerToggle.setActive("online");
|
||||
new RadarControl(map).mount(sidebar);
|
||||
|
||||
sidebar.insertAdjacentHTML("beforeend", `<div class="sidebar-group-label" title="Navigation"></div>`);
|
||||
gnssControl.mount(sidebar);
|
||||
new LiveTrackPanelControl(map).mount(sidebar);
|
||||
|
||||
// The sidebar already has a "Base map" icon (opens the same panel) —
|
||||
// this is a second entry point for it, grouped with Home/zoom on the map
|
||||
// itself rather than off in the page's own side rail, matching NPS's
|
||||
// layout. Added after mount() since it reuses that panel/toggle state.
|
||||
// layout. layerToggle only needs to exist (not be mounted yet) for this.
|
||||
const mapLayersButton = new MapLayersButton(layerToggle);
|
||||
map.addControl(mapLayersButton, "top-left");
|
||||
|
||||
const profilePanel = new TrackProfilePanel(map);
|
||||
profilePanel.mount();
|
||||
new GpxPanelControl(map, profilePanel).mount(sidebar);
|
||||
new RadarControl(map).mount(sidebar);
|
||||
gnssControl.mount(sidebar);
|
||||
new LiveTrackPanelControl(map).mount(sidebar);
|
||||
|
||||
function applyStyle(name) {
|
||||
layerToggle.setActive(name);
|
||||
map.setStyle(name === "offline" ? offlineStyle() : ONLINE_STYLE);
|
||||
|
||||
Reference in new issue
Block a user