Files
freemoto/app/web/static/index.html
Pedan a2743dd7fb
Some checks failed
build-and-push / docker (push) Failing after 10m36s
complete overhaul
2025-09-18 00:23:21 +02:00

264 lines
14 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>FreeMoto · Route Planner</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" rel="stylesheet" />
<style>
:root {
--panel-radius: 18px;
--glass-bg: rgba(255,255,255,0.82);
--glass-border: rgba(16,24,40,0.08);
}
html, body { height: 100%; }
body { margin: 0; overflow: hidden; background: linear-gradient(180deg, #f2f4f7, #eef2f6); }
#map { position: absolute; inset: 0; z-index: 1; }
/* Top app bar - new gradient look */
.appbar {
position: fixed; inset: 0 0 auto 0; z-index: 1002;
background: linear-gradient(90deg, #0ea5e9, #6366f1);
color: #fff;
}
.appbar .navbar-brand { color: #fff; }
.appbar .btn { color: #fff; border-color: rgba(255,255,255,0.6); }
/* Floating dock panel */
.nav-panel {
position: fixed; left: 10px; right: 10px; bottom: 10px; z-index: 1001;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
backdrop-filter: blur(10px) saturate(160%);
border-radius: 999px; /* pill */
box-shadow: 0 10px 30px rgba(2, 8, 20, 0.1);
padding: 8px 12px;
}
.nav-panel .form-control, .nav-panel .btn { border-radius: 999px; }
.nav-panel .input-group > .input-group-text { border-radius: 999px 0 0 999px; }
@media (min-width: 768px) {
.nav-panel {
top: 86px; bottom: auto; left: 24px; right: auto; width: 520px;
border-radius: var(--panel-radius);
padding: 14px;
}
.nav-panel .form-control, .nav-panel .btn { border-radius: var(--panel-radius); }
.nav-panel .input-group > .input-group-text { border-radius: var(--panel-radius) 0 0 var(--panel-radius); }
}
.section-title { font-weight: 600; color: #334155; }
#routeInfoCard { font-size: 0.95rem; }
/* Suggestions dropdown */
#sourceSuggestions, #destSuggestions { position: absolute; top: 100%; left: 0; right: 0; z-index: 2000; max-height: 220px; overflow: auto; border-radius: 12px; }
/* Directions bottom sheet - improved */
.sheet { position: fixed; left: 0; right: 0; bottom: 0; z-index: 1001; }
.sheet-card { border-radius: var(--panel-radius) var(--panel-radius) 0 0; max-height: 60vh; overflow: hidden; }
.sheet .handle { width: 44px; height: 5px; border-radius: 999px; background: #CBD5E1; margin: 6px auto 6px; }
.sheet-header { position: sticky; top: 0; background: #fff; z-index: 1; padding: 4px 8px; border-bottom: 1px solid #eef2f6; }
.sheet-body { overflow: auto; max-height: calc(60vh - 42px); }
#directionsSheet { display: none; }
.sheet.collapsed .sheet-card { max-height: 28vh; }
.sheet.collapsed .sheet-body { max-height: calc(28vh - 42px); }
.floating-group { position: fixed; right: 14px; bottom: 86px; z-index: 1002; display: flex; flex-direction: column; gap: 10px; }
/* Dracula-like dark theme */
[data-theme="dark"] body { background: linear-gradient(180deg, #1e1f29, #282a36); color: #f8f8f2; }
[data-theme="dark"] .appbar { background: linear-gradient(90deg, #44475a, #6272a4); color: #f8f8f2; }
[data-theme="dark"] .appbar .navbar-brand { color: #f8f8f2; }
[data-theme="dark"] .appbar .btn { color: #f8f8f2; border-color: rgba(248,248,242,0.6); }
[data-theme="dark"] .nav-panel { background: rgba(40, 42, 54, 0.85); border-color: rgba(248,248,242,0.08); box-shadow: 0 10px 30px rgba(0,0,0,0.4); }
[data-theme="dark"] .form-control, [data-theme="dark"] .input-group-text { background: #282a36; color: #f8f8f2; border-color: #44475a; }
[data-theme="dark"] .btn-outline-secondary { color: #f8f8f2; border-color: #8be9fd; }
[data-theme="dark"] .btn-primary { background-color: #6272a4; border-color: #6272a4; }
[data-theme="dark"] .btn-warning { background-color: #ffb86c; border-color: #ffb86c; color: #1e1f29; }
[data-theme="dark"] .badge.text-bg-light { background-color: #44475a !important; color: #f8f8f2 !important; }
[data-theme="dark"] .card, [data-theme="dark"] .sheet-card { background: #282a36; color: #f8f8f2; }
[data-theme="dark"] .list-group-item { background: #282a36; color: #f8f8f2; border-color: #44475a; }
[data-theme="dark"] .sheet-header { background: #282a36; border-bottom-color: #44475a; }
[data-theme="dark"] .handle { background: #44475a; }
</style>
</head>
<body>
<!-- App Bar -->
<nav class="appbar navbar navbar-light px-3">
<span class="navbar-brand mb-0 h1 d-flex align-items-center gap-2">
<span style="font-size: 1.25rem">🏍️</span>
<span>FreeMoto</span>
</span>
<div class="d-flex align-items-center gap-3 flex-wrap justify-content-end">
<div class="d-flex align-items-center gap-2" title="Prefer twisty roads (less highways)">
<label for="twistiness" class="form-label mb-0 text-white-50 d-none d-md-inline">Twistiness</label>
<input type="range" class="form-range" id="twistiness" min="0" max="100" value="50" style="width:140px">
<span id="twistinessValue" class="badge rounded-pill text-bg-light">50</span>
</div>
<div class="d-flex align-items-center gap-2" title="Prefer highways (faster)">
<label for="highwayPref" class="form-label mb-0 text-white-50 d-none d-md-inline">Highways</label>
<input type="range" class="form-range" id="highwayPref" min="0" max="100" value="50" style="width:120px">
<span id="highwayPrefValue" class="badge rounded-pill text-bg-light">50</span>
</div>
<span id="summaryPill" class="badge rounded-pill text-bg-light d-none"></span>
<button class="btn btn-outline-secondary btn-sm" id="clearRouteBtn" title="Clear route">Clear</button>
<button class="btn btn-outline-secondary btn-sm" id="zoomOutBtn" title="Zoom out"></button>
<button class="btn btn-outline-secondary btn-sm" id="zoomInBtn" title="Zoom in">+</button>
<button class="btn btn-outline-secondary btn-sm" id="themeToggle" title="Toggle dark mode">🌙</button>
</div>
</nav>
<div id="map"></div>
<!-- Floating actions (mobile) -->
<div class="floating-group d-md-none">
<button class="btn btn-dark export-gpx" title="Export GPX">GPX</button>
<button class="btn btn-primary" id="plotRouteBtn" title="Plot Route">Route</button>
</div>
<!-- Control Panel -->
<div class="nav-panel">
<div class="d-flex align-items-center justify-content-between mb-2">
<div class="d-flex align-items-center gap-2">
<span class="badge text-bg-primary">Beta</span>
<span class="fw-semibold">Motorcycle route planner</span>
</div>
<button class="btn btn-sm btn-outline-secondary d-none d-md-inline" onclick="resetMarkers()">Reset</button>
</div>
<div id="routeInfoCard" class="alert alert-info d-none" role="alert"></div>
<div id="nextManeuverBanner" class="alert alert-secondary py-2 px-3 d-none" role="alert"></div>
<div class="section-title mb-1">Route</div>
<div class="input-group mb-2 position-relative">
<span class="input-group-text" title="Start">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#0d6efd" viewBox="0 0 16 16"><path d="M8 16s6-5.686 6-10A6 6 0 1 0 2 6c0 4.314 6 10 6 10zm0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></svg>
</span>
<input type="text" class="form-control" id="sourceInput" placeholder="Start address" autocomplete="off" />
<button class="btn btn-outline-secondary" type="button" id="useCurrentSource" title="Use current location">📍</button>
<div id="sourceSuggestions" class="list-group position-absolute w-100"></div>
</div>
<div class="input-group mb-2 position-relative">
<span class="input-group-text" title="Destination">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#dc3545" viewBox="0 0 16 16"><path d="M14.778 2.222a.5.5 0 0 1 0 .707l-2.5 2.5a.5.5 0 0 1-.707 0l-2.5-2.5a.5.5 0 0 1 .707-.707L12 3.793l2.071-2.071a.5.5 0 0 1 .707 0z"/><path d="M2.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5z"/></svg>
</span>
<input type="text" class="form-control" id="destInput" placeholder="Destination address" autocomplete="off" />
<button class="btn btn-outline-secondary" type="button" id="useCurrentDest" title="Use current location">📍</button>
<div id="destSuggestions" class="list-group position-absolute w-100"></div>
</div>
<div class="d-grid gap-2 d-none d-md-grid mb-2">
<button type="button" id="plotRouteBtn" class="btn btn-success">Plot Route</button>
</div>
<div class="accordion mb-2" id="optionsAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#optionsCollapse" aria-expanded="false" aria-controls="optionsCollapse">
Route Options
</button>
</h2>
<div id="optionsCollapse" class="accordion-collapse collapse" data-bs-parent="#optionsAccordion">
<div class="accordion-body">
<div class="form-check mb-1">
<input class="form-check-input" type="checkbox" id="useShortest">
<label class="form-check-label" for="useShortest">Shortest route</label>
</div>
<div class="form-check mb-1">
<input class="form-check-input" type="checkbox" id="avoidHighways">
<label class="form-check-label" for="avoidHighways">Avoid freeways</label>
</div>
<div class="form-check mb-1">
<input class="form-check-input" type="checkbox" id="avoidTollRoads">
<label class="form-check-label" for="avoidTollRoads">Avoid tolls</label>
</div>
<div class="form-check mb-1">
<input class="form-check-input" type="checkbox" id="avoidFerries">
<label class="form-check-label" for="avoidFerries">Avoid ferries</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="avoidUnpaved">
<label class="form-check-label" for="avoidUnpaved">Avoid unpaved</label>
</div>
<hr>
<div class="row g-2 align-items-center mb-2">
<div class="col-12 col-md-6 d-flex align-items-center gap-2">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="roundTripToggle">
<label class="form-check-label" for="roundTripToggle">Round Trip</label>
</div>
</div>
<div class="col-8 col-md-4">
<div class="input-group input-group-sm">
<input type="number" min="5" max="500" step="5" id="roundTripKm" class="form-control" placeholder="Distance (km)" value="100">
<span class="input-group-text">km</span>
</div>
</div>
<div class="col-4 col-md-2 d-grid">
<button type="button" id="roundTripBtn" class="btn btn-sm btn-outline-primary">Create</button>
</div>
</div>
<div class="row g-2 align-items-center mb-2">
<div class="col-12 col-md-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="roundTripNoRepeat">
<label class="form-check-label" for="roundTripNoRepeat">Avoid repeated segments</label>
</div>
</div>
</div>
<hr>
<div class="d-flex align-items-center gap-2">
<label class="form-label mb-0">Export</label>
<select id="exportMode" class="form-select form-select-sm" style="max-width: 180px;">
<option value="both" selected>Track + Route</option>
<option value="track">Track only</option>
<option value="route">Route only</option>
</select>
<div class="form-check form-switch ms-2">
<input class="form-check-input" type="checkbox" id="voiceToggle">
<label class="form-check-label" for="voiceToggle">Voice</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mb-2">
<div class="section-title">Waypoints</div>
<ul id="waypointList" class="list-group small"></ul>
</div>
<div class="d-flex gap-2 d-none d-md-flex">
<button onclick="resetMarkers()" class="btn btn-outline-primary">Reset Points</button>
<button type="button" class="btn btn-warning export-gpx">Export GPX</button>
</div>
</div>
<!-- Directions Bottom Sheet -->
<div id="directionsSheet" class="sheet">
<div class="card shadow-lg sheet-card">
<div class="card-body p-0">
<div class="handle"></div>
<div class="sheet-header d-flex align-items-center justify-content-between px-3 py-2">
<div class="fw-semibold">Directions</div>
<button class="btn btn-sm btn-outline-secondary" id="closeDirections">Close</button>
</div>
<div class="sheet-body px-2">
<ul class="list-group list-group-flush mt-2" id="directionsList"></ul>
</div>
</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 src="/main.js"></script>
<script src="/route.js"></script>
<script src="/geolocate.js"></script>
</body>
</html>