fix: proper umlauts across all files, simplify gallery upload, fix Menu spelling, show local events in overview
This commit is contained in:
parent
e805abbf12
commit
e91cd8572e
@ -562,6 +562,70 @@ textarea:focus {
|
|||||||
margin-top: var(--space-2);
|
margin-top: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gallery Upload */
|
||||||
|
.gallery-upload {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-preview {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-thumb {
|
||||||
|
position: relative;
|
||||||
|
width: 5.5rem;
|
||||||
|
height: 5.5rem;
|
||||||
|
border-radius: var(--radius-sm, 0.5rem);
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-thumb img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-thumb-remove {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.2rem;
|
||||||
|
right: 0.2rem;
|
||||||
|
width: 1.4rem;
|
||||||
|
height: 1.4rem;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-add-btn {
|
||||||
|
width: 5.5rem;
|
||||||
|
height: 5.5rem;
|
||||||
|
border: 2px dashed var(--color-border-strong);
|
||||||
|
border-radius: var(--radius-sm, 0.5rem);
|
||||||
|
background: transparent;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: var(--color-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: border-color 0.15s, color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-add-btn:hover {
|
||||||
|
border-color: var(--olive);
|
||||||
|
color: var(--olive);
|
||||||
|
}
|
||||||
|
|
||||||
.site-footer {
|
.site-footer {
|
||||||
width: min(100% - 2rem, var(--max-width));
|
width: min(100% - 2rem, var(--max-width));
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
.profile-page {
|
.profile-page {
|
||||||
/* Reserve a large safe zone below sticky nav so title/actions are never covered. */
|
/* Reserve a large safe zone below sticky nav so title/actions are never covered. */
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
padding-top: 6.5rem;
|
padding-top: 6.5rem;
|
||||||
@ -76,7 +76,7 @@
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Konsistentes Karten-Layout fuer alle Profilsektionen. */
|
/* Konsistentes Karten-Layout für alle Profilsektionen. */
|
||||||
.profile-panel {
|
.profile-panel {
|
||||||
background: rgba(255, 255, 255, 0.88);
|
background: rgba(255, 255, 255, 0.88);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
@ -113,7 +113,7 @@
|
|||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Einzelne Eventkarte fuer "Meine Events" und "Meine Anmeldungen". */
|
/* Einzelne Eventkarte für "Meine Events" und "Meine Anmeldungen". */
|
||||||
.profile-event-card {
|
.profile-event-card {
|
||||||
border: 1px solid rgba(107, 107, 5, 0.25);
|
border: 1px solid rgba(107, 107, 5, 0.25);
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "Italienische Tavolata",
|
"title": "Italienische Tavolata",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"hostMessage": [
|
"hostMessage": [
|
||||||
"Ciao zusammen! Ich liebe die italienische Küche, nicht nur wegen des Essens, sondern wegen des Gefühls: Alle sitzen an einem langen Tisch, teilen sich grosse Platten und geniessen die Zeit.",
|
"Ciao zusammen! Ich liebe die italienische Küche, nicht nur wegen des Essens, sondern wegen des Gefühls: Alle sitzen an einem langen Tisch, teilen sich grosse Platten und geniessen die Zeit.",
|
||||||
"Genau das möchte ich mit euch teilen. Ich bereite dafuer eine klassische Tavolata vor, bei der verschiedene Gerichte in die Mitte des Tisches kommen und sich jeder bedient."
|
"Genau das möchte ich mit euch teilen. Ich bereite dafür eine klassische Tavolata vor, bei der verschiedene Gerichte in die Mitte des Tisches kommen und sich jeder bedient."
|
||||||
],
|
],
|
||||||
"menu": [
|
"menu": [
|
||||||
"Bruschetta-Variationen und Antipasti",
|
"Bruschetta-Variationen und Antipasti",
|
||||||
|
|||||||
@ -285,6 +285,15 @@
|
|||||||
<label for="eventDescription">Beschreibung des Events</label>
|
<label for="eventDescription">Beschreibung des Events</label>
|
||||||
<textarea id="eventDescription" name="eventDescription" rows="6" required></textarea>
|
<textarea id="eventDescription" name="eventDescription" rows="6" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label>Fotos hinzufügen <span class="field-hint-inline">(optional)</span></label>
|
||||||
|
<div class="gallery-upload">
|
||||||
|
<div class="gallery-preview" id="galleryPreview"></div>
|
||||||
|
<button type="button" class="gallery-add-btn" id="galleryAddBtn" aria-label="Foto hinzufügen">+</button>
|
||||||
|
<input type="file" id="galleryFileInput" accept="image/*" multiple hidden />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// =============================
|
// =============================
|
||||||
// SETUP: Wichtige HTML-Elemente holen
|
// SETUP: Wichtige HTML-Elemente holen
|
||||||
// Diese Konstanten verbinden unser JavaScript mit dem HTML.
|
// Diese Konstanten verbinden unser JavaScript mit dem HTML.
|
||||||
// So können wir später Buttons, Formularfelder und Bereiche steuern.
|
// So können wir später Buttons, Formularfelder und Bereiche steuern.
|
||||||
@ -428,9 +428,9 @@ function buildStoredEvent() {
|
|||||||
? []
|
? []
|
||||||
: getCheckboxValues("allergies").split(", ").filter(Boolean),
|
: getCheckboxValues("allergies").split(", ").filter(Boolean),
|
||||||
allergiesNote: form.elements.allergiesOther.value.trim(),
|
allergiesNote: form.elements.allergiesOther.value.trim(),
|
||||||
// Host wird separat gefuehrt und nicht als angemeldeter Gast gezaehlt.
|
// Host wird separat geführt und nicht als angemeldeter Gast gezählt.
|
||||||
participants: [],
|
participants: [],
|
||||||
gallery: [],
|
gallery: [...galleryImages],
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
source: "local"
|
source: "local"
|
||||||
};
|
};
|
||||||
@ -737,6 +737,64 @@ function focusFieldByName(fieldName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============================
|
||||||
|
// STEP 8b: Galerie-Upload (Fotos hinzufügen)
|
||||||
|
// =============================
|
||||||
|
const galleryImages = [];
|
||||||
|
|
||||||
|
function registerGalleryHandlers() {
|
||||||
|
const addBtn = document.getElementById("galleryAddBtn");
|
||||||
|
const fileInput = document.getElementById("galleryFileInput");
|
||||||
|
const preview = document.getElementById("galleryPreview");
|
||||||
|
|
||||||
|
if (!addBtn) return;
|
||||||
|
|
||||||
|
// Klick auf + öffnet direkt den Datei-Dialog
|
||||||
|
addBtn.addEventListener("click", () => {
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Datei(en) hochladen
|
||||||
|
fileInput.addEventListener("change", () => {
|
||||||
|
Array.from(fileInput.files).forEach(file => {
|
||||||
|
if (!file.type.startsWith("image/")) return;
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
addGalleryImage(e.target.result);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
fileInput.value = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function addGalleryImage(src) {
|
||||||
|
galleryImages.push(src);
|
||||||
|
renderGalleryPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeGalleryImage(index) {
|
||||||
|
galleryImages.splice(index, 1);
|
||||||
|
renderGalleryPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderGalleryPreview() {
|
||||||
|
preview.innerHTML = "";
|
||||||
|
galleryImages.forEach((src, i) => {
|
||||||
|
const thumb = document.createElement("div");
|
||||||
|
thumb.className = "gallery-thumb";
|
||||||
|
thumb.innerHTML = `
|
||||||
|
<img src="${src}" alt="Foto ${i + 1}">
|
||||||
|
<button type="button" class="gallery-thumb-remove" aria-label="Foto entfernen">×</button>
|
||||||
|
`;
|
||||||
|
thumb.querySelector(".gallery-thumb-remove").addEventListener("click", () => {
|
||||||
|
removeGalleryImage(i);
|
||||||
|
});
|
||||||
|
preview.appendChild(thumb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// =============================
|
// =============================
|
||||||
// STEP 9: Alles starten
|
// STEP 9: Alles starten
|
||||||
// Hier werden alle Event Listener registriert
|
// Hier werden alle Event Listener registriert
|
||||||
@ -765,6 +823,7 @@ function initEventCreationFlow() {
|
|||||||
registerMenuBulletHandler();
|
registerMenuBulletHandler();
|
||||||
registerValidationFeedbackHandlers();
|
registerValidationFeedbackHandlers();
|
||||||
registerReviewEditHandlers();
|
registerReviewEditHandlers();
|
||||||
|
registerGalleryHandlers();
|
||||||
|
|
||||||
// Browser-Zurück-Taste: vorherigen Schritt wiederherstellen
|
// Browser-Zurück-Taste: vorherigen Schritt wiederherstellen
|
||||||
window.addEventListener("popstate", (e) => {
|
window.addEventListener("popstate", (e) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||||
@ -152,13 +152,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
return userEmail === hostEmail;
|
return userEmail === hostEmail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback fuer aeltere Datensaetze ohne hostEmail.
|
// Fallback für ältere Datensätze ohne hostEmail.
|
||||||
const userFirstName = String(user.vorname || '').trim().toLowerCase();
|
const userFirstName = String(user.vorname || '').trim().toLowerCase();
|
||||||
const hostName = String(event.host?.name || '').trim().toLowerCase();
|
const hostName = String(event.host?.name || '').trim().toLowerCase();
|
||||||
return Boolean(userFirstName && hostName && userFirstName === hostName);
|
return Boolean(userFirstName && hostName && userFirstName === hostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prueft, ob der aktuelle Benutzer bereits in der Teilnehmerliste des Events steht.
|
// Prüft, ob der aktuelle Benutzer bereits in der Teilnehmerliste des Events steht.
|
||||||
function isUserListedInEventParticipants(event, user) {
|
function isUserListedInEventParticipants(event, user) {
|
||||||
if (!event || !user || !Array.isArray(event.participants)) {
|
if (!event || !user || !Array.isArray(event.participants)) {
|
||||||
return false;
|
return false;
|
||||||
@ -258,7 +258,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
: ['Der Host hat für dieses Event noch keine Nachricht hinterlegt.'];
|
: ['Der Host hat für dieses Event noch keine Nachricht hinterlegt.'];
|
||||||
const menuItems = Array.isArray(event.menu) && event.menu.length > 0
|
const menuItems = Array.isArray(event.menu) && event.menu.length > 0
|
||||||
? event.menu
|
? event.menu
|
||||||
: ['Menü wird in Kuerze bekannt gegeben.'];
|
: ['Menü wird in Kürze bekannt gegeben.'];
|
||||||
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
|
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
|
||||||
? event.specifications
|
? event.specifications
|
||||||
: [];
|
: [];
|
||||||
@ -329,7 +329,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
<img src="${locationIconPath}" alt="">
|
<img src="${locationIconPath}" alt="">
|
||||||
${event.location}
|
${event.location}
|
||||||
</span>
|
</span>
|
||||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste</p>
|
<p class="event-date-time">${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gäste</p>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="detail-title">${event.title}</h1>
|
<h1 class="detail-title">${event.title}</h1>
|
||||||
<div class="event-meta-row detail-chip-row">
|
<div class="event-meta-row detail-chip-row">
|
||||||
@ -349,7 +349,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article class="detail-panel detail-panel-compact">
|
<article class="detail-panel detail-panel-compact">
|
||||||
<h2 class="detail-section-title">Menue</h2>
|
<h2 class="detail-section-title">Menu</h2>
|
||||||
<ul class="detail-menu-list">
|
<ul class="detail-menu-list">
|
||||||
${menuItems.map(item => `<li>${item}</li>`).join('')}
|
${menuItems.map(item => `<li>${item}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
@ -393,7 +393,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
<img src="${locationIconPath}" alt="">
|
<img src="${locationIconPath}" alt="">
|
||||||
${event.location}
|
${event.location}
|
||||||
</span>
|
</span>
|
||||||
<span class="detail-action-meta-text">| ${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gaeste</span>
|
<span class="detail-action-meta-text">| ${displayDate} | ${displayTime} | ${confirmedGuests}/${totalGuests} Gäste</span>
|
||||||
</small>
|
</small>
|
||||||
<strong>${event.title}</strong>
|
<strong>${event.title}</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||||
@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prueft, ob ein Event dem aktuellen Benutzer gehoert.
|
// Prüft, ob ein Event dem aktuellen Benutzer gehört.
|
||||||
function isEventOwnedByCurrentUser(event, user) {
|
function isEventOwnedByCurrentUser(event, user) {
|
||||||
if (!event || !user) {
|
if (!event || !user) {
|
||||||
return false;
|
return false;
|
||||||
@ -198,7 +198,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
: `${timeString} Uhr`;
|
: `${timeString} Uhr`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baut aus Eventdatum/-zeit ein Date-Objekt fuer Fristlogik und Vergleiche.
|
// Baut aus Eventdatum/-zeit ein Date-Objekt für Fristlogik und Vergleiche.
|
||||||
function parseEventDateTime(event) {
|
function parseEventDateTime(event) {
|
||||||
if (!event?.date) {
|
if (!event?.date) {
|
||||||
return null;
|
return null;
|
||||||
@ -252,7 +252,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zaehlt eindeutige Registrierungen eines Events ueber alle Benutzer.
|
// Zählt eindeutige Registrierungen eines Events über alle Benutzer.
|
||||||
function countRegistrationsForEvent(registrationMap, eventId) {
|
function countRegistrationsForEvent(registrationMap, eventId) {
|
||||||
return Object.values(registrationMap).reduce((count, ids) => {
|
return Object.values(registrationMap).reduce((count, ids) => {
|
||||||
const hasEvent = Array.isArray(ids)
|
const hasEvent = Array.isArray(ids)
|
||||||
@ -385,7 +385,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<img src="${locationIconPath}" alt="">
|
<img src="${locationIconPath}" alt="">
|
||||||
${event.location}
|
${event.location}
|
||||||
</span>
|
</span>
|
||||||
<p class="event-date-time">${displayDate} | ${displayTime} | ${bookedSeats}/${totalCapacity} Gaeste</p>
|
<p class="event-date-time">${displayDate} | ${displayTime} | ${bookedSeats}/${totalCapacity} Gäste</p>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="event-title">${event.title}</h2>
|
<h2 class="event-title">${event.title}</h2>
|
||||||
<div class="event-meta-row">
|
<div class="event-meta-row">
|
||||||
@ -444,7 +444,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anmeldung: Benutzer zum Event hinzufuegen und Snackbar anzeigen.
|
// Anmeldung: Benutzer zum Event hinzufügen und Snackbar anzeigen.
|
||||||
if (action === 'register' && !isFull && !isRegistrationClosed) {
|
if (action === 'register' && !isFull && !isRegistrationClosed) {
|
||||||
idSet.add(Number(event.id));
|
idSet.add(Number(event.id));
|
||||||
const snackbar = document.getElementById('snackbar');
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// =============================================
|
// =============================================
|
||||||
// Galerie-Karussell (Startseite)
|
// Galerie-Karussell (Startseite)
|
||||||
// Diese Datei steuert die Foto-Galerie mit Pfeilen.
|
// Diese Datei steuert die Foto-Galerie mit Pfeilen.
|
||||||
// =============================================
|
// =============================================
|
||||||
@ -9,7 +9,7 @@ const prevArrow = document.querySelector('.gallery__arrow--prev');
|
|||||||
const nextArrow = document.querySelector('.gallery__arrow--next');
|
const nextArrow = document.querySelector('.gallery__arrow--next');
|
||||||
const dotsContainer = document.querySelector('.gallery__dots');
|
const dotsContainer = document.querySelector('.gallery__dots');
|
||||||
|
|
||||||
// Nur ausfuehren, wenn die Galerie auf der Seite vorhanden ist.
|
// Nur ausführen, wenn die Galerie auf der Seite vorhanden ist.
|
||||||
if (carouselTrack) {
|
if (carouselTrack) {
|
||||||
// Alle einzelnen Karten/Bilder im Track sammeln.
|
// Alle einzelnen Karten/Bilder im Track sammeln.
|
||||||
const items = Array.from(carouselTrack.querySelectorAll('.gallery__item'));
|
const items = Array.from(carouselTrack.querySelectorAll('.gallery__item'));
|
||||||
@ -62,7 +62,7 @@ if (carouselTrack) {
|
|||||||
updateTrack();
|
updateTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Geht zur naechsten Seite (mit Wrap-around am Ende).
|
// Geht zur nächsten Seite (mit Wrap-around am Ende).
|
||||||
function showNext() {
|
function showNext() {
|
||||||
activePage = (activePage + 1) % pageCount;
|
activePage = (activePage + 1) % pageCount;
|
||||||
updateTrack();
|
updateTrack();
|
||||||
@ -80,13 +80,13 @@ if (carouselTrack) {
|
|||||||
if (nextArrow) nextArrow.addEventListener('click', showNext);
|
if (nextArrow) nextArrow.addEventListener('click', showNext);
|
||||||
if (prevArrow) prevArrow.addEventListener('click', showPrev);
|
if (prevArrow) prevArrow.addEventListener('click', showPrev);
|
||||||
|
|
||||||
// Tastatur-Support fuer Barrierefreiheit.
|
// Tastatur-Support für Barrierefreiheit.
|
||||||
document.addEventListener('keydown', function(event) {
|
document.addEventListener('keydown', function(event) {
|
||||||
if (event.key === 'ArrowRight') showNext();
|
if (event.key === 'ArrowRight') showNext();
|
||||||
if (event.key === 'ArrowLeft') showPrev();
|
if (event.key === 'ArrowLeft') showPrev();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reagiert auf Bildschirmgroessen-Aenderungen.
|
// Reagiert auf Bildschirmgrössen-Änderungen.
|
||||||
window.addEventListener('resize', function() {
|
window.addEventListener('resize', function() {
|
||||||
var newPerPage = getItemsPerPage();
|
var newPerPage = getItemsPerPage();
|
||||||
if (newPerPage !== itemsPerPage) {
|
if (newPerPage !== itemsPerPage) {
|
||||||
@ -99,7 +99,7 @@ if (carouselTrack) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Lightbox: Bild vergroessern bei Klick
|
// Lightbox: Bild vergrössern bei Klick
|
||||||
// =============================================
|
// =============================================
|
||||||
const lightbox = document.getElementById('gallery-lightbox');
|
const lightbox = document.getElementById('gallery-lightbox');
|
||||||
const lightboxImage = lightbox ? lightbox.querySelector('.lightbox__image') : null;
|
const lightboxImage = lightbox ? lightbox.querySelector('.lightbox__image') : null;
|
||||||
@ -119,7 +119,7 @@ if (carouselTrack) {
|
|||||||
lightboxImage.src = '';
|
lightboxImage.src = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Klick auf Galerie-Bild oeffnet die Lightbox.
|
// Klick auf Galerie-Bild öffnet die Lightbox.
|
||||||
items.forEach(function(item) {
|
items.forEach(function(item) {
|
||||||
var img = item.querySelector('img');
|
var img = item.querySelector('img');
|
||||||
if (img) {
|
if (img) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// =============================================
|
// =============================================
|
||||||
// Mini-Galerie auf der Landingpage
|
// Mini-Galerie auf der Landingpage
|
||||||
// Diese Datei hebt immer ein Bild hervor und
|
// Diese Datei hebt immer ein Bild hervor und
|
||||||
// erlaubt Navigation mit Pfeilen/Tastatur.
|
// erlaubt Navigation mit Pfeilen/Tastatur.
|
||||||
@ -38,7 +38,7 @@ function showPrev() {
|
|||||||
if (nextBtn) nextBtn.addEventListener('click', showNext);
|
if (nextBtn) nextBtn.addEventListener('click', showNext);
|
||||||
if (prevBtn) prevBtn.addEventListener('click', showPrev);
|
if (prevBtn) prevBtn.addEventListener('click', showPrev);
|
||||||
|
|
||||||
// Tastatursteuerung fuer bessere Bedienbarkeit.
|
// Tastatursteuerung für bessere Bedienbarkeit.
|
||||||
document.addEventListener('keydown', (event) => {
|
document.addEventListener('keydown', (event) => {
|
||||||
if (event.key === 'ArrowRight') {
|
if (event.key === 'ArrowRight') {
|
||||||
showNext();
|
showNext();
|
||||||
|
|||||||
10
js/login.js
10
js/login.js
@ -1,4 +1,4 @@
|
|||||||
// =============================================
|
// =============================================
|
||||||
// Login-Logik
|
// Login-Logik
|
||||||
// Diese Datei validiert die Eingaben, sucht den
|
// Diese Datei validiert die Eingaben, sucht den
|
||||||
// Benutzer im localStorage und legt die Session an.
|
// Benutzer im localStorage und legt die Session an.
|
||||||
@ -25,12 +25,12 @@ function getStoredUsers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speichert den aktiven Benutzer fuer nachfolgende Seiten.
|
// Speichert den aktiven Benutzer für nachfolgende Seiten.
|
||||||
function setCurrentUser(user) {
|
function setCurrentUser(user) {
|
||||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erstellt einen Demo-Benutzer, falls fuer die E-Mail noch kein Account existiert.
|
// Erstellt einen Demo-Benutzer, falls für die E-Mail noch kein Account existiert.
|
||||||
function createFallbackUser(email, passwort) {
|
function createFallbackUser(email, passwort) {
|
||||||
const localPart = email.split('@')[0] || 'Gast';
|
const localPart = email.split('@')[0] || 'Gast';
|
||||||
const normalized = localPart.replace(/[._-]/g, ' ').trim();
|
const normalized = localPart.replace(/[._-]/g, ' ').trim();
|
||||||
@ -86,7 +86,7 @@ function validateForm(event) {
|
|||||||
passwortGroup.classList.remove('has-error');
|
passwortGroup.classList.remove('has-error');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn alle Validierungen bestanden, pruefen wir:
|
// Wenn alle Validierungen bestanden, prüfen wir:
|
||||||
// 1) gibt es den Benutzer schon?
|
// 1) gibt es den Benutzer schon?
|
||||||
// 2) ist das Passwort korrekt?
|
// 2) ist das Passwort korrekt?
|
||||||
// Danach speichern wir die aktive Session.
|
// Danach speichern wir die aktive Session.
|
||||||
@ -103,7 +103,7 @@ function validateForm(event) {
|
|||||||
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
|
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
|
||||||
setCurrentUser(userToLogin);
|
setCurrentUser(userToLogin);
|
||||||
|
|
||||||
// Snackbar anzeigen und dann zur Event-Uebersicht weiterleiten.
|
// Snackbar anzeigen und dann zur Event-Übersicht weiterleiten.
|
||||||
var snackbar = document.getElementById('snackbar');
|
var snackbar = document.getElementById('snackbar');
|
||||||
if (snackbar) {
|
if (snackbar) {
|
||||||
snackbar.classList.add('snackbar--visible');
|
snackbar.classList.add('snackbar--visible');
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||||
const USERS_STORAGE_KEY = 'socialCookingUsers';
|
const USERS_STORAGE_KEY = 'socialCookingUsers';
|
||||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||||
|
|
||||||
// Zentrale DOM-Referenzen fuer klare, testbare Funktionen.
|
// Zentrale DOM-Referenzen für klare, testbare Funktionen.
|
||||||
const loggedOutState = document.getElementById('logged-out-state');
|
const loggedOutState = document.getElementById('logged-out-state');
|
||||||
const loggedInContent = document.getElementById('logged-in-content');
|
const loggedInContent = document.getElementById('logged-in-content');
|
||||||
const profileHeadline = document.getElementById('profile-headline');
|
const profileHeadline = document.getElementById('profile-headline');
|
||||||
@ -109,7 +109,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
profileSubline.textContent = 'Bitte logge dich ein, um deinen Bereich zu sehen.';
|
profileSubline.textContent = 'Bitte logge dich ein, um deinen Bereich zu sehen.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fuellt Ueberschriften und Formular mit den aktuellen Benutzerdaten.
|
// Füllt Überschriften und Formular mit den aktuellen Benutzerdaten.
|
||||||
function renderLoggedInState(user) {
|
function renderLoggedInState(user) {
|
||||||
loggedOutState.classList.add('hidden');
|
loggedOutState.classList.add('hidden');
|
||||||
loggedInContent.classList.remove('hidden');
|
loggedInContent.classList.remove('hidden');
|
||||||
@ -154,7 +154,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Globale Funktionen fuer das Logout-Modal.
|
// Globale Funktionen für das Logout-Modal.
|
||||||
window.closeLogoutModal = function() {
|
window.closeLogoutModal = function() {
|
||||||
const logoutModal = document.getElementById('logoutModal');
|
const logoutModal = document.getElementById('logoutModal');
|
||||||
logoutModal.classList.remove('show');
|
logoutModal.classList.remove('show');
|
||||||
@ -305,7 +305,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
setStoredEvents(nextStoredEvents);
|
setStoredEvents(nextStoredEvents);
|
||||||
|
|
||||||
// Event-ID fuer alle Benutzer aus den Anmeldungen entfernen.
|
// Event-ID für alle Benutzer aus den Anmeldungen entfernen.
|
||||||
const registrationMap = getRegistrationMap();
|
const registrationMap = getRegistrationMap();
|
||||||
Object.keys(registrationMap).forEach(email => {
|
Object.keys(registrationMap).forEach(email => {
|
||||||
const ids = Array.isArray(registrationMap[email])
|
const ids = Array.isArray(registrationMap[email])
|
||||||
@ -366,12 +366,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speichert Profilaenderungen lokal und synchronisiert auch den Benutzerkatalog.
|
// Speichert Profiländerungen lokal und synchronisiert auch den Benutzerkatalog.
|
||||||
function handleProfileSubmit(event) {
|
function handleProfileSubmit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (!validateProfileForm()) {
|
if (!validateProfileForm()) {
|
||||||
profileFeedback.textContent = 'Bitte pruefe die markierten Felder.';
|
profileFeedback.textContent = 'Bitte prüfe die markierten Felder.';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(nextUser));
|
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(nextUser));
|
||||||
syncUserInUserStore(previousEmail, nextUser);
|
syncUserInUserStore(previousEmail, nextUser);
|
||||||
|
|
||||||
// Falls sich die E-Mail geaendert hat, verschieben wir bestehende Anmeldungen auf die neue E-Mail.
|
// Falls sich die E-Mail geändert hat, verschieben wir bestehende Anmeldungen auf die neue E-Mail.
|
||||||
migrateRegistrationEmail(previousEmail, nextUser.email);
|
migrateRegistrationEmail(previousEmail, nextUser.email);
|
||||||
|
|
||||||
passwortInput.value = '';
|
passwortInput.value = '';
|
||||||
@ -450,7 +450,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ermittelt angemeldete Events ueber die Registration-Map.
|
// Ermittelt angemeldete Events über die Registration-Map.
|
||||||
function getMyRegisteredEvents(events, user) {
|
function getMyRegisteredEvents(events, user) {
|
||||||
const registrationMap = getRegistrationMap();
|
const registrationMap = getRegistrationMap();
|
||||||
const registeredIds = Array.isArray(registrationMap[user.email]) ? registrationMap[user.email] : [];
|
const registeredIds = Array.isArray(registrationMap[user.email]) ? registrationMap[user.email] : [];
|
||||||
@ -459,7 +459,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return events.filter(event => idSet.has(Number(event.id)));
|
return events.filter(event => idSet.has(Number(event.id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rendert gehostete Events inkl. Zaehler.
|
// Rendert gehostete Events inkl. Zähler.
|
||||||
function renderMyEvents(events, user) {
|
function renderMyEvents(events, user) {
|
||||||
const hostedEvents = getMyHostedEvents(events, user);
|
const hostedEvents = getMyHostedEvents(events, user);
|
||||||
myEventsCount.textContent = String(hostedEvents.length);
|
myEventsCount.textContent = String(hostedEvents.length);
|
||||||
@ -471,7 +471,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}, 'hosting');
|
}, 'hosting');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rendert angemeldete Events inkl. Zaehler.
|
// Rendert angemeldete Events inkl. Zähler.
|
||||||
function renderMyRegistrations(events, user) {
|
function renderMyRegistrations(events, user) {
|
||||||
const registeredEvents = getMyRegisteredEvents(events, user);
|
const registeredEvents = getMyRegisteredEvents(events, user);
|
||||||
myRegistrationsCount.textContent = String(registeredEvents.length);
|
myRegistrationsCount.textContent = String(registeredEvents.length);
|
||||||
@ -483,7 +483,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}, 'registrations');
|
}, 'registrations');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baut die Eventkarten fuer beide Listen in einheitlichem Markup.
|
// Baut die Eventkarten für beide Listen in einheitlichem Markup.
|
||||||
function renderEventCards(container, events, emptyStateConfig, mode) {
|
function renderEventCards(container, events, emptyStateConfig, mode) {
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
|
|
||||||
@ -538,7 +538,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gibt true zurueck, wenn ein Event innerhalb der naechsten 12 Stunden startet.
|
// Gibt true zurück, wenn ein Event innerhalb der nächsten 12 Stunden startet.
|
||||||
function isAddressVisibleWindow(event) {
|
function isAddressVisibleWindow(event) {
|
||||||
const eventDateTime = parseEventDateTime(event);
|
const eventDateTime = parseEventDateTime(event);
|
||||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||||
@ -551,7 +551,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return msUntilStart >= 0 && msUntilStart <= twelveHoursInMs;
|
return msUntilStart >= 0 && msUntilStart <= twelveHoursInMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse fuer ISO- und lokalisierte Datumsformate aus den Eventdaten.
|
// Parse für ISO- und lokalisierte Datumsformate aus den Eventdaten.
|
||||||
function parseEventDateTime(event) {
|
function parseEventDateTime(event) {
|
||||||
if (!event?.date) {
|
if (!event?.date) {
|
||||||
return null;
|
return null;
|
||||||
@ -605,7 +605,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatiert ein Eventdatum konsistent fuer die Profilkarten.
|
// Formatiert ein Eventdatum konsistent für die Profilkarten.
|
||||||
function formatEventDate(dateString) {
|
function formatEventDate(dateString) {
|
||||||
if (!dateString) {
|
if (!dateString) {
|
||||||
return 'Kein Datum';
|
return 'Kein Datum';
|
||||||
@ -620,7 +620,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return dateString;
|
return dateString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vereinheitlicht die Zeitanzeige fuer die Profilseite.
|
// Vereinheitlicht die Zeitanzeige für die Profilseite.
|
||||||
function formatEventTime(timeString) {
|
function formatEventTime(timeString) {
|
||||||
if (!timeString) {
|
if (!timeString) {
|
||||||
return 'Keine Uhrzeit';
|
return 'Keine Uhrzeit';
|
||||||
@ -629,7 +629,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return timeString.includes('UHR') ? timeString.replace('UHR', 'Uhr').trim() : timeString;
|
return timeString.includes('UHR') ? timeString.replace('UHR', 'Uhr').trim() : timeString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalisiert Vergleichswerte fuer robuste String-Matches.
|
// Normalisiert Vergleichswerte für robuste String-Matches.
|
||||||
function normalizeText(value) {
|
function normalizeText(value) {
|
||||||
return String(value || '').trim().toLowerCase();
|
return String(value || '').trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// =============================================
|
// =============================================
|
||||||
// Dynamische Navigation
|
// Dynamische Navigation
|
||||||
// Je nach Login-Status wird die Kopfzeile fuer
|
// Je nach Login-Status wird die Kopfzeile für
|
||||||
// alle Seiten mit passendem Markup aufgebaut.
|
// alle Seiten mit passendem Markup aufgebaut.
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const navContainers = document.querySelectorAll('.nav-tab-links');
|
const navContainers = document.querySelectorAll('.nav-tab-links');
|
||||||
const currentPage = (window.location.pathname.split('/').pop() || 'index.html').toLowerCase();
|
const currentPage = (window.location.pathname.split('/').pop() || 'index.html').toLowerCase();
|
||||||
|
|
||||||
// Beendet frueh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
// Beendet früh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
||||||
if (!navContainers.length) {
|
if (!navContainers.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baut die Navigation fuer ausgeloggte Besucher.
|
// Baut die Navigation für ausgeloggte Besucher.
|
||||||
function buildLoggedOutNavigation() {
|
function buildLoggedOutNavigation() {
|
||||||
const loginIsActive = currentPage === 'login.html';
|
const loginIsActive = currentPage === 'login.html';
|
||||||
const signupIsActive = currentPage === 'signup.html';
|
const signupIsActive = currentPage === 'signup.html';
|
||||||
@ -64,7 +64,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baut die Navigation fuer eingeloggte Benutzer.
|
// Baut die Navigation für eingeloggte Benutzer.
|
||||||
function buildLoggedInNavigation(user) {
|
function buildLoggedInNavigation(user) {
|
||||||
const initial = (user.vorname || 'U').charAt(0).toUpperCase();
|
const initial = (user.vorname || 'U').charAt(0).toUpperCase();
|
||||||
const isEventOverview = currentPage === 'event_overview.html';
|
const isEventOverview = currentPage === 'event_overview.html';
|
||||||
|
|||||||
10
js/signup.js
10
js/signup.js
@ -1,4 +1,4 @@
|
|||||||
// =============================================
|
// =============================================
|
||||||
// Signup-Logik
|
// Signup-Logik
|
||||||
// Diese Datei validiert das Formular, speichert
|
// Diese Datei validiert das Formular, speichert
|
||||||
// neue Benutzer lokal und startet direkt die Session.
|
// neue Benutzer lokal und startet direkt die Session.
|
||||||
@ -31,7 +31,7 @@ function setStoredUsers(users) {
|
|||||||
localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(users));
|
localStorage.setItem(USERS_STORAGE_KEY, JSON.stringify(users));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Speichert den aktiven Benutzer fuer nachfolgende Seiten.
|
// Speichert den aktiven Benutzer für nachfolgende Seiten.
|
||||||
function setCurrentUser(user) {
|
function setCurrentUser(user) {
|
||||||
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(user));
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ function closeWelcomeModal() {
|
|||||||
window.location.href = 'event_overview.html';
|
window.location.href = 'event_overview.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hauptfunktion fuer Formularvalidierung und Speicherung.
|
// Hauptfunktion für Formularvalidierung und Speicherung.
|
||||||
function validateForm(event) {
|
function validateForm(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@ -110,8 +110,8 @@ function validateForm(event) {
|
|||||||
passwortGroup.classList.remove('has-error');
|
passwortGroup.classList.remove('has-error');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn alles gueltig ist:
|
// Wenn alles gültig ist:
|
||||||
// 1) auf doppelte E-Mail pruefen
|
// 1) auf doppelte E-Mail prüfen
|
||||||
// 2) neuen Benutzer speichern
|
// 2) neuen Benutzer speichern
|
||||||
// 3) als aktuellen Benutzer einloggen
|
// 3) als aktuellen Benutzer einloggen
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user