mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 05:31:12 -05:00
196
backend/templates/maps/partials/map_container.html
Normal file
196
backend/templates/maps/partials/map_container.html
Normal file
@@ -0,0 +1,196 @@
|
||||
<!-- 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>
|
||||
Reference in New Issue
Block a user