diff --git a/web/static/app.js b/web/static/app.js index 9bd6ada..0feb2de 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -36,17 +36,33 @@ function isMobile() { return window.innerWidth < 768; } function openPanel() { document.getElementById('sidebar').classList.add('panel-open'); + const fab = document.getElementById('panel-fab'); + if (fab) fab.style.display = 'none'; +} + +function closePanel() { + document.getElementById('sidebar').classList.remove('panel-open'); + const fab = document.getElementById('panel-fab'); + if (fab) fab.style.removeProperty('display'); } function updateHandleLabel(text) { const el = document.getElementById('sidebar-handle-label'); if (el) el.textContent = text; + const fabLabel = document.getElementById('panel-fab-label'); + if (fabLabel) fabLabel.textContent = text; } document.getElementById('sidebar-handle').addEventListener('click', () => { - document.getElementById('sidebar').classList.toggle('panel-open'); + if (document.getElementById('sidebar').classList.contains('panel-open')) { + closePanel(); + } else { + openPanel(); + } }); +document.getElementById('panel-fab').addEventListener('click', openPanel); + // ── Helpers ──────────────────────────────────────────────────────────────── /** diff --git a/web/static/style.css b/web/static/style.css index cb7abf1..e44ee8d 100644 --- a/web/static/style.css +++ b/web/static/style.css @@ -42,6 +42,11 @@ html, body { } @media (max-width: 767.98px) { + /* overflow:hidden on body clips position:fixed in mobile Safari — reset it */ + html, body { + overflow: visible; + } + #sidebar { position: fixed; bottom: 0; @@ -51,15 +56,18 @@ html, body { max-width: 100% !important; flex: none !important; height: 65vh; - max-height: calc(100vh - 56px); + max-height: calc(100dvh - 56px); min-height: unset; - transform: translateY(calc(100% - 48px)); + /* fully off-screen by default; FAB opens it */ + transform: translateY(100%); transition: transform 0.3s ease; z-index: 1000; border-radius: 16px 16px 0 0; border-right: none !important; box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.15); background: #fff; + /* clear of home-indicator / browser chrome */ + padding-bottom: env(safe-area-inset-bottom, 0px); } #sidebar.panel-open { @@ -70,6 +78,31 @@ html, body { width: 100% !important; max-width: 100% !important; flex: 0 0 100% !important; + position: relative; + } + + /* Floating action button */ + #panel-fab { + position: absolute; + bottom: calc(env(safe-area-inset-bottom, 0px) + 56px); /* above attribution */ + right: 12px; + z-index: 999; + display: flex; + align-items: center; + gap: 6px; + background: #fff; + border: none; + border-radius: 24px; + padding: 10px 16px; + font-size: 0.875rem; + font-weight: 600; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + cursor: pointer; + white-space: nowrap; + } + + #panel-fab:active { + background: #f8f9fa; } } diff --git a/web/templates/index.html b/web/templates/index.html index ec3cc16..db80462 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -2,7 +2,7 @@ - + {% if route_name %}{{ route_name }} – {% endif %}OSM Public Transport → GeoJSON {% if route_name %}{% endif %} @@ -124,7 +124,13 @@ -
+
+ + +