Refactor location results, universal map, and road trip planner templates to utilize Alpine.js for state management and event handling. Enhanced geolocation button functionality, improved map initialization, and streamlined trip management interactions.

This commit is contained in:
pacnpal
2025-09-26 13:55:06 -04:00
parent d4431acb39
commit 757ad1be89
3 changed files with 414 additions and 45 deletions

View File

@@ -197,10 +197,122 @@
<!-- Leaflet MarkerCluster JS -->
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
<!-- AlpineJS Map Component (HTMX + AlpineJS Only) -->
<div x-data="universalMap" x-init="initMap()" style="display: none;">
<!-- Map functionality handled by AlpineJS + HTMX -->
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('universalMap', () => ({
map: null,
markers: {},
markerCluster: null,
init() {
this.initMap();
this.setupFilters();
},
initMap() {
// Initialize Leaflet map
if (typeof L !== 'undefined') {
this.map = L.map('map-container').setView([39.8283, -98.5795], 4);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(this.map);
// Initialize marker cluster group
this.markerCluster = L.markerClusterGroup({
iconCreateFunction: (cluster) => {
const count = cluster.getChildCount();
return L.divIcon({
html: `<div class="cluster-marker-inner">${count}</div>`,
className: 'cluster-marker',
iconSize: [40, 40]
});
}
});
this.map.addLayer(this.markerCluster);
this.loadMapData();
}
},
setupFilters() {
// Handle filter pill clicks
document.querySelectorAll('.filter-pill').forEach(pill => {
pill.addEventListener('click', () => {
const checkbox = pill.querySelector('input[type="checkbox"]');
checkbox.checked = !checkbox.checked;
pill.classList.toggle('active', checkbox.checked);
this.updateFilters();
});
// Set initial state
const checkbox = pill.querySelector('input[type="checkbox"]');
pill.classList.toggle('active', checkbox.checked);
});
},
loadMapData() {
// Load initial map data via HTMX
const form = document.getElementById('map-filters');
if (form) {
htmx.trigger(form, 'submit');
}
},
updateFilters() {
// Trigger HTMX filter update
const form = document.getElementById('map-filters');
if (form) {
htmx.trigger(form, 'change');
}
},
addMarker(data) {
const icon = this.getMarkerIcon(data.type);
const marker = L.marker([data.lat, data.lng], { icon })
.bindPopup(this.createPopupContent(data));
this.markerCluster.addLayer(marker);
this.markers[data.id] = marker;
},
getMarkerIcon(type) {
const icons = {
'park': '🎢',
'ride': '🎠',
'company': '🏢',
'default': '📍'
};
return L.divIcon({
html: `<div class="location-marker-inner">${icons[type] || icons.default}</div>`,
className: 'location-marker',
iconSize: [30, 30],
iconAnchor: [15, 15]
});
},
createPopupContent(data) {
return `
<div class="location-info-popup">
<h3>${data.name}</h3>
${data.description ? `<p>${data.description}</p>` : ''}
${data.location ? `<p><strong>Location:</strong> ${data.location}</p>` : ''}
${data.url ? `<p><a href="${data.url}" class="text-blue-600 hover:text-blue-800">View Details</a></p>` : ''}
</div>
`;
},
clearMarkers() {
this.markerCluster.clearLayers();
this.markers = {};
}
}));
});
</script>
<!-- Map Component Container -->
<div x-data="universalMap" x-init="init()" style="display: none;"></div>
<style>
.cluster-marker {