Files
thrillwiki_django_no_react/templates/maps/partials/map_container.html
pacnpal b5bae44cb8 Add Road Trip Planner template with interactive map and trip management features
- Implemented a new HTML template for the Road Trip Planner.
- Integrated Leaflet.js for interactive mapping and routing.
- Added functionality for searching and selecting parks to include in a trip.
- Enabled drag-and-drop reordering of selected parks.
- Included trip optimization and route calculation features.
- Created a summary display for trip statistics.
- Added functionality to save trips and manage saved trips.
- Enhanced UI with responsive design and dark mode support.
2025-08-15 20:53:00 -04:00

196 lines
7.7 KiB
HTML

<!-- Reusable Map Container Component -->
<div class="relative">
<div id="{{ map_id|default:'map-container' }}"
class="map-container {% if map_classes %}{{ map_classes }}{% endif %}"
style="{% if map_height %}height: {{ map_height }};{% endif %}">
</div>
<!-- Map Loading Indicator -->
<div id="{{ map_id|default:'map-container' }}-loading"
class="htmx-indicator absolute inset-0 flex items-center justify-center bg-gray-100 dark:bg-gray-800 rounded-lg">
<div class="text-center">
<div class="w-8 h-8 mx-auto mb-4 border-4 border-blue-500 rounded-full border-t-transparent animate-spin"></div>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ loading_text|default:"Loading map data..." }}
</p>
</div>
</div>
<!-- Map Controls Overlay -->
{% if show_controls %}
<div class="absolute top-4 right-4 z-10 space-y-2">
{% if show_fullscreen %}
<button id="{{ map_id|default:'map-container' }}-fullscreen"
class="p-2 bg-white dark:bg-gray-800 rounded-lg shadow-md hover:shadow-lg transition-shadow"
title="Toggle Fullscreen">
<i class="fas fa-expand text-gray-600 dark:text-gray-400"></i>
</button>
{% endif %}
{% if show_layers %}
<button id="{{ map_id|default:'map-container' }}-layers"
class="p-2 bg-white dark:bg-gray-800 rounded-lg shadow-md hover:shadow-lg transition-shadow"
title="Map Layers">
<i class="fas fa-layer-group text-gray-600 dark:text-gray-400"></i>
</button>
{% endif %}
{% if show_locate %}
<button id="{{ map_id|default:'map-container' }}-locate"
class="p-2 bg-white dark:bg-gray-800 rounded-lg shadow-md hover:shadow-lg transition-shadow"
title="Find My Location">
<i class="fas fa-crosshairs text-gray-600 dark:text-gray-400"></i>
</button>
{% endif %}
</div>
{% endif %}
<!-- Map Legend -->
{% if show_legend %}
<div class="absolute bottom-4 left-4 z-10">
<div class="p-3 bg-white dark:bg-gray-800 rounded-lg shadow-md">
<h4 class="text-sm font-semibold text-gray-900 dark:text-white mb-2">Legend</h4>
<div class="space-y-1 text-xs">
{% if legend_items %}
{% for item in legend_items %}
<div class="flex items-center">
<div class="w-3 h-3 mr-2 rounded-full" style="background-color: {{ item.color }};"></div>
<span class="text-gray-700 dark:text-gray-300">{{ item.label }}</span>
</div>
{% endfor %}
{% else %}
<div class="flex items-center">
<div class="w-3 h-3 mr-2 rounded-full bg-green-500"></div>
<span class="text-gray-700 dark:text-gray-300">Operating Parks</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 mr-2 rounded-full bg-blue-500"></div>
<span class="text-gray-700 dark:text-gray-300">Rides</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 mr-2 rounded-full bg-purple-500"></div>
<span class="text-gray-700 dark:text-gray-300">Companies</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 mr-2 rounded-full bg-red-500"></div>
<span class="text-gray-700 dark:text-gray-300">Closed/Demolished</span>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
<!-- Map Container Styles -->
<style>
.map-container {
height: {{ map_height|default:'60vh' }};
min-height: {{ min_height|default:'400px' }};
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.map-container.fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
border-radius: 0;
height: 100vh !important;
min-height: 100vh !important;
}
.map-container.fullscreen + .absolute {
z-index: 10000;
}
/* Dark mode adjustments */
.dark .map-container {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2);
}
</style>
<!-- Map Container JavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const mapId = '{{ map_id|default:"map-container" }}';
const mapContainer = document.getElementById(mapId);
{% if show_fullscreen %}
// Fullscreen toggle
const fullscreenBtn = document.getElementById(mapId + '-fullscreen');
if (fullscreenBtn) {
fullscreenBtn.addEventListener('click', function() {
const icon = this.querySelector('i');
if (mapContainer.classList.contains('fullscreen')) {
mapContainer.classList.remove('fullscreen');
icon.className = 'fas fa-expand text-gray-600 dark:text-gray-400';
this.title = 'Toggle Fullscreen';
} else {
mapContainer.classList.add('fullscreen');
icon.className = 'fas fa-compress text-gray-600 dark:text-gray-400';
this.title = 'Exit Fullscreen';
}
// Trigger map resize if map instance exists
if (window[mapId + 'Instance']) {
setTimeout(() => {
window[mapId + 'Instance'].invalidateSize();
}, 100);
}
});
}
{% endif %}
{% if show_locate %}
// Geolocation
const locateBtn = document.getElementById(mapId + '-locate');
if (locateBtn && navigator.geolocation) {
locateBtn.addEventListener('click', function() {
const icon = this.querySelector('i');
icon.className = 'fas fa-spinner fa-spin text-gray-600 dark:text-gray-400';
navigator.geolocation.getCurrentPosition(
function(position) {
icon.className = 'fas fa-crosshairs text-gray-600 dark:text-gray-400';
// Trigger custom event with user location
const event = new CustomEvent('userLocationFound', {
detail: {
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy
}
});
mapContainer.dispatchEvent(event);
},
function(error) {
icon.className = 'fas fa-crosshairs text-red-500';
console.error('Geolocation error:', error);
// Reset icon after delay
setTimeout(() => {
icon.className = 'fas fa-crosshairs text-gray-600 dark:text-gray-400';
}, 2000);
}
);
});
}
{% endif %}
// Escape key handler for fullscreen
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && mapContainer.classList.contains('fullscreen')) {
const fullscreenBtn = document.getElementById(mapId + '-fullscreen');
if (fullscreenBtn) {
fullscreenBtn.click();
}
}
});
});
</script>