Add location request

This commit is contained in:
2025-09-04 13:16:42 +02:00
parent 915ed53b42
commit 0cfac629b5

View File

@@ -100,6 +100,79 @@
box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.1);
}
/* Location Control Layout */
.location-control {
display: flex;
gap: 0.75rem;
align-items: center;
}
.location-select {
flex: 1;
}
.location-btn {
padding: 1rem 1.5rem;
background: linear-gradient(135deg, #10b981, #059669);
border: none;
border-radius: 0.75rem;
color: white;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
min-width: 140px;
}
.location-btn:hover {
background: linear-gradient(135deg, #059669, #047857);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.location-btn:disabled {
background: #374151;
color: #9ca3af;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.location-btn.loading {
background: linear-gradient(135deg, #6366f1, #4f46e5);
position: relative;
overflow: hidden;
}
.location-btn.loading::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
animation: loading-sweep 1.5s infinite;
}
@keyframes loading-sweep {
0% { left: -100%; }
100% { left: 100%; }
}
@media (max-width: 768px) {
.location-control {
flex-direction: column;
gap: 0.5rem;
}
.location-btn {
width: 100%;
min-width: auto;
}
}
/* Horizontal Time Tabs */
.time-tabs {
display: flex;
@@ -656,10 +729,15 @@
<div class="control-panel">
<div class="control-group">
<label class="control-label">Standort</label>
<select class="custom-select" id="locationSelect">
<option value="all">🌍 Alle Standorte</option>
<!-- Standorte werden dynamisch geladen -->
</select>
<div class="location-control">
<select class="custom-select location-select" id="locationSelect">
<option value="all">🌍 Alle Standorte</option>
<!-- Standorte werden dynamisch geladen -->
</select>
<button class="location-btn" id="findLocationBtn" onclick="findNearestLocation()" title="Nächstgelegenen Standort finden">
📍 Mein Standort
</button>
</div>
</div>
<div class="control-group">
@@ -831,6 +909,9 @@
}
}
// Global variable to store locations with coordinates
let locationsData = [];
// Load locations from database
async function loadLocations() {
try {
@@ -843,6 +924,9 @@
const locations = responseData.data || responseData; // Handle both formats
const locationSelect = document.getElementById('locationSelect');
// Store locations globally for distance calculations
locationsData = locations;
// Clear existing options except "Alle Standorte"
locationSelect.innerHTML = '<option value="all">🌍 Alle Standorte</option>';
@@ -859,6 +943,156 @@
}
}
// Calculate distance between two points using Haversine formula
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // Earth's radius in kilometers
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c; // Distance in kilometers
return distance;
}
function toRadians(degrees) {
return degrees * (Math.PI / 180);
}
// Find nearest location based on user's current position
async function findNearestLocation() {
const btn = document.getElementById('findLocationBtn');
const locationSelect = document.getElementById('locationSelect');
// Check if geolocation is supported
if (!navigator.geolocation) {
showLocationError('Geolocation wird von diesem Browser nicht unterstützt.');
return;
}
// Update button state to loading
btn.disabled = true;
btn.classList.add('loading');
btn.textContent = '🔍 Suche...';
try {
// Get user's current position
const position = await new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
resolve,
reject,
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 300000 // 5 minutes
}
);
});
const userLat = position.coords.latitude;
const userLon = position.coords.longitude;
// Calculate distances to all locations
const locationsWithDistance = locationsData.map(location => ({
...location,
distance: calculateDistance(
userLat,
userLon,
parseFloat(location.latitude),
parseFloat(location.longitude)
)
}));
// Find the nearest location
const nearestLocation = locationsWithDistance.reduce((nearest, current) => {
return current.distance < nearest.distance ? current : nearest;
});
// Select the nearest location in the dropdown
locationSelect.value = nearestLocation.name;
// Trigger change event to update the leaderboard
locationSelect.dispatchEvent(new Event('change'));
// Show success notification
showLocationSuccess(nearestLocation.name, nearestLocation.distance);
} catch (error) {
console.error('Error getting location:', error);
let errorMessage = 'Standort konnte nicht ermittelt werden.';
if (error.code) {
switch(error.code) {
case error.PERMISSION_DENIED:
errorMessage = 'Standortzugriff wurde verweigert. Bitte erlaube den Standortzugriff in den Browser-Einstellungen.';
break;
case error.POSITION_UNAVAILABLE:
errorMessage = 'Standortinformationen sind nicht verfügbar.';
break;
case error.TIMEOUT:
errorMessage = 'Zeitüberschreitung beim Abrufen des Standorts.';
break;
}
}
showLocationError(errorMessage);
} finally {
// Reset button state
btn.disabled = false;
btn.classList.remove('loading');
btn.textContent = '📍 Mein Standort';
}
}
// Show success notification for location finding
function showLocationSuccess(locationName, distance) {
const notificationBubble = document.getElementById('notificationBubble');
const notificationTitle = document.getElementById('notificationTitle');
const notificationSubtitle = document.getElementById('notificationSubtitle');
// Update notification content
notificationTitle.textContent = `📍 Standort gefunden!`;
notificationSubtitle.textContent = `${locationName} (${distance.toFixed(1)} km entfernt)`;
// Show notification
notificationBubble.classList.remove('hide');
notificationBubble.classList.add('show');
// Auto-hide after 4 seconds
setTimeout(() => {
hideNotification();
}, 4000);
}
// Show error notification for location finding
function showLocationError(message) {
const notificationBubble = document.getElementById('notificationBubble');
const notificationTitle = document.getElementById('notificationTitle');
const notificationSubtitle = document.getElementById('notificationSubtitle');
// Change notification style to error
notificationBubble.style.background = 'linear-gradient(135deg, #dc3545, #c82333)';
// Update notification content
notificationTitle.textContent = '❌ Fehler';
notificationSubtitle.textContent = message;
// Show notification
notificationBubble.classList.remove('hide');
notificationBubble.classList.add('show');
// Auto-hide after 6 seconds
setTimeout(() => {
hideNotification();
// Reset notification style
notificationBubble.style.background = 'linear-gradient(135deg, #00d4ff, #0891b2)';
}, 6000);
}
// Load data from local database via MCP
async function loadData() {
try {