This commit is contained in:
@@ -137,7 +137,14 @@ body {
|
||||
.site-footer__inner { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 24px 16px 30px; }
|
||||
.site-footer__links { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; font-weight: 600; }
|
||||
.site-footer__links a:hover { color: var(--color-primary); }
|
||||
.site-footer__link-button { border: 0; background: transparent; padding: 0; font: inherit; color: var(--color-text); cursor: pointer; }
|
||||
.site-footer__link-button:hover { color: var(--color-primary); }
|
||||
.site-footer__copy { margin: 0; color: var(--color-muted); font-size: 14px; text-align: center; }
|
||||
.cookie-consent { position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 220; }
|
||||
.cookie-consent[hidden] { display: none; }
|
||||
.cookie-consent__inner { max-width: 1120px; margin: 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 18px; align-items: center; padding: 18px 20px; background: rgba(255,255,255,0.98); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: 0 18px 40px rgba(0,0,0,0.16); backdrop-filter: blur(10px); }
|
||||
.cookie-consent__copy p { margin: 6px 0 0; color: var(--color-muted); }
|
||||
.cookie-consent__actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
|
||||
.legal-page { min-height: 40vh; }
|
||||
.content-card { background: #fff; border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 24px; box-shadow: var(--shadow-card); }
|
||||
.content-card--narrow { max-width: 860px; margin: 0 auto; }
|
||||
@@ -279,6 +286,8 @@ body {
|
||||
.forum-admin-item { padding-left: 16px; padding-right: 16px; }
|
||||
.forum-post__body,
|
||||
.forum-reply-form { padding: 18px 16px; }
|
||||
.cookie-consent__inner { grid-template-columns: 1fr; }
|
||||
.cookie-consent__actions { justify-content: stretch; }
|
||||
}
|
||||
|
||||
/* Auth & Dashboard */
|
||||
|
||||
@@ -55,6 +55,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const threads = Array.isArray(window.__threads) ? window.__threads : [];
|
||||
const EVENTS_RADIUS_KM = 20;
|
||||
const LOCATION_STORAGE_KEY = 'pkt_user_location';
|
||||
const LOCATION_SESSION_STORAGE_KEY = 'pkt_user_location_session';
|
||||
const LOCATION_SESSION_PREFERENCE_KEY = 'pkt_user_location_session_preference';
|
||||
|
||||
const el = {
|
||||
sliderTrack: document.getElementById('eventSlider'),
|
||||
@@ -75,7 +77,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
quickLng: document.getElementById('qsLng'),
|
||||
quickGeo: document.getElementById('quickGeo'),
|
||||
eventsSection: document.getElementById('events'),
|
||||
locationPreferenceModal: document.getElementById('locationPreferenceModal'),
|
||||
};
|
||||
let effectiveLocationPreference = locationPreference;
|
||||
|
||||
const fmtDate = (iso) => {
|
||||
const d = new Date(iso);
|
||||
@@ -98,7 +102,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
?.slice(prefix.length) || '';
|
||||
};
|
||||
|
||||
const persistLocation = (location) => {
|
||||
const persistLocation = (location, mode = 'persistent') => {
|
||||
if (!location || !Number.isFinite(location.lat) || !Number.isFinite(location.lng)) return;
|
||||
const payload = {
|
||||
lat: Number(location.lat.toFixed(6)),
|
||||
@@ -106,12 +110,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
label: location.label || 'Mein Standort',
|
||||
savedAt: new Date().toISOString(),
|
||||
};
|
||||
try {
|
||||
window.localStorage.setItem(LOCATION_STORAGE_KEY, JSON.stringify(payload));
|
||||
} catch (err) {
|
||||
// ignore
|
||||
if (mode === 'session') {
|
||||
try {
|
||||
window.sessionStorage.setItem(LOCATION_SESSION_STORAGE_KEY, JSON.stringify(payload));
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
window.localStorage.setItem(LOCATION_STORAGE_KEY, JSON.stringify(payload));
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
setCookie('pkt_user_location', JSON.stringify(payload), 30);
|
||||
}
|
||||
setCookie('pkt_user_location', JSON.stringify(payload), 30);
|
||||
if (el.quickLat) el.quickLat.value = payload.lat.toFixed(6);
|
||||
if (el.quickLng) el.quickLng.value = payload.lng.toFixed(6);
|
||||
if (el.quickLoc && (!el.quickLoc.value || el.quickLoc.value === 'Mein Standort')) {
|
||||
@@ -125,6 +137,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
window.sessionStorage.removeItem(LOCATION_SESSION_STORAGE_KEY);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
document.cookie = 'pkt_user_location=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; SameSite=Lax';
|
||||
if (el.quickLat) el.quickLat.value = '';
|
||||
if (el.quickLng) el.quickLng.value = '';
|
||||
@@ -133,6 +150,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
const getStoredLocation = () => {
|
||||
const candidates = [];
|
||||
try {
|
||||
const session = window.sessionStorage.getItem(LOCATION_SESSION_STORAGE_KEY);
|
||||
if (session) candidates.push(session);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
const local = window.localStorage.getItem(LOCATION_STORAGE_KEY);
|
||||
if (local) candidates.push(local);
|
||||
@@ -333,7 +356,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
lng: pos.coords.longitude,
|
||||
label: 'Mein Standort',
|
||||
};
|
||||
persistLocation(location);
|
||||
persistLocation(location, options.persistMode || 'persistent');
|
||||
resolve(location);
|
||||
},
|
||||
() => resolve(null),
|
||||
@@ -345,19 +368,133 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
);
|
||||
});
|
||||
|
||||
const closeLocationPreferenceModal = () => {
|
||||
el.locationPreferenceModal?.classList.remove('open');
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-location-pref-close]').forEach(btn => {
|
||||
btn.addEventListener('click', closeLocationPreferenceModal);
|
||||
});
|
||||
el.locationPreferenceModal?.addEventListener('click', (event) => {
|
||||
if (event.target === el.locationPreferenceModal) {
|
||||
closeLocationPreferenceModal();
|
||||
}
|
||||
});
|
||||
|
||||
const saveLocationPreference = async (preference) => {
|
||||
effectiveLocationPreference = preference;
|
||||
if (!isLoggedIn) {
|
||||
try {
|
||||
window.localStorage.setItem('pkt_location_preference_guest', preference);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const body = new URLSearchParams({ preference });
|
||||
const response = await fetch('/api/location-preference', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||
},
|
||||
body: body.toString(),
|
||||
});
|
||||
return response.ok;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const getSessionPreference = () => {
|
||||
try {
|
||||
return window.sessionStorage.getItem(LOCATION_SESSION_PREFERENCE_KEY);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const setSessionPreference = (value) => {
|
||||
try {
|
||||
if (!value) {
|
||||
window.sessionStorage.removeItem(LOCATION_SESSION_PREFERENCE_KEY);
|
||||
} else {
|
||||
window.sessionStorage.setItem(LOCATION_SESSION_PREFERENCE_KEY, value);
|
||||
}
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
|
||||
const resolvePromptChoice = () => new Promise((resolve) => {
|
||||
if (!el.locationPreferenceModal) {
|
||||
resolve('disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
const buttons = el.locationPreferenceModal.querySelectorAll('[data-location-pref-choice]');
|
||||
const cleanup = () => {
|
||||
buttons.forEach(button => button.removeEventListener('click', handleClick));
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
};
|
||||
const finish = (value) => {
|
||||
cleanup();
|
||||
closeLocationPreferenceModal();
|
||||
resolve(value);
|
||||
};
|
||||
const handleClick = (event) => {
|
||||
const value = event.currentTarget.getAttribute('data-location-pref-choice') || 'disabled';
|
||||
finish(value);
|
||||
};
|
||||
const handleKeydown = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
finish('disabled');
|
||||
}
|
||||
};
|
||||
|
||||
buttons.forEach(button => button.addEventListener('click', handleClick));
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
el.locationPreferenceModal.classList.add('open');
|
||||
});
|
||||
|
||||
const ensureEventsLocation = async () => {
|
||||
if (locationPreference === 'disabled') {
|
||||
const sessionPreference = getSessionPreference();
|
||||
if (effectiveLocationPreference === 'disabled') {
|
||||
clearStoredLocation();
|
||||
renderSlider(null);
|
||||
return null;
|
||||
}
|
||||
|
||||
const stored = applyStoredLocationToForm();
|
||||
if (stored && locationPreference !== 'enabled') {
|
||||
if (stored && effectiveLocationPreference !== 'enabled' && sessionPreference !== 'session') {
|
||||
renderSlider(stored);
|
||||
return stored;
|
||||
}
|
||||
const location = await requestLocation();
|
||||
|
||||
if (effectiveLocationPreference === 'prompt') {
|
||||
const choice = sessionPreference || await resolvePromptChoice();
|
||||
if (choice === 'session') {
|
||||
setSessionPreference('session');
|
||||
const location = await requestLocation({ persistMode: 'session' });
|
||||
renderSlider(location || stored);
|
||||
return location;
|
||||
}
|
||||
if (choice === 'disabled') {
|
||||
await saveLocationPreference('disabled');
|
||||
clearStoredLocation();
|
||||
renderSlider(null);
|
||||
return null;
|
||||
}
|
||||
if (choice === 'enabled') {
|
||||
await saveLocationPreference('enabled');
|
||||
effectiveLocationPreference = 'enabled';
|
||||
}
|
||||
}
|
||||
|
||||
const location = await requestLocation({
|
||||
persistMode: effectiveLocationPreference === 'enabled' ? 'persistent' : 'session',
|
||||
});
|
||||
renderSlider(location || stored);
|
||||
return location;
|
||||
};
|
||||
@@ -384,7 +521,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
lat: pos.coords.latitude,
|
||||
lng: pos.coords.longitude,
|
||||
label: 'Mein Standort',
|
||||
});
|
||||
}, effectiveLocationPreference === 'enabled' ? 'persistent' : 'session');
|
||||
renderSlider(getStoredLocation());
|
||||
},
|
||||
() => alert('Standort konnte nicht ermittelt werden.')
|
||||
@@ -426,14 +563,25 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});
|
||||
|
||||
const initialLocation = locationPreference === 'disabled' ? null : applyStoredLocationToForm();
|
||||
if (locationPreference === 'disabled') {
|
||||
try {
|
||||
if (!isLoggedIn) {
|
||||
const guestPreference = window.localStorage.getItem('pkt_location_preference_guest');
|
||||
if (guestPreference && ['disabled', 'prompt', 'enabled'].includes(guestPreference)) {
|
||||
effectiveLocationPreference = guestPreference;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const initialLocation = effectiveLocationPreference === 'disabled' ? null : applyStoredLocationToForm();
|
||||
if (effectiveLocationPreference === 'disabled') {
|
||||
clearStoredLocation();
|
||||
}
|
||||
renderSlider(initialLocation);
|
||||
renderThreadSlider();
|
||||
|
||||
if (locationPreference === 'enabled' && window.location.pathname === '/') {
|
||||
if (effectiveLocationPreference === 'enabled' && window.location.pathname === '/') {
|
||||
ensureEventsLocation();
|
||||
} else if (window.location.hash === '#events' || window.location.hash === '#quicksearch') {
|
||||
ensureEventsLocation();
|
||||
|
||||
Reference in New Issue
Block a user