Commit Graph
16 Commits
Author SHA1 Message Date
randy 465a644365 Split notes into a title + body, with light self-authored markdown
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 13s
Both NoteSaveForm (create) and the popup's inline Edit form now have
a title input (-> properties.name, shown in the black header, same as
every other waypoint popup) and a separate body textarea (->
properties.description) for more detail than a single line.

New formatNoteBody renders that body with a small self-rolled
markdown subset — **bold**, *italic*, auto-linked URLs (reusing the
existing linkify), newlines to <br> — deliberately a new function, not
a change to formatDescription: that one renders uploaded GPX/park4night
content, which is untrusted, and docs/nps-resources.adoc already has a
specific call not to add markdown rendering to that path. A note's
body is written by the logged-in viewer themselves, not uploaded, so
that concern doesn't apply here — the escape-then-selectively-markup
order (linkify first, since it does its own escaping, then wrap
already-escaped text in real <strong>/<em> tags) keeps it safe either
way.

Verified live: title renders in the popup header, **bold**/*italic*/
a URL in the body all render correctly. Full test suite: 115 runs, 0
failures (unaffected — description is just another property, not
something the backend routes inspect).
2026-09-09 13:03:42 +02:00
randy 2a22906a68 Fix Edit/Delete on notes saved before properties.id existed
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
The earliest notes (saved before the previous commit added id
tracking) have no properties.id — update/delete target a feature by
that id, so offering Edit/Delete for one without it just 404s
("Could not delete/save the note", the generic fetch-failure alert).

The popup no longer offers Edit/Delete without an id. New
rake gpx:backfill_note_ids assigns one to any pre-existing Note
feature missing it, so already-saved notes become editable again too
— run once against wherever data/gpx actually lives (e.g. inside the
deployed container).
2026-09-09 12:58:19 +02:00
randy b0576f3725 Make Measure's vertices draggable and deletable
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
Drag: mousedown on a vertex circle calls event.preventDefault() (the
documented way to opt a gesture out of MapLibre's own drag-to-pan),
then a map-wide mousemove/mouseup follows the cursor and updates that
point's coordinates live. Delete: clicking a vertex selects it (shown
larger/yellow); Delete or Backspace removes it, guarded against
eating a keystroke meant for an actual text input on the page.

A vertex's own mousedown sets a one-shot flag so the same click
doesn't also fall through to the generic map-click handler and add a
brand new point on top of it.
2026-09-09 12:47:44 +02:00
randy aafb4cb4a0 Consolidate note-drawing into Measure; add edit/delete
CI / check (push) Successful in 39s
CI / deploy (push) Successful in 13s
Measure already draws distance lines and area polygons by hand — a
second click-to-draw UI in the notes tool (Point/Area mode, from the
previous commit) duplicated that. Replaced it with a "Save as note"
button on the Measure panel that saves whatever shape is currently
drawn there; NotesControl goes back to being just a one-click point
pin. Both share a single NoteSaveForm (notes.js) for the note-text +
target-layer-file UI instead of two copies of it.

gpx.js: the "lines" source now also renders a note-flagged LineString
(dashed, popup-on-click) alongside the Polygon fill/outline from
before — the plain track-line layer excludes category:"Note" features
so a saved distance note doesn't also get the track hover-summary/
profile-panel treatment.

Notes are now individually editable/deletable from their own popup
(logged-in only): Edit swaps the popup content for an inline
textarea, Delete confirms and removes. Both target the feature by a
new client-generated properties.id rather than array position (new
GpxStore#update_feature/#delete_feature, PUT/DELETE /api/gpx/notes),
since neither array index nor the note's own text (the thing being
edited) is a stable identifier.

Verified live: Measure's Save button (disabled/enabled state, saves
the exact on-screen shape), the popup's Edit/Delete buttons and inline
edit form. Full test suite: 115 runs, 0 failures (new coverage for
update_feature/delete_feature and the PUT/DELETE routes).
2026-09-09 11:39:36 +02:00
randy db58468187 Add polygon notes (Area mode) to the user overlay tool
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
notes.js: Point/Area mode toggle mirroring measure.js's UX — Area
mode accumulates clicked vertices with a live dashed-preview polygon
(own small preview source/layers), a Finish button once 3+ corners
are placed, then the same save form as Point mode.

gpx.js's _addLayers now also renders Polygon features from a file's
"lines" source (fill + outline, filtered by geometry-type — the
existing line layer already only draws LineString, so this is just
two more layers on the same source, not a new bucket) with
popup-on-click like a waypoint, not the track line's hover-summary/
profile-panel behavior. Without this a saved polygon wouldn't have
rendered back on reload.

Fixed along the way: .notes-panel__form/.notes-panel__modes both set
their own `display`, which silently wins over the browser's default
`[hidden] { display: none }` (author styles always beat user-agent
ones) — same gotcha .gpx-panel__action[hidden] already has a comment
about. The form was never actually invisible before being opened.

Verified live: real polygon file (fill/outline render, click ->
popup) and the full Area-mode draw flow (mode switch, live preview,
Finish, form) via headless Chrome. Full test suite: 104 runs, 0
failures — one new backend test confirms a Polygon feature round-
trips through POST /api/gpx/notes.

Known gap (noted in TODO.adoc): the category filter matrix only
re-slices the points source, so toggling "Note" off hides point notes
but not polygon ones.
2026-09-09 11:27:25 +02:00
randy f53c74e06f Add rake overpass:pois to fetch camper POIs from Overpass
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
lib/maptool/overpass_pois.rb: queries Overpass for drinking water,
dump stations, LPG refill, toilets, laundromats, supermarkets/
convenience stores, and springs within a bbox, writes GeoJSON. A
dev-time tool (like the offline.pmtiles/terrain.pmtiles generation
steps already documented) — not called by the running app, drop the
output into data/gpx/ or upload it through the Tracks panel like any
other .geojson layer.

Verified against the real Overpass API (88 POIs for central
Bratislava) in addition to the new unit tests (pure to_geojson/
build_query logic, no network in the suite itself). Full suite: 103
runs, 0 failures.
2026-09-09 10:21:41 +02:00
randy aa2b96ac70 Add a "user overlay" tool: click the map, save a note
New map-corner "Add note" control (public/js/notes.js), mirroring
measure.js's click-to-place UX. Click the map, write a short note,
pick an existing .geojson layer file or name a new one — saved via a
new GpxStore#append_feature (grows the target file in place, unlike
save()'s always-disambiguate-the-filename behavior) through a new
POST /api/gpx/notes route.

No new rendering path: a note is just another point in a .geojson
file the Tracks panel's tree already lists, checkboxes, and pops up —
visibility toggling ("layers") comes for free from that existing
machinery, per-file, with no changes needed there.

Points only for now — a polygon mode would need gpx.js's point/line
split taught a third Polygon bucket first, or a saved polygon
wouldn't render back on reload (see TODO.adoc).

Covered by new tests: GpxStore#append_feature (create/append/missing-
path/filename-safety) and the /api/gpx/notes route (auth gate, create,
append, malformed/missing-geometry rejection, 404 on a missing
target). Full suite: 97 runs, 0 failures.
2026-09-09 10:18:50 +02:00
randy 5caf865fc8 Cache radar tile images with a Service Worker
CI / check (push) Successful in 40s
CI / deploy (push) Successful in 12s
public/sw.js: network-falling-back-to-cache for RainViewer radar tile
requests specifically (nothing else — the app itself is served by the
same local server that's already the offline resource in the van, so
there's no app-shell to precache). Registered from layout.erb, a no-op
where it can't register (insecure context) rather than an error.

Verified: registers and controls the page, tiles get cached on a
normal fetch, cache.match() correctly retrieves them by the same
request. CDP's network-blocking simulation doesn't interact cleanly
with Service Worker fetch interception (a known tooling quirk, not
specific to this), so the actual offline fallback path is the
standard try/catch pattern, verified by code review rather than a
simulated-offline screenshot.
2026-09-09 09:51:29 +02:00
randy a98b8dbd47 Mark GPX drag-and-drop import as done in TODO 2026-09-09 09:47:14 +02:00
randy 8d090b0774 Cache the weather forecast for offline fallback
Radar flyout now also shows a 3-day Open-Meteo forecast (free, no API
key) for the map's current center. Radar frames and the forecast fetch
independently — one being unreachable doesn't hide the other. The last
successful forecast is cached in localStorage and shown (with a
"cached from" note) when the live fetch fails, so there's still
something useful once actually offline.

Radar tile images themselves aren't cached — that needs a Service
Worker, left as a separate follow-up (see TODO.adoc).
2026-09-09 09:42:10 +02:00
randy 707e71caf1 Add elevation-tinted terrain (hypsometric color-relief layer)
Reuses the same raster-dem source the hillshade toggle already added
— a color-relief layer tints by elevation band (green valleys through
brown mid-slopes to pale grey peaks, in this app's own palette) under
the hillshade layer, so one toggle gives the combined shaded-relief
look instead of two separate layers.
2026-09-09 09:33:00 +02:00
randy 77a4c96b1c Add a hillshade/terrain-shading toggle to the map
Sidebar toggle (new HillshadeControl) adds a raster-dem hillshade
layer: public Terrarium tiles when online, or a local
data/terrain.pmtiles when present (mirrors offline.pmtiles' optional-
local-file pattern, new /api/terrain-tiles + /tiles/terrain.pmtiles
endpoints). No offline terrain data is bundled, so the toggle is
online-only until one is generated — see docs/development.adoc for
how.
2026-09-09 09:27:17 +02:00
randy f49e44800a Distinguish unpaved tracks from paved roads on both basemaps
Offline: fill in protomaps' "other" road-kind color (unset before,
so tracks/paths silently fell back to plain white against the cream
background); also fixes a dead "minor" theme key that was never read
by the actual paint expression (only minor_a/minor_b is), so ordinary
streets were quietly using the base theme's default yellow instead of
this app's cream.

Online: Liberty's own road_service_track layer merges paved service
roads with unpaved tracks into one color, which isn't safe to just
recolor brown (real driveways aren't unpaved). Clones it into a
second layer scoped to class=="track" only, dashed and dirt-brown,
matching the offline treatment without mislabeling paved service
roads.
2026-09-09 09:17:00 +02:00
randy 8ca5ca9bc1 Add an offline-data status dot to the topbar
Small green/gray indicator reusing the existing /api/offline-tiles
check, showing at a glance whether this server has offline map data.
Closes out the top banner TODO item — DEM elevation and a hamburger
menu are intentionally left out (no DEM layer yet, and the sidebar
isn't mobile-collapsed).
2026-09-09 09:11:52 +02:00
randy 53b0e8961b Turn the GPX category legend into a clickable Unigrid filter matrix
CI / check (push) Successful in 2m5s
CI / deploy (push) Successful in 13s
Legend items are now toggle buttons (icon grid, not a color-swatch
list) that hide/show that category's waypoints on the map. Filtering
re-slices each file's source data rather than using a layer filter,
since MapLibre clusters a GeoJSON source's full data regardless of
what a layer filter hides.
2026-09-09 09:09:07 +02:00
randy d1f2e7376e Add offline vanlife feature ideas to TODO
Captures ideas for offline maps/POI data, an NPS Unigrid-inspired
visual redesign, a 4-module menu reorg, and custom layer support.
Hardware-dependent features (leveling, Victron/HA telemetry) are
parked under Nice to have for later.
2026-09-09 08:18:07 +02:00