better mobile UX

This commit is contained in:
Polen 2026-04-07 22:41:03 -04:00
parent a488993211
commit 3fdb38d3a0
3 changed files with 120 additions and 24 deletions

View file

@ -131,7 +131,7 @@
document.getElementById('slider-label').textContent = Math.ceil(maxPrice) + '¢/L'; document.getElementById('slider-label').textContent = Math.ceil(maxPrice) + '¢/L';
const fuelLabel = { regular: 'Régulier', super: 'Super', diesel: 'Diesel' }[currentFuel]; const fuelLabel = { regular: 'Régulier', super: 'Super', diesel: 'Diesel' }[currentFuel];
document.getElementById('legend-title').textContent = `Prix ${fuelLabel.toLowerCase()} (¢/L)`; document.getElementById('legend-title').textContent = `${fuelLabel} (¢/L)`;
document.getElementById('min-price').textContent = minPrice.toFixed(1) + '¢'; document.getElementById('min-price').textContent = minPrice.toFixed(1) + '¢';
document.getElementById('max-price').textContent = maxPrice.toFixed(1) + '¢'; document.getElementById('max-price').textContent = maxPrice.toFixed(1) + '¢';
@ -232,6 +232,29 @@
showCostco = this.checked; showCostco = this.checked;
rebuildMarkers(); rebuildMarkers();
}); });
// ── Mobile filter panel toggle ─────────────────────────
var filterToggle = document.getElementById('filter-toggle');
var sliderPanel = document.getElementById('slider-panel');
var filterBackdrop = document.getElementById('filter-backdrop');
function openFilterPanel() {
sliderPanel.classList.add('open');
filterToggle.classList.add('hidden');
if (filterBackdrop) filterBackdrop.classList.add('visible');
}
function closeFilterPanel() {
sliderPanel.classList.remove('open');
filterToggle.classList.remove('hidden');
if (filterBackdrop) filterBackdrop.classList.remove('visible');
}
if (filterToggle) {
filterToggle.addEventListener('click', openFilterPanel);
}
if (filterBackdrop) {
filterBackdrop.addEventListener('click', closeFilterPanel);
}
} }
// ── Initialise ───────────────────────────────────────────── // ── Initialise ─────────────────────────────────────────────
@ -279,7 +302,6 @@
}); });
loadingEl.style.display = 'none'; loadingEl.style.display = 'none';
document.getElementById('map-stats').textContent = allStations.length + ' stations';
rebuildMarkers(); rebuildMarkers();
map.addLayer(clusterGroup); map.addLayer(clusterGroup);

View file

@ -94,26 +94,31 @@ html, body { height: 100%; margin: 0; padding: 0; }
box-shadow: 0 2px 8px rgba(0,0,0,0.15); box-shadow: 0 2px 8px rgba(0,0,0,0.15);
} }
/* Legend */ /* Legend (inline inside slider-panel) */
#legend { #legend {
position: absolute; bottom: 20px; right: 20px; margin-top: 8px;
padding: 12px 16px; padding-top: 8px;
z-index: 1000; font-size: 13px; min-width: 180px; border-top: 1px solid var(--border);
font-size: 11px;
color: var(--muted-foreground);
} }
#legend h3 { margin-bottom: 8px; font-size: 14px; } .legend-header {
.legend-gradient {
height: 16px; border-radius: 4px;
background: linear-gradient(to right, #16a34a, #65a30d, #ca8a04, #ea580c, #dc2626);
margin-bottom: 4px; margin-bottom: 4px;
font-weight: 500;
}
.legend-gradient {
height: 8px; border-radius: 3px;
background: linear-gradient(to right, #16a34a, #65a30d, #ca8a04, #ea580c, #dc2626);
margin-bottom: 2px;
opacity: 0.85;
} }
.legend-labels { .legend-labels {
display: flex; justify-content: space-between; display: flex; justify-content: space-between;
font-size: 11px; color: var(--muted-foreground); font-size: 10px; color: var(--muted-foreground);
} }
#map-stats { margin-top: 8px; font-size: 11px; color: var(--muted-foreground); }
#last-updated { #last-updated {
position: absolute; bottom: 8px; left: 12px; position: absolute; bottom: 24px; right: 8px;
padding: 5px 10px; padding: 5px 10px;
z-index: 1000; font-size: 11px; z-index: 1000; font-size: 11px;
color: var(--muted-foreground); color: var(--muted-foreground);
@ -233,3 +238,68 @@ html, body { height: 100%; margin: 0; padding: 0; }
/* ── htmx loading indicator ──────────────────────────── */ /* ── htmx loading indicator ──────────────────────────── */
.htmx-request #stats-content { opacity: 0.5; transition: opacity 0.2s; } .htmx-request #stats-content { opacity: 0.5; transition: opacity 0.2s; }
/* ── Filter toggle button (mobile only) ─────────────── */
#filter-toggle {
display: none; /* hidden on desktop */
position: absolute;
bottom: 16px; left: 12px;
z-index: 1001;
padding: 8px 14px;
font-size: 13px; font-weight: 600;
cursor: pointer;
align-items: center; gap: 6px;
border: none;
color: var(--card-foreground);
}
#filter-toggle svg { flex-shrink: 0; }
/* ── Mobile layout ──────────────────────────────────── */
@media (max-width: 768px) {
#filter-toggle { display: flex; }
#slider-panel {
position: fixed;
top: auto; left: 0; right: 0; bottom: 0;
min-width: 0; width: 100%;
border-radius: 16px 16px 0 0;
max-height: 70vh;
overflow-y: auto;
padding: 16px 16px 20px;
transform: translateY(100%);
transition: transform 0.3s ease;
z-index: 1100;
}
#slider-panel.open { transform: translateY(0); }
/* Drag handle hint at top of the panel */
#slider-panel::before {
content: '';
display: block;
width: 36px; height: 4px;
background: var(--muted-foreground);
border-radius: 2px;
margin: 0 auto 12px;
opacity: 0.4;
}
/* Semi-transparent backdrop when panel is open */
#filter-backdrop {
display: none;
position: fixed; inset: 0;
background: rgba(0,0,0,0.3);
z-index: 1099;
}
#filter-backdrop.visible { display: block; }
/* Hide the toggle when panel is open */
#filter-toggle.hidden { display: none; }
/* Cluster tooltip: constrain on small screens */
.cluster-info-tooltip {
white-space: normal;
max-width: 70vw;
left: auto; right: 0;
transform: translateY(-50%);
}
}

View file

@ -9,6 +9,11 @@
<div id="page-map"> <div id="page-map">
<div id="map"></div> <div id="map"></div>
<button id="filter-toggle" class="map-panel" aria-label="Filtres">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
<span>Filtres</span>
</button>
<div id="slider-panel" class="map-panel"> <div id="slider-panel" class="map-panel">
<select id="region-select"> <select id="region-select">
<option value="">Toutes les régions</option> <option value="">Toutes les régions</option>
@ -49,21 +54,20 @@
<span id="slider-max">-</span> <span id="slider-max">-</span>
</div> </div>
<div id="visible-count"></div> <div id="visible-count"></div>
</div> <div id="legend">
<div class="legend-header" id="legend-title">Régulier (¢/L)</div>
<div id="last-updated" class="map-panel">{{.LastUpdated}}</div>
<div id="legend" class="map-panel">
<h3 id="legend-title">Prix régulier (¢/L)</h3>
<div class="legend-gradient"></div> <div class="legend-gradient"></div>
<div class="legend-labels"> <div class="legend-labels">
<span id="min-price">-</span> <span id="min-price">-</span>
<span id="max-price">-</span> <span id="max-price">-</span>
</div> </div>
<div id="map-stats">{{.StationCount}} stations</div>
</div> </div>
</div> </div>
<div id="filter-backdrop"></div>
<div id="last-updated" class="map-panel">{{.LastUpdated}}</div>
</div>
<script> <script>
window.__stations = {{.StationsJSON}}; window.__stations = {{.StationsJSON}};
window.__deltas = {{.DeltasJSON}}; window.__deltas = {{.DeltasJSON}};