47 lines
6.8 KiB
HTML
47 lines
6.8 KiB
HTML
{% extends 'base.html' %}
|
|
{% from '_ui.html' import icon %}
|
|
{% block title %}Route planner · Stride{% endblock %}
|
|
{% block head %}
|
|
<link rel="stylesheet" href="{{ url_for('static',filename='vendor/leaflet.css') }}">
|
|
<link rel="stylesheet" href="{{ url_for('static',filename='planner.css') }}">
|
|
{% endblock %}
|
|
{% macro location(kind, label, letter) %}
|
|
<div class="planner-location">
|
|
<label for="plan-{{ kind }}"><span class="location-letter {{ kind }}">{{ letter }}</span>{{ label }}</label>
|
|
<div class="location-search"><input id="plan-{{ kind }}" placeholder="Search a place or address" autocomplete="off" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="{{ kind }}-results" aria-describedby="{{ kind }}-hint" {{ 'required' if kind == 'start' }}><div id="{{ kind }}-results" class="location-results" role="listbox" aria-label="{{ label }} suggestions" hidden></div></div>
|
|
<div id="{{ kind }}-hint" class="location-hint" aria-live="polite">Search, enter coordinates, or pick on the map.</div>
|
|
<button type="button" class="planner-link" id="pick-{{ kind }}">{{ icon('route') }} Pick {{ 'start' if kind == 'start' else 'finish' }} on map</button>
|
|
</div>
|
|
{% endmacro %}
|
|
{% block content %}
|
|
<div id="route-planner" data-csrf="{{ csrf_token() }}" data-base="{{ url_for('planner.index') }}">
|
|
<div class="page-heading"><div><span class="eyebrow">EXPLORE YOUR NEXT RUN</span><h1>A good run starts here.</h1><p>Find a route that fits your distance, terrain and favourite places.</p></div><a class="button secondary" href="#saved-route-library">{{ icon('route') }} Saved routes</a></div>
|
|
{% if not configured %}<div class="flash">Route generation is not connected yet. The site operator needs to configure ORS_API_KEY. You can still view and export your saved routes.</div>{% endif %}
|
|
<div class="planner-stage">
|
|
<form id="planner-form" class="planner-controls">
|
|
<div class="planner-section-heading"><span class="eyebrow">YOUR ROUTE</span>{{ icon('route') }}</div>
|
|
<label for="plan-mode">Route type</label><select id="plan-mode"><option value="loop">Loop · back to the start</option><option value="point">Point to point</option></select>
|
|
{{ location('start', 'Start location', 'S') }}
|
|
<div id="finish-fields" hidden>{{ location('end', 'Finish location', 'F') }}</div>
|
|
<div id="loop-note" class="loop-note">↻ Finish at your starting location</div>
|
|
<button type="button" class="planner-link" id="my-location">{{ icon('profile') }} Use my current location</button>
|
|
<hr>
|
|
<div class="planner-fields"><div><label for="plan-distance">Distance <span class="field-unit">km</span></label><input id="plan-distance" type="number" min="1" max="50" step="0.1" value="15" required></div><div><label for="plan-hill">Hills</label><select id="plan-hill"><option value="flat">Mostly flat</option><option value="rolling" selected>Rolling</option><option value="hilly">Hill challenge</option></select></div></div>
|
|
<p class="field-help">Distance target ±5% · hill preferences guide the match.</p>
|
|
<details class="planner-preferences"><summary>Route preferences</summary><label for="plan-priority">Prioritise</label><select id="plan-priority"><option value="quality">Route quality</option><option value="distance">Closest distance</option><option value="hills">Hill match</option></select><label for="plan-surface">Surface</label><select id="plan-surface"><option value="any">Any surface</option><option value="paved">Mostly paved</option><option value="trails">Paths and tracks</option></select><label class="planner-check"><input id="plan-repeats" type="checkbox" checked> Minimise repeated sections</label></details>
|
|
<button class="button primary" id="generate-routes" {% if not configured %}disabled{% endif %}>{{ icon('run') }} Find my routes</button>
|
|
<p class="planner-provider-note">Place searches and locations use openrouteservice.</p>
|
|
</form>
|
|
<div class="planner-map-panel"><div class="planner-map-heading"><div><span class="eyebrow">ROUTE PREVIEW</span><p id="map-instruction">Search a place or tap the map to set your start.</p></div><button class="button secondary" type="button" id="fit-map">Fit locations</button></div><div id="planner-map" aria-label="Route planner map"></div><div class="planner-map-footer"><span><i class="legend-dot start"></i> Start <i class="legend-dot end"></i> Finish</span><span>Walking paths · elevation · surface</span></div></div>
|
|
</div>
|
|
<p id="planner-status" role="status" aria-live="polite">Choose your starting point to begin.</p>
|
|
<div id="planner-results" hidden>
|
|
<div class="planner-results-heading"><h2>Your route options</h2><span class="field-help">Select a route to explore its details</span></div><div id="route-options" class="planner-options" aria-label="Suggested routes"></div>
|
|
<div class="planner-detail"><div><span class="eyebrow">SELECTED ROUTE</span><h2 id="route-heading">Route details</h2><div id="route-metrics" class="planner-metrics"></div><div class="planner-profile"><canvas id="route-profile" aria-label="Elevation by distance" role="img"></canvas></div><p id="profile-status" class="field-help"></p><p id="distance-status" class="planner-distance-note"></p></div><div><span class="eyebrow">KNOW YOUR ROUTE</span><h2>Quality & terrain</h2><dl id="quality-details"></dl><details class="planner-quality-notes"><summary>About these estimates</summary><p class="field-help">Repetition uses matching geometry edges. Road share describes mapped way types, not traffic. Missing attributes stay unknown. Crossings, lighting and current access are unverified.</p></details><form id="save-route-form"><label for="route-name">Route name</label><input id="route-name" maxlength="160" required><div class="planner-save-actions"><button class="button primary">Save route</button><a id="route-export" class="button secondary" hidden>Export GPX</a><button type="button" id="delete-route" class="button secondary" hidden>Delete</button></div></form></div></div>
|
|
</div>
|
|
<section id="saved-route-library" class="planner-library"><div class="planner-results-heading"><div><span class="eyebrow">READY FOR ANOTHER DAY</span><h2>Your saved routes</h2></div><span class="field-help">Private to you · latest 100</span></div><div id="saved-routes">{% for route in saved_routes %}<button type="button" class="button secondary" data-saved="{{ route.id }}">{{ route.title }}</button>{% else %}<p id="empty-saved">Your next favourite route belongs here. Plan a run and save it for later.</p>{% endfor %}</div></section>
|
|
<p class="planner-attribution">Routing & search © openrouteservice · OpenStreetMap contributors. Check current path access before heading out.</p>
|
|
</div>
|
|
{% endblock %}
|
|
{% block scripts %}<script src="{{ url_for('static',filename='vendor/leaflet.js') }}"></script><script src="{{ url_for('static',filename='vendor/chart.umd.js') }}"></script><script src="{{ url_for('static',filename='planner.js') }}"></script>{% endblock %}
|