# 09-Sep-2026 — OS Maps routes page - search-first landing, real map thumbnails, mobile-responsive card [#99](https://github.com/nbarrett/ngx-ramblers/issues/99)

## [build 885](https://github.com/nbarrett/ngx-ramblers/actions/runs/34342625474) — [commit 66a062c](https://github.com/nbarrett/ngx-ramblers/commit/66a062c5ef07ed6b5e4e6d2a34969d8efaaf60c3)

_____

### **maps**: OS Maps routes page ([#99](https://github.com/nbarrett/ngx-ramblers/issues/99))

## The problem

The routes page loaded and displayed every saved route at once (630+ on a
busy account) in a plain table - overwhelming, slow to scan, and none of it
worked on a phone.

## Search-first landing, capped results

Nothing is shown until you type a search or choose a filter; the landing
state explains how many routes there are and prompts you to search. Results
are capped to the first 50 matches, with a note showing the total and asking
you to narrow the search when there are more. Sorting moved to a Sort by
control with a direction toggle.

## Real map thumbnails

For routes that have already been converted, the real GPX geometry is
already held in S3, so each card fetches it (reusing GpxParserService,
RouteFollowPayloadService.gpxDownloadUrl and MapTilesService's base layer -
the same machinery the app's full map views already use) and draws an actual
small Leaflet map: real OpenStreetMap tiles, the route line in its saved
colour, fitted to the route's bounds. A checkmark badge on the thumbnail
corner shows imported status, matching OS Maps' own visual language, instead
of a separate text field. Not-yet-imported routes, which have no geometry
anywhere in our system, keep an icon placeholder.

Getting the map's lifecycle right took a few passes: Angular's structural
@if was recreating the map's container on every data change, and the leaflet
directive gave no way to guard against Leaflet's "container is being reused"
error when @for reused a DOM node across component instances faster than the
old map's teardown ran. Fixed by taking direct control of L.map() construction
in ngAfterViewInit, with an explicit clear of any stale internal marker
before creating a new map.

## Card layout matching OS Maps' own design

Distance, date, a source badge and an imported-status line were crammed into
one free-flowing row, so a longer title or date pushed everything after it
sideways - a jagged, misaligned look row to row. Rebuilt to match OS Maps'
own card design instead: one short metadata line (distance + a compact date,
not the full weekday form), source as an icon-only tooltip rather than a text
badge, imported status moved to the thumbnail badge. The title (for
already-imported routes) and the thumbnail now open this app's own edit page
directly, since "Open in OS Maps" already covers the external link and
having both was redundant; the separate edit icon button is gone.

Also added the real OS Maps logo (already used elsewhere in the app for
attribution) to the "Open in OS Maps" link, in place of a generic icon.

## Mobile

- The thumbnail stretches to fill the card's actual height rather than
sitting at a fixed size while wrapped titles make mobile cards much
taller - capped at 140px so a very tall card doesn't stretch it into a
sliver.
- Back to walks admin / Convert selected to GPX / Load routes from OS Maps
go full width and stack on narrow screens; Last loaded and the refresh
button stay grouped as one unit.
- Search / Show / Sort by each take the full row width on narrow screens.
- Tightened row gaps that were adding more vertical space than the shorter,
single-line content needed.

## Diagnostics

Added a one-off debug log of the real OS Maps routes/search response shape
(route names redacted) - the fields we map today (id, title, date, distance)
are a small slice of what that response might carry, and this lets a future
pass build a real preview for not-yet-imported routes against the actual
payload instead of a guess.