feat: Update CSS styles and enhance JavaScript functionality for event visibility and navigation
Added Comments for easier understanding of code
This commit is contained in:
parent
c3bea2817c
commit
d04a7e07de
@ -39,7 +39,7 @@ html {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
font-family: var(--font-main);
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
line-height: 1.5;
|
||||
@ -183,6 +183,7 @@ fieldset {
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-family: "Bagel Fat One", cursive;
|
||||
font-size: clamp(2rem, 4vw, 4rem);
|
||||
line-height: 1.03;
|
||||
letter-spacing: -0.03em;
|
||||
|
||||
@ -20,15 +20,15 @@
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
:root {
|
||||
--black: #000000;
|
||||
--black: #22211A;
|
||||
--white: #ffffff;
|
||||
--button-green: #6b6b05;
|
||||
--button-green-dark: #514c04;
|
||||
--button-green: var(--olive);
|
||||
--button-green-dark: var(--olive-dark);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: var(--font-main);
|
||||
background: #FFFDE3; /* butter background color from stylesheet */
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ body {
|
||||
.how-step__png--brown {
|
||||
filter: brightness(0) saturate(100%) invert(39%) sepia(84%) saturate(1682%) hue-rotate(349deg) brightness(93%) contrast(86%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.how-it-works__steps {
|
||||
@ -378,7 +378,7 @@ body {
|
||||
}
|
||||
|
||||
/* Center arrow removed – using side arrows only */
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.gallery__track {
|
||||
@ -405,12 +405,19 @@ body {
|
||||
justify-content: center;
|
||||
border-radius: 999px;
|
||||
font-size: 0.95rem;
|
||||
transition: background-color 0.2s ease, transform 0.2s ease;
|
||||
transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
.btn:hover,
|
||||
.btn:focus-visible {
|
||||
background-color: var(--button-green-dark);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(107, 107, 5, 0.28);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 6px rgba(107, 107, 5, 0.25);
|
||||
}
|
||||
|
||||
.nav__link {
|
||||
@ -512,7 +519,7 @@ body {
|
||||
}
|
||||
|
||||
.gallery__brand {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: var(--font-main);
|
||||
color: #DD541A;
|
||||
}
|
||||
|
||||
|
||||
@ -117,6 +117,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return msUntilStart <= twelveHoursInMs;
|
||||
}
|
||||
|
||||
// Adresse ist nur im 12h-Fenster VOR Eventstart sichtbar.
|
||||
function isAddressVisibleWindow(event) {
|
||||
const eventDateTime = parseEventDateTime(event);
|
||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const msUntilStart = eventDateTime.getTime() - Date.now();
|
||||
const twelveHoursInMs = 12 * 60 * 60 * 1000;
|
||||
|
||||
return msUntilStart >= 0 && msUntilStart <= twelveHoursInMs;
|
||||
}
|
||||
|
||||
function countRegistrationsForEvent(registrationMap, eventId) {
|
||||
return Object.values(registrationMap).reduce((count, ids) => {
|
||||
const hasEvent = Array.isArray(ids)
|
||||
@ -286,7 +299,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
: isRegistrationClosed
|
||||
? ' detail-primary-btn-danger'
|
||||
: ' detail-primary-btn-register';
|
||||
const shouldRevealAddress = Boolean(event.address) && isRegistrationClosed && hasAddressAccess;
|
||||
const shouldRevealAddress = Boolean(event.address) && isAddressVisibleWindow(event) && hasAddressAccess;
|
||||
const addressPanelMarkup = shouldRevealAddress
|
||||
? `
|
||||
<article class="detail-panel detail-panel-compact">
|
||||
|
||||
@ -1,30 +1,45 @@
|
||||
// =============================================
|
||||
// Galerie-Karussell (Startseite)
|
||||
// Diese Datei steuert die Foto-Galerie mit Pfeilen.
|
||||
// =============================================
|
||||
|
||||
// Wichtige Elemente aus dem HTML holen.
|
||||
const carouselTrack = document.querySelector('.gallery__track');
|
||||
const prevArrow = document.querySelector('.gallery__arrow--prev');
|
||||
const nextArrow = document.querySelector('.gallery__arrow--next');
|
||||
|
||||
// Nur ausfuehren, wenn die Galerie auf der Seite vorhanden ist.
|
||||
if (carouselTrack) {
|
||||
// Alle einzelnen Karten/Bilder im Track sammeln.
|
||||
const items = Array.from(carouselTrack.querySelectorAll('.gallery__item'));
|
||||
|
||||
// Auf Mobile zeigen wir 1 Bild, auf Desktop 3 Bilder pro "Seite".
|
||||
const getItemsPerPage = () => (window.matchMedia('(max-width: 900px)').matches ? 1 : 3);
|
||||
let itemsPerPage = getItemsPerPage();
|
||||
const pageCount = Math.ceil(items.length / itemsPerPage);
|
||||
let activePage = 0;
|
||||
|
||||
// Scrollt den Track auf eine bestimmte Seite.
|
||||
function scrollToPage(page) {
|
||||
activePage = page;
|
||||
const pageWidth = carouselTrack.clientWidth;
|
||||
carouselTrack.scrollTo({ left: pageWidth * page, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
// Geht zur naechsten Seite (mit Wrap-around am Ende).
|
||||
function showNext() {
|
||||
activePage = (activePage + 1) % pageCount;
|
||||
scrollToPage(activePage);
|
||||
}
|
||||
|
||||
// Geht zur vorherigen Seite (mit Wrap-around zum Ende).
|
||||
function showPrev() {
|
||||
activePage = (activePage - 1 + pageCount) % pageCount;
|
||||
scrollToPage(activePage);
|
||||
}
|
||||
|
||||
// Wenn sich bei Resize die Karten-Anzahl pro Seite aendert,
|
||||
// laden wir die Seite neu, damit Layout und Seitenzahl wieder stimmen.
|
||||
function refreshCarousel() {
|
||||
const responsiveItemsPerPage = getItemsPerPage();
|
||||
if (responsiveItemsPerPage !== itemsPerPage) {
|
||||
@ -33,9 +48,11 @@ if (carouselTrack) {
|
||||
}
|
||||
}
|
||||
|
||||
// Klick-Steuerung der Pfeile.
|
||||
if (nextArrow) nextArrow.addEventListener('click', showNext);
|
||||
if (prevArrow) prevArrow.addEventListener('click', showPrev);
|
||||
|
||||
// Tastatur-Support fuer Barrierefreiheit.
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'ArrowRight') {
|
||||
showNext();
|
||||
@ -45,6 +62,7 @@ if (carouselTrack) {
|
||||
}
|
||||
});
|
||||
|
||||
// Reagiert auf Bildschirmgroessen-Aenderungen.
|
||||
window.addEventListener('resize', () => {
|
||||
refreshCarousel();
|
||||
scrollToPage(activePage);
|
||||
|
||||
@ -1,8 +1,18 @@
|
||||
// =============================================
|
||||
// Mini-Galerie auf der Landingpage
|
||||
// Diese Datei hebt immer ein Bild hervor und
|
||||
// erlaubt Navigation mit Pfeilen/Tastatur.
|
||||
// =============================================
|
||||
|
||||
// Elemente aus dem DOM lesen.
|
||||
const prevBtn = document.querySelector('.arrow--prev');
|
||||
const nextBtn = document.querySelector('.arrow--next');
|
||||
const items = Array.from(document.querySelectorAll('.gallery__item'));
|
||||
let activeIndex = 0;
|
||||
|
||||
// Aktualisiert die Darstellung aller Bilder:
|
||||
// - aktives Bild ist klar sichtbar
|
||||
// - inaktive Bilder sind abgeblendet
|
||||
function updateGallery() {
|
||||
items.forEach((item, i) => {
|
||||
item.style.opacity = i === activeIndex ? '1' : '0.35';
|
||||
@ -10,20 +20,25 @@ function updateGallery() {
|
||||
});
|
||||
}
|
||||
|
||||
// Ein Schritt nach rechts.
|
||||
function showNext() {
|
||||
if (!items.length) return;
|
||||
activeIndex = (activeIndex + 1) % items.length;
|
||||
updateGallery();
|
||||
}
|
||||
|
||||
// Ein Schritt nach links.
|
||||
function showPrev() {
|
||||
if (!items.length) return;
|
||||
activeIndex = (activeIndex - 1 + items.length) % items.length;
|
||||
updateGallery();
|
||||
}
|
||||
|
||||
nextBtn.addEventListener('click', showNext);
|
||||
prevBtn.addEventListener('click', showPrev);
|
||||
// Event-Handler nur registrieren, wenn die Buttons existieren.
|
||||
if (nextBtn) nextBtn.addEventListener('click', showNext);
|
||||
if (prevBtn) prevBtn.addEventListener('click', showPrev);
|
||||
|
||||
// keyboard support
|
||||
// Tastatursteuerung fuer bessere Bedienbarkeit.
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'ArrowRight') {
|
||||
showNext();
|
||||
@ -33,4 +48,5 @@ document.addEventListener('keydown', (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Initialen Zustand einmal setzen.
|
||||
updateGallery();
|
||||
14
js/login.js
14
js/login.js
@ -1,3 +1,10 @@
|
||||
// =============================================
|
||||
// Login-Logik
|
||||
// Diese Datei validiert die Eingaben, sucht den
|
||||
// Benutzer im localStorage und legt die Session an.
|
||||
// =============================================
|
||||
|
||||
// Formular und Felder aus dem HTML holen.
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
const emailInput = document.getElementById('email');
|
||||
const passwortInput = document.getElementById('passwort');
|
||||
@ -79,7 +86,10 @@ function validateForm(event) {
|
||||
passwortGroup.classList.remove('has-error');
|
||||
}
|
||||
|
||||
// Wenn alle Validierungen bestanden, Benutzer pruefen und Session speichern.
|
||||
// Wenn alle Validierungen bestanden, pruefen wir:
|
||||
// 1) gibt es den Benutzer schon?
|
||||
// 2) ist das Passwort korrekt?
|
||||
// Danach speichern wir die aktive Session.
|
||||
if (isValid) {
|
||||
const users = getStoredUsers();
|
||||
const matchedUser = users.find(user => user.email?.toLowerCase() === emailValue.toLowerCase());
|
||||
@ -93,7 +103,7 @@ function validateForm(event) {
|
||||
const userToLogin = matchedUser || createFallbackUser(emailValue, passwortValue);
|
||||
setCurrentUser(userToLogin);
|
||||
|
||||
// Weiterleitung zur Event-Overview-Seite.
|
||||
// Nach erfolgreichem Login geht es zur Event-Uebersicht.
|
||||
window.location.href = 'event_overview.html';
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const card = document.createElement('article');
|
||||
card.className = 'profile-event-card profile-event-card-clickable';
|
||||
card.setAttribute('data-event-id', String(event.id));
|
||||
const addressMarkup = mode === 'registrations' && event.address
|
||||
const addressMarkup = mode === 'registrations' && event.address && isAddressVisibleWindow(event)
|
||||
? `
|
||||
<div class="profile-event-address-block" aria-label="Event Adresse">
|
||||
<p class="profile-event-address-label">Adresse</p>
|
||||
@ -486,6 +486,73 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Gibt true zurueck, wenn ein Event innerhalb der naechsten 12 Stunden startet.
|
||||
function isAddressVisibleWindow(event) {
|
||||
const eventDateTime = parseEventDateTime(event);
|
||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const msUntilStart = eventDateTime.getTime() - Date.now();
|
||||
const twelveHoursInMs = 12 * 60 * 60 * 1000;
|
||||
|
||||
return msUntilStart >= 0 && msUntilStart <= twelveHoursInMs;
|
||||
}
|
||||
|
||||
// Parse fuer ISO- und lokalisierte Datumsformate aus den Eventdaten.
|
||||
function parseEventDateTime(event) {
|
||||
if (!event?.date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dateValue = String(event.date).trim();
|
||||
const isoDateMatch = dateValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
let year;
|
||||
let month;
|
||||
let day;
|
||||
|
||||
if (isoDateMatch) {
|
||||
year = Number(isoDateMatch[1]);
|
||||
month = Number(isoDateMatch[2]);
|
||||
day = Number(isoDateMatch[3]);
|
||||
} else {
|
||||
const monthMap = {
|
||||
JAN: 1,
|
||||
FEB: 2,
|
||||
'MÄR': 3,
|
||||
MRZ: 3,
|
||||
APR: 4,
|
||||
MAI: 5,
|
||||
JUN: 6,
|
||||
JUL: 7,
|
||||
AUG: 8,
|
||||
SEP: 9,
|
||||
OKT: 10,
|
||||
NOV: 11,
|
||||
DEZ: 12
|
||||
};
|
||||
const localizedMatch = dateValue.match(/^(\d{1,2})\.\s*([A-ZÄÖÜ]{3})\.\s*(\d{4})$/);
|
||||
|
||||
if (!localizedMatch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
day = Number(localizedMatch[1]);
|
||||
month = monthMap[localizedMatch[2]];
|
||||
year = Number(localizedMatch[3]);
|
||||
|
||||
if (!month) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const timeMatch = String(event.time || '').match(/(\d{1,2}):(\d{2})/);
|
||||
const hours = timeMatch ? Number(timeMatch[1]) : 0;
|
||||
const minutes = timeMatch ? Number(timeMatch[2]) : 0;
|
||||
|
||||
return new Date(year, month - 1, day, hours, minutes, 0, 0);
|
||||
}
|
||||
|
||||
// Formatiert ein Eventdatum konsistent fuer die Profilkarten.
|
||||
function formatEventDate(dateString) {
|
||||
if (!dateString) {
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
// =============================================
|
||||
// Dynamische Navigation
|
||||
// Je nach Login-Status wird die Kopfzeile fuer
|
||||
// alle Seiten mit passendem Markup aufgebaut.
|
||||
// =============================================
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const navContainers = document.querySelectorAll('.nav-tab-links');
|
||||
|
||||
16
js/signup.js
16
js/signup.js
@ -1,3 +1,10 @@
|
||||
// =============================================
|
||||
// Signup-Logik
|
||||
// Diese Datei validiert das Formular, speichert
|
||||
// neue Benutzer lokal und startet direkt die Session.
|
||||
// =============================================
|
||||
|
||||
// Formular und Felder aus dem HTML holen.
|
||||
const signupForm = document.getElementById('signupForm');
|
||||
const vornameInput = document.getElementById('vorname');
|
||||
const nachnameInput = document.getElementById('nachname');
|
||||
@ -41,7 +48,7 @@ function closeWelcomeModal() {
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
// Validierungsfunktion
|
||||
// Hauptfunktion fuer Formularvalidierung und Speicherung.
|
||||
function validateForm(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@ -102,7 +109,10 @@ function validateForm(event) {
|
||||
passwortGroup.classList.remove('has-error');
|
||||
}
|
||||
|
||||
// Wenn alle Validierungen bestanden, Benutzer speichern und Session setzen.
|
||||
// Wenn alles gueltig ist:
|
||||
// 1) auf doppelte E-Mail pruefen
|
||||
// 2) neuen Benutzer speichern
|
||||
// 3) als aktuellen Benutzer einloggen
|
||||
if (isValid) {
|
||||
const existingUsers = getStoredUsers();
|
||||
const emailLower = emailValue.toLowerCase();
|
||||
@ -128,7 +138,7 @@ function validateForm(event) {
|
||||
setCurrentUser(newUser);
|
||||
|
||||
openWelcomeModal();
|
||||
// Hier würde spaeter die Registrierung zum Backend gesendet.
|
||||
// Hier koennte spaeter ein echter API-Call zum Backend stehen.
|
||||
|
||||
// Weiterleitung zur Event-Overview-Seite.
|
||||
window.location.href = 'event_overview.html';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user