214 lines
11 KiB
HTML
214 lines
11 KiB
HTML
<!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" />
|
||
<link href="/styles.css?v=20250918" rel="stylesheet" />
|
||
</head>
|
||
<body>
|
||
<!-- App Bar -->
|
||
<header class="appbar navbar px-3">
|
||
<div class="container-fluid d-flex align-items-center justify-content-between">
|
||
<div class="d-flex align-items-center gap-2">
|
||
<span class="navbar-brand mb-0 h1 d-flex align-items-center gap-2">
|
||
<span aria-hidden="true">🏍️</span>
|
||
<span>FreeMoto</span>
|
||
</span>
|
||
<span id="summaryPill" class="badge rounded-pill text-bg-light d-none"></span>
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<button class="btn btn-outline-secondary btn-sm" id="clearRouteBtn" title="Clear route">Clear</button>
|
||
<div class="btn-group btn-group-sm" role="group" aria-label="Zoom controls">
|
||
<button class="btn btn-outline-secondary" id="zoomOutBtn" title="Zoom out">−</button>
|
||
<button class="btn btn-outline-secondary" id="zoomInBtn" title="Zoom in">+</button>
|
||
</div>
|
||
<button class="btn btn-outline-secondary btn-sm" id="themeToggle" title="Toggle dark mode">🌙</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Map canvas -->
|
||
<div id="map" aria-label="Map"></div>
|
||
|
||
<!-- Control Drawer: overlay on mobile, sidebar on desktop -->
|
||
<aside class="nav-panel shadow">
|
||
<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="status"></div>
|
||
|
||
<!-- Route inputs -->
|
||
<div class="section-title mb-1">Route</div>
|
||
<div class="row g-2 align-items-stretch">
|
||
<div class="col-12">
|
||
<div class="input-group position-relative">
|
||
<span class="input-group-text" title="Start" aria-label="Start">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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>
|
||
<div class="col-12 d-flex justify-content-center">
|
||
<button id="swapBtn" class="btn btn-light border rounded-circle shadow-sm" type="button" title="Swap start/end">⇅</button>
|
||
</div>
|
||
<div class="col-12">
|
||
<div class="input-group position-relative">
|
||
<span class="input-group-text" title="Destination" aria-label="Destination">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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>
|
||
</div>
|
||
|
||
<!-- Quick sliders -->
|
||
<div class="row g-3 mt-1">
|
||
<div class="col-12">
|
||
<label for="twistiness" class="form-label mb-1 text-muted">Twistiness</label>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<input type="range" class="form-range" id="twistiness" min="0" max="100" value="50" />
|
||
<span id="twistinessValue" class="badge rounded-pill text-bg-light">50</span>
|
||
</div>
|
||
</div>
|
||
<div class="col-12">
|
||
<label for="highwayPref" class="form-label mb-1 text-muted">Highways</label>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<input type="range" class="form-range" id="highwayPref" min="0" max="100" value="50" />
|
||
<span id="highwayPrefValue" class="badge rounded-pill text-bg-light">50</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="d-grid gap-2 my-2 d-none d-md-grid">
|
||
<button type="button" id="plotRouteBtn" class="btn btn-success">Plot Route</button>
|
||
</div>
|
||
|
||
<!-- Options accordion -->
|
||
<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 mb-2">
|
||
<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 flex-wrap">
|
||
<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>
|
||
<button type="button" class="btn btn-warning btn-sm export-gpx">Export GPX</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-2">
|
||
<div class="section-title">Waypoints</div>
|
||
<ul id="waypointList" class="list-group small"></ul>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Panel toggle button (mobile portrait) -->
|
||
<button id="panelToggle" class="btn btn-outline-secondary btn-sm panel-toggle d-md-none" type="button" aria-expanded="true" title="Toggle panel">☰</button>
|
||
|
||
<!-- Floating actions (mobile) -->
|
||
<div class="floating-group d-md-none">
|
||
<button class="btn btn-primary fab" id="recenterBtn" title="Recenter">◎</button>
|
||
<button class="btn btn-primary" id="plotRouteBtn" title="Plot Route">Route</button>
|
||
<button class="btn btn-dark export-gpx" title="Export GPX">GPX</button>
|
||
</div>
|
||
|
||
<!-- Directions Bottom Sheet -->
|
||
<div id="directionsSheet" class="sheet" aria-live="polite">
|
||
<div class="card shadow-lg sheet-card">
|
||
<div class="card-body p-0">
|
||
<div class="handle" role="separator" aria-label="Resize directions"></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>
|
||
|
||
<!-- Scripts -->
|
||
<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>
|