Make public transport routes discoverable with shareable search
Add one-click examples and route search by number or metadata, with transport type, location and map-area filters. Preserve search filters and bounds in shareable URLs and restore searches on reload and browser navigation. Validate with 91 passing tests, including desktop and mobile browser coverage, and strict mypy checks. Closes #2
This commit is contained in:
parent
29afb4f115
commit
a79b0a7098
7 changed files with 919 additions and 12 deletions
|
|
@ -32,15 +32,90 @@
|
|||
<!-- Scrollable content area -->
|
||||
<div id="sidebar-inner">
|
||||
|
||||
<form id="route-search-form" class="mb-3">
|
||||
<label for="route-search" class="form-label fw-semibold small">Find a public transport route</label>
|
||||
<div class="input-group input-group-sm mb-2">
|
||||
<input id="route-search" type="search" class="form-control" required
|
||||
minlength="2" maxlength="100" placeholder="e.g. M11 or Bristol Airport"
|
||||
aria-describedby="search-help">
|
||||
<button id="search-button" class="btn btn-primary" type="submit">Search</button>
|
||||
</div>
|
||||
<label for="search-mode" class="visually-hidden">Transport type</label>
|
||||
<select id="search-mode" class="form-select form-select-sm">
|
||||
<option value="">All transport types</option>
|
||||
<option value="bus">Bus</option>
|
||||
<option value="trolleybus">Trolleybus</option>
|
||||
<option value="tram">Tram</option>
|
||||
<option value="subway">Subway / metro</option>
|
||||
<option value="train">Train</option>
|
||||
<option value="light_rail">Light rail</option>
|
||||
<option value="monorail">Monorail</option>
|
||||
<option value="ferry">Ferry</option>
|
||||
<option value="funicular">Funicular</option>
|
||||
</select>
|
||||
<label for="search-location" class="form-label small mt-2 mb-1">Location (optional)</label>
|
||||
<input id="search-location" class="form-control form-control-sm" type="text"
|
||||
minlength="2" maxlength="100" placeholder="e.g. Bristol, UK" autocomplete="off"
|
||||
aria-describedby="search-area-help">
|
||||
<div class="form-check mt-2">
|
||||
<input id="search-map-area" class="form-check-input" type="checkbox">
|
||||
<label for="search-map-area" class="form-check-label small">Search this map area</label>
|
||||
</div>
|
||||
<p id="search-help" class="form-text mb-0">Search by route number, name,
|
||||
destination, operator or network. Route numbers match exactly.</p>
|
||||
<p id="search-area-help" class="form-text mb-0">Leave location blank to search worldwide,
|
||||
or limit to a place or the current map view. Routes can extend outside the area.</p>
|
||||
<p id="search-area-label" class="small mt-2 mb-0"></p>
|
||||
<p class="form-text mb-0">After searching, copy the page URL to share these filters.</p>
|
||||
<div id="location-results" class="list-group small mt-2"></div>
|
||||
<p id="search-status" class="small mt-2 mb-0" role="status" aria-live="polite"></p>
|
||||
<div id="search-results" class="list-group small mt-2"></div>
|
||||
</form>
|
||||
|
||||
<!-- A first route is one click away; no OSM knowledge required. -->
|
||||
<details class="mb-3"{% if not relation_id %} open{% endif %}>
|
||||
<summary class="fw-semibold">Try a public transport route</summary>
|
||||
<p class="small mt-2 mb-2">View a route on the map and download it as GeoJSON.
|
||||
Choose an example to get started:</p>
|
||||
<div class="list-group small mb-2">
|
||||
<a class="list-group-item list-group-item-action"
|
||||
href="{{ url_for('route_page', relation_id=18892969) }}">
|
||||
<span class="fw-semibold d-block">Bristol airport bus A1</span>
|
||||
<span class="text-muted">Airport → Bus Station · Bus</span>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action"
|
||||
href="{{ url_for('route_page', relation_id=15083963) }}">
|
||||
<span class="fw-semibold d-block">Istanbul Metro M11</span>
|
||||
<span class="text-muted">One direction · Subway</span>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action"
|
||||
href="{{ url_for('route_page', relation_id=15083966) }}">
|
||||
<span class="fw-semibold d-block">Istanbul M11 — all directions</span>
|
||||
<span class="text-muted">Compare routes, then choose a direction</span>
|
||||
</a>
|
||||
</div>
|
||||
<details{% if not relation_id %} open{% endif %} class="small">
|
||||
<summary class="fw-semibold">How to use this tool</summary>
|
||||
<ol class="ps-3 mt-2 mb-0">
|
||||
<li>Search and choose a result, try an example, or paste a route URL below.</li>
|
||||
<li>Download the full route, or select a start stop and then an end stop to preview a segment.</li>
|
||||
<li>Choose whether to include stops, then download your GeoJSON file.</li>
|
||||
</ol>
|
||||
</details>
|
||||
</details>
|
||||
|
||||
<!-- Load form -->
|
||||
<form method="post" action="{{ url_for('load') }}" class="mb-3">
|
||||
<label class="form-label fw-semibold small">Relation ID or OSM URL</label>
|
||||
<label for="relation-input" class="form-label fw-semibold small">Load your own route</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" name="relation" class="form-control"
|
||||
placeholder="e.g. 15083963"
|
||||
<input type="text" name="relation" id="relation-input" class="form-control"
|
||||
placeholder="Relation ID or OSM URL" aria-describedby="relation-help" required
|
||||
value="{{ relation_id or '' }}">
|
||||
<button class="btn btn-primary" type="submit">Load</button>
|
||||
</div>
|
||||
<p id="relation-help" class="form-text mb-0">Paste an OpenStreetMap route relation URL
|
||||
(e.g. https://www.openstreetmap.org/relation/15083963) or its numeric ID.
|
||||
A relation groups the ways and stops belonging to a route.</p>
|
||||
</form>
|
||||
|
||||
<!-- Error alert -->
|
||||
|
|
@ -141,6 +216,9 @@
|
|||
// Injected by Flask so app.js works correctly under any mount path.
|
||||
const RELATION_ID = {{ relation_id | tojson }};
|
||||
const URLS = {
|
||||
indexPage: {{ url_for('index') | tojson }},
|
||||
searchApi: {{ url_for('api_search') | tojson }},
|
||||
locationsApi: {{ url_for('api_locations') | tojson }},
|
||||
routeApi: {{ url_for('api_route', relation_id=0)[:-1] | tojson }},
|
||||
segmentApi: {{ url_for('api_segment', relation_id=0)[:-1] | tojson }},
|
||||
routeMasterApi: {{ url_for('api_route_master', relation_id=0)[:-1] | tojson }},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue