chore: remove Livewire public components and homepage, prepare for Vue
This commit is contained in:
@@ -1,203 +0,0 @@
|
||||
import L from 'leaflet';
|
||||
import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png';
|
||||
import markerIcon from 'leaflet/dist/images/marker-icon.png';
|
||||
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
||||
|
||||
delete L.Icon.Default.prototype._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconUrl: markerIcon,
|
||||
iconRetinaUrl: markerIcon2x,
|
||||
shadowUrl: markerShadow,
|
||||
});
|
||||
|
||||
function escHtml(str) {
|
||||
return String(str ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
const CLASSIFICATION_COLOURS = {
|
||||
current: '#22c55e',
|
||||
recent: '#64748b',
|
||||
stale: '#f59e0b',
|
||||
outdated: '#ef4444',
|
||||
};
|
||||
|
||||
const UK_CENTRE = [54.0, -2.0];
|
||||
const UK_ZOOM = 7;
|
||||
|
||||
const USER_MARKER_CSS = `
|
||||
@keyframes fuelalert-pulse {
|
||||
0% { transform: scale(1); opacity: 0.6; }
|
||||
70% { transform: scale(2.8); opacity: 0; }
|
||||
100% { transform: scale(1); opacity: 0; }
|
||||
}
|
||||
.fuelalert-user-marker { position: relative; width: 16px; height: 16px; }
|
||||
.fuelalert-user-dot { position: absolute; inset: 0; border-radius: 50%; background: #3b82f6; border: 2px solid #fff; box-shadow: 0 0 0 2px #3b82f6; }
|
||||
.fuelalert-user-ring { position: absolute; inset: 0; border-radius: 50%; background: #3b82f6; animation: fuelalert-pulse 2s ease-out infinite; }
|
||||
`;
|
||||
|
||||
function injectUserMarkerStyles() {
|
||||
if (document.getElementById('fuelalert-user-marker-styles')) return;
|
||||
const style = document.createElement('style');
|
||||
style.id = 'fuelalert-user-marker-styles';
|
||||
style.textContent = USER_MARKER_CSS;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
export function stationMap(results, meta, radius) {
|
||||
return {
|
||||
results,
|
||||
meta,
|
||||
radius,
|
||||
_map: null,
|
||||
_markers: [],
|
||||
_userMarker: null,
|
||||
|
||||
init() {
|
||||
injectUserMarkerStyles();
|
||||
this._map = L.map(this.$el, { zoomControl: true }).setView(UK_CENTRE, UK_ZOOM);
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
maxZoom: 19,
|
||||
}).addTo(this._map);
|
||||
|
||||
window.addEventListener('map-update', (e) => {
|
||||
this.results = e.detail.results;
|
||||
this.meta = e.detail.meta;
|
||||
this.radius = e.detail.radius;
|
||||
this._plotMarkers();
|
||||
});
|
||||
|
||||
this.locateUser();
|
||||
},
|
||||
|
||||
getZoomForRadius(radiusMiles) {
|
||||
if (radiusMiles <= 1) return 15;
|
||||
if (radiusMiles <= 2) return 14;
|
||||
if (radiusMiles <= 5) return 12;
|
||||
if (radiusMiles <= 10) return 11;
|
||||
if (radiusMiles <= 15) return 10;
|
||||
if (radiusMiles <= 25) return 9;
|
||||
if (radiusMiles <= 50) return 8;
|
||||
return 7;
|
||||
},
|
||||
|
||||
_clearMarkers() {
|
||||
this._markers.forEach((m) => m.remove());
|
||||
this._markers = [];
|
||||
},
|
||||
|
||||
addUserMarker(lat, lng) {
|
||||
if (this._userMarker) {
|
||||
this._userMarker.remove();
|
||||
}
|
||||
|
||||
const icon = L.divIcon({
|
||||
className: '',
|
||||
html: '<div class="fuelalert-user-marker"><div class="fuelalert-user-ring"></div><div class="fuelalert-user-dot"></div></div>',
|
||||
iconSize: [16, 16],
|
||||
iconAnchor: [8, 8],
|
||||
});
|
||||
|
||||
this._userMarker = L.marker([lat, lng], { icon, zIndexOffset: 1000 })
|
||||
.bindPopup('Your location')
|
||||
.addTo(this._map);
|
||||
|
||||
console.log(`[stationMap] user marker lat=${lat} lng=${lng}`);
|
||||
},
|
||||
|
||||
locateUser() {
|
||||
if (!navigator.geolocation) {
|
||||
console.warn('[stationMap] Geolocation not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
const ipFallback = () => {
|
||||
fetch('https://ipapi.co/json/')
|
||||
.then((r) => r.json())
|
||||
.then((d) => d.latitude && d.longitude && this.addUserMarker(d.latitude, d.longitude))
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
// Quick low-accuracy fix first — places the marker immediately.
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => {
|
||||
this.addUserMarker(pos.coords.latitude, pos.coords.longitude);
|
||||
|
||||
// Then refine with high accuracy if GPS is available.
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(precise) => this.addUserMarker(precise.coords.latitude, precise.coords.longitude),
|
||||
() => {},
|
||||
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 },
|
||||
);
|
||||
},
|
||||
() => ipFallback(),
|
||||
{ enableHighAccuracy: false, timeout: 5000, maximumAge: 60000 },
|
||||
);
|
||||
},
|
||||
|
||||
destroy() {
|
||||
if (this._map) {
|
||||
this._map.remove();
|
||||
this._map = null;
|
||||
this._markers = [];
|
||||
this._userMarker = null;
|
||||
}
|
||||
},
|
||||
|
||||
_plotMarkers() {
|
||||
if (!this._map) {
|
||||
return;
|
||||
}
|
||||
this._clearMarkers();
|
||||
|
||||
if (!this.results || this.results.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.results.forEach((station) => {
|
||||
const colour = escHtml(CLASSIFICATION_COLOURS[station.price_classification] ?? '#64748b');
|
||||
const miles = (station.distance_km * 0.621371).toFixed(1);
|
||||
const supermarketTag = station.is_supermarket
|
||||
? '<span style="display:inline-block;background:#84cc16;color:#fff;font-size:10px;padding:1px 5px;border-radius:3px;margin-left:4px;">Supermarket</span>'
|
||||
: '';
|
||||
|
||||
const popup = `
|
||||
<div style="min-width:160px">
|
||||
<strong style="font-size:13px">${escHtml(station.name)}</strong>${supermarketTag}<br>
|
||||
<span style="font-size:20px;font-weight:700;color:${colour}">${Number(station.price).toFixed(1)}p</span><br>
|
||||
<span style="font-size:12px;color:#6b7280">${escHtml(miles)} miles away</span><br>
|
||||
<span style="font-size:11px;color:#9ca3af">${escHtml(station.address)}, ${escHtml(station.postcode)}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const marker = L.circleMarker([station.lat, station.lng], {
|
||||
radius: 9,
|
||||
fillColor: colour,
|
||||
color: '#ffffff',
|
||||
weight: 2,
|
||||
opacity: 1,
|
||||
fillOpacity: 0.85,
|
||||
}).bindPopup(popup);
|
||||
|
||||
marker.addTo(this._map);
|
||||
this._markers.push(marker);
|
||||
});
|
||||
|
||||
const map = this._map;
|
||||
const lat = this.meta?.lat;
|
||||
const lng = this.meta?.lng;
|
||||
const zoom = this.getZoomForRadius(this.radius);
|
||||
|
||||
setTimeout(() => {
|
||||
map.invalidateSize();
|
||||
map.setView([lat, lng], zoom, { animate: true, duration: 0.5 });
|
||||
console.log(`[stationMap] setView lat=${lat} lng=${lng} zoom=${zoom} (radius=${this.radius}mi)`);
|
||||
}, 50);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user