Enhance event overview layout and styling; update event date and improve participant name handling. Pop-Up that Events are free. Explenation for Event Adresse.

This commit is contained in:
viiivo 2026-04-22 10:19:13 +02:00
parent 21d96597cc
commit 7ecc2cf91a
7 changed files with 155 additions and 23 deletions

View File

@ -21,6 +21,17 @@
line-height: 1.15;
}
.overview-title-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-4);
}
.overview-title-row .overview-title {
margin-bottom: var(--space-4);
}
.detail-title {
margin-bottom: var(--space-4);
}
@ -122,6 +133,7 @@
.meta-filter select {
cursor: pointer;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='currentColor' stroke-width='1.5' fill='none' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
background-repeat: no-repeat;
@ -752,6 +764,13 @@
font-size: 34px;
}
.overview-info-button {
width: 44px;
height: 44px;
flex-basis: 44px;
font-size: 1.5rem;
}
.top-nav-links {
gap: 8px;
}
@ -878,6 +897,19 @@
font-size: 30px;
}
.overview-title-row {
align-items: flex-start;
gap: 12px;
}
.overview-info-button {
width: 40px;
height: 40px;
flex-basis: 40px;
font-size: 1.35rem;
margin-top: 2px;
}
.top-nav-links {
width: auto;
justify-content: flex-end;

View File

@ -682,23 +682,82 @@ label {
animation: modalSlideIn 0.3s ease;
}
.btn-info {
width: 48px;
height: 48px;
flex: 0 0 48px;
border: 1.5px solid var(--olive);
border-radius: 999px;
background: var(--butter-light);
color: var(--olive);
font-family: "Bagel Fat One", cursive;
font-size: 1.7rem;
line-height: 1;
cursor: pointer;
box-shadow: var(--shadow-interaction);
transition: background-color 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}
.btn-info:hover,
.btn-info:focus-visible {
background: var(--butter);
border-color: var(--olive-dark);
transform: translateY(-1px);
}
.btn-info:focus-visible {
outline: 2px solid var(--olive-dark);
}
@keyframes modalSlideIn {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
position: relative;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-4);
}
.modal-header h2 {
padding: var(--space-20)var(--space-20) 0 var(--space-20);
margin: 0;
padding: 0;
text-align: left;
flex: 1;
}
.modal-close {
width: 32px;
height: 32px;
flex: 0 0 32px;
margin-left: auto;
border: none;
background: transparent;
color: var(--olive);
font-size: 2rem;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: color 0.2s ease, transform 0.2s ease;
}
.modal-close:hover,
.modal-close:focus-visible {
color: var(--olive-dark);
transform: translateY(-1px);
}
.modal-close:focus-visible {
outline: 2px solid var(--olive-dark);
outline-offset: 2px;
}
.close-btn {
position: absolute;
right: 0;
top: 0;
font-size: 28px;
color: var(--black);
background: none;
@ -712,7 +771,9 @@ label {
}
.modal-body {
padding: var(--space-20) var(--space-20) var(--space-4) var(--space-20);
padding: var(--space-4) 0 0;
text-align: left;
line-height: 1.7;
}
.modal-footer {

View File

@ -4,7 +4,7 @@
"title": "Italienische Tavolata",
"location": "Luzern",
"address": "Pilatusstrasse 18, 6003 Luzern",
"date": "22. APR. 2026",
"date": "23. APR. 2026",
"time": "15:30 UHR",
"category": "Dinner",
"diet": "Vegetarisch",

View File

@ -30,7 +30,10 @@
<main class="container layout-wide">
<!-- Page headline -->
<p class="badge margin-bottom-40">Event finden</p>
<h1>Was darf es sein?</h1>
<div class="overview-title-row">
<h1 class="overview-title">Was darf es sein?</h1>
<button type="button" id="info-button" class="btn-info" aria-label="Informationen zu kostenlosen Events">?</button>
</div>
<!-- Filter section: category chips + location/date filters -->
<section class="filter-section">

View File

@ -68,8 +68,9 @@
const firstName = String(user.vorname || '').trim();
const lastName = String(user.nachname || '').trim();
const fullName = `${firstName} ${lastName}`.trim();
return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim();
return (fullName || firstName || String(user.email || '').trim()).trim();
}
function getResolvedParticipants(event, registrationMap) {
@ -102,6 +103,24 @@
return baseParticipants;
}
function getParticipantNameForViewer(name, canSeeLastName) {
const rawName = String(name || '').trim();
if (!rawName) {
return '';
}
if (canSeeLastName) {
return rawName;
}
// Bei E-Mail-Fallback nur den lokalen Teil anzeigen.
if (rawName.includes('@')) {
return rawName.split('@')[0].trim() || rawName;
}
return rawName.split(/\s+/)[0];
}
function setRegistrationMap(registrationMap) {
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
}
@ -337,6 +356,10 @@
: [];
const registrationMap = getRegistrationMap();
const participants = getResolvedParticipants(event, registrationMap);
const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser);
const participantNamesForView = participants
.map(name => getParticipantNameForViewer(name, isOwnEvent))
.filter(Boolean);
const galleryImages = Array.isArray(event.gallery)
? event.gallery.filter(Boolean)
: [];
@ -351,14 +374,13 @@
</div>
`
: '';
const visibleParticipants = participants.slice(0, 6);
const remainingParticipants = Math.max(0, participants.length - visibleParticipants.length);
const visibleParticipants = participantNamesForView.slice(0, 6);
const remainingParticipants = Math.max(0, participantNamesForView.length - visibleParticipants.length);
const totalGuests = Number.isFinite(event.spots) ? event.spots : 0;
const confirmedGuests = participants.length;
const freePlaces = Math.max(0, totalGuests - confirmedGuests);
const isFull = freePlaces === 0;
const isRegistrationClosed = isRegistrationClosedForEvent(event);
const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser);
const deregInfo = getDeregistrationInfo(event);
const userRegistrations = currentUser?.email && Array.isArray(registrationMap[currentUser.email])
? registrationMap[currentUser.email].map(id => Number(id))
@ -456,7 +478,7 @@
${remainingParticipants > 0 ? `<span class="participant-more">+${remainingParticipants}</span>` : ''}
</div>
<div class="detail-participants-full hidden" data-participants-full>
${participants.map(name => `
${participantNamesForView.map(name => `
<div class="detail-participant-item">
<span class="participant-name">${name}</span>
</div>

View File

@ -36,6 +36,11 @@
}
}
function getInfoModalShownKeyForUser(user) {
const email = String(user?.email || '').trim().toLowerCase();
return email ? `${INFO_MODAL_SHOWN_KEY}:${email}` : INFO_MODAL_SHOWN_KEY;
}
// Prüft, ob ein Event dem aktuellen Benutzer gehört.
function isEventOwnedByCurrentUser(event, user) {
if (!event || !user) {
@ -91,8 +96,9 @@
const firstName = String(user.vorname || '').trim();
const lastName = String(user.nachname || '').trim();
const fullName = `${firstName} ${lastName}`.trim();
return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim();
return (fullName || firstName || String(user.email || '').trim()).trim();
}
function getResolvedParticipants(event, registrationMap) {
@ -640,10 +646,11 @@
// Auto-open info modal on first login
if (currentUser && infoModal) {
const hasShownInfoModal = localStorage.getItem(INFO_MODAL_SHOWN_KEY);
const userInfoModalKey = getInfoModalShownKeyForUser(currentUser);
const hasShownInfoModal = localStorage.getItem(userInfoModalKey);
if (!hasShownInfoModal) {
infoModal.classList.add('show');
localStorage.setItem(INFO_MODAL_SHOWN_KEY, 'true');
localStorage.setItem(userInfoModalKey, 'true');
}
}

View File

@ -515,13 +515,20 @@
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 && isAddressVisibleWindow(event)
? `
<div class="profile-event-address-block" aria-label="Event Adresse">
<p class="profile-event-address-label">Adresse</p>
<p class="profile-event-address">${event.address}</p>
</div>
`
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>
<p class="profile-event-address">${event.address}</p>
</div>
`
: `
<div class="profile-event-address-block" aria-label="Hinweis zur Adresse">
<p class="profile-event-address-label">Adresse</p>
<p class="profile-event-address">Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.</p>
</div>
`)
: '';
const actionMarkup = mode === 'registrations'