better mobile UX
This commit is contained in:
parent
a488993211
commit
3fdb38d3a0
3 changed files with 120 additions and 24 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,19 +54,18 @@
|
||||||
<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 class="legend-gradient"></div>
|
||||||
|
<div class="legend-labels">
|
||||||
<div id="legend" class="map-panel">
|
<span id="min-price">-</span>
|
||||||
<h3 id="legend-title">Prix régulier (¢/L)</h3>
|
<span id="max-price">-</span>
|
||||||
<div class="legend-gradient"></div>
|
</div>
|
||||||
<div class="legend-labels">
|
|
||||||
<span id="min-price">-</span>
|
|
||||||
<span id="max-price">-</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="map-stats">{{.StationCount}} stations</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="filter-backdrop"></div>
|
||||||
|
<div id="last-updated" class="map-panel">{{.LastUpdated}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue