openstreetmap-tools/web/templates/index.html
Edward Betts c2355a053d Set page title server-side for link preview compatibility
When a specific relation URL is loaded, fetch_relation_name() makes a
lightweight GET /relation/{id}.json call to get the name tag and pass
it to the template. The <title> and og:title are then set server-side,
so forum link previews and crawlers see the route name in the HTML
without executing JavaScript.

Errors are swallowed silently so a slow or failed API response just
falls back to the default title.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 21:01:25 +00:00

136 lines
5.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% if route_name %}{{ route_name }} {% endif %}OSM Public Transport → GeoJSON</title>
{% if route_name %}<meta property="og:title" content="{{ route_name }} OSM Public Transport → GeoJSON">{% endif %}
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav class="navbar navbar-dark bg-dark px-3" style="height:56px">
<a class="navbar-brand" href="{{ url_for('index') }}">OSM Public Transport → GeoJSON</a>
<a class="nav-link text-white" href="{{ url_for('docs') }}">API docs</a>
</nav>
<div class="container-fluid h-100 p-0">
<div class="row g-0 h-100" id="main-row">
<!-- Sidebar -->
<div class="col-3 border-end" id="sidebar">
<!-- 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>
<div class="input-group input-group-sm">
<input type="text" name="relation" class="form-control"
placeholder="e.g. 15083963"
value="{{ relation_id or '' }}">
<button class="btn btn-primary" type="submit">Load</button>
</div>
</form>
<!-- Error alert -->
{% if error %}
<div class="alert alert-danger alert-dismissible py-2 small" role="alert">
{{ error }}
<button type="button" class="btn-close btn-sm" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<div id="js-alert" class="alert alert-danger alert-dismissible py-2 small d-none" role="alert">
<span id="js-alert-msg"></span>
<button type="button" class="btn-close btn-sm" data-bs-dismiss="alert"></button>
</div>
<!-- Route master panel (shown when a route_master relation is loaded) -->
<div id="route-master-panel" class="d-none">
<div class="mb-3">
<div class="fw-semibold" id="route-master-name"></div>
<a id="route-master-osm-link" class="small text-muted" target="_blank" rel="noopener">View on OSM ↗</a>
</div>
<div class="fw-semibold small mb-1">Routes</div>
<div id="route-master-list"></div>
</div>
<!-- Route info (hidden until loaded) -->
<div id="route-panel" class="d-none">
<div class="mb-3">
<div class="fw-semibold" id="route-name"></div>
<a id="route-osm-link" class="small text-muted" target="_blank" rel="noopener">View on OSM ↗</a>
</div>
<!-- From / To slots -->
<div class="mb-1">
<label class="form-label fw-semibold small mb-1">From</label>
<div class="slot-box active" id="slot-from" title="Click to make active, then click a stop">
<span class="placeholder" id="slot-from-text">Click a stop…</span>
<span class="pencil" id="slot-from-pencil"></span>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold small mb-1">To</label>
<div class="slot-box" id="slot-to" title="Click to make active, then click a stop">
<span class="placeholder" id="slot-to-text">Click a stop…</span>
<span class="pencil d-none" id="slot-to-pencil"></span>
</div>
</div>
<!-- Clear button -->
<button class="btn btn-outline-secondary btn-sm w-100 mb-3" id="btn-clear" type="button">
✕ Clear selection
</button>
<!-- Include stops toggle -->
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="include-stops" checked>
<label class="form-check-label small" for="include-stops">Include stops in GeoJSON</label>
</div>
<!-- Download buttons -->
<div class="d-grid gap-2 mb-3">
<button class="btn btn-outline-secondary btn-sm disabled" id="btn-download-segment">
↓ Download segment
</button>
<button class="btn btn-outline-secondary btn-sm" id="btn-download-full">
↓ Download full route
</button>
</div>
<!-- Other directions -->
<div id="other-directions-panel" class="d-none mb-3">
<div class="fw-semibold small mb-1">Other directions</div>
<div id="other-directions-list"></div>
</div>
<!-- Stop list -->
<div class="fw-semibold small mb-1">Stops <span id="stop-count" class="text-muted"></span></div>
<div id="stop-list"></div>
</div>
</div><!-- /sidebar -->
<!-- Map -->
<div class="col-9" id="map"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// Injected by Flask so app.js works correctly under any mount path.
const RELATION_ID = {{ relation_id | tojson }};
const URLS = {
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 }},
routePage: {{ url_for('route_page', relation_id=0)[:-1] | tojson }},
};
</script>
<script src="{{ url_for('static', filename='app.js') }}"></script>
</body>
</html>