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:
parent
21d96597cc
commit
7ecc2cf91a
@ -21,6 +21,17 @@
|
|||||||
line-height: 1.15;
|
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 {
|
.detail-title {
|
||||||
margin-bottom: var(--space-4);
|
margin-bottom: var(--space-4);
|
||||||
}
|
}
|
||||||
@ -122,6 +133,7 @@
|
|||||||
|
|
||||||
.meta-filter select {
|
.meta-filter select {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
-webkit-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-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;
|
background-repeat: no-repeat;
|
||||||
@ -752,6 +764,13 @@
|
|||||||
font-size: 34px;
|
font-size: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overview-info-button {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
flex-basis: 44px;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.top-nav-links {
|
.top-nav-links {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
@ -878,6 +897,19 @@
|
|||||||
font-size: 30px;
|
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 {
|
.top-nav-links {
|
||||||
width: auto;
|
width: auto;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@ -682,23 +682,82 @@ label {
|
|||||||
animation: modalSlideIn 0.3s ease;
|
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 {
|
@keyframes modalSlideIn {
|
||||||
from { transform: translateY(-50px); opacity: 0; }
|
from { transform: translateY(-50px); opacity: 0; }
|
||||||
to { transform: translateY(0); opacity: 1; }
|
to { transform: translateY(0); opacity: 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header h2 {
|
.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 {
|
.close-btn {
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
background: none;
|
background: none;
|
||||||
@ -712,7 +771,9 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-body {
|
.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 {
|
.modal-footer {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"title": "Italienische Tavolata",
|
"title": "Italienische Tavolata",
|
||||||
"location": "Luzern",
|
"location": "Luzern",
|
||||||
"address": "Pilatusstrasse 18, 6003 Luzern",
|
"address": "Pilatusstrasse 18, 6003 Luzern",
|
||||||
"date": "22. APR. 2026",
|
"date": "23. APR. 2026",
|
||||||
"time": "15:30 UHR",
|
"time": "15:30 UHR",
|
||||||
"category": "Dinner",
|
"category": "Dinner",
|
||||||
"diet": "Vegetarisch",
|
"diet": "Vegetarisch",
|
||||||
|
|||||||
@ -30,7 +30,10 @@
|
|||||||
<main class="container layout-wide">
|
<main class="container layout-wide">
|
||||||
<!-- Page headline -->
|
<!-- Page headline -->
|
||||||
<p class="badge margin-bottom-40">Event finden</p>
|
<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 -->
|
<!-- Filter section: category chips + location/date filters -->
|
||||||
<section class="filter-section">
|
<section class="filter-section">
|
||||||
|
|||||||
@ -68,8 +68,9 @@
|
|||||||
|
|
||||||
const firstName = String(user.vorname || '').trim();
|
const firstName = String(user.vorname || '').trim();
|
||||||
const lastName = String(user.nachname || '').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) {
|
function getResolvedParticipants(event, registrationMap) {
|
||||||
@ -102,6 +103,24 @@
|
|||||||
return baseParticipants;
|
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) {
|
function setRegistrationMap(registrationMap) {
|
||||||
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
|
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
|
||||||
}
|
}
|
||||||
@ -337,6 +356,10 @@
|
|||||||
: [];
|
: [];
|
||||||
const registrationMap = getRegistrationMap();
|
const registrationMap = getRegistrationMap();
|
||||||
const participants = getResolvedParticipants(event, registrationMap);
|
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)
|
const galleryImages = Array.isArray(event.gallery)
|
||||||
? event.gallery.filter(Boolean)
|
? event.gallery.filter(Boolean)
|
||||||
: [];
|
: [];
|
||||||
@ -351,14 +374,13 @@
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: '';
|
: '';
|
||||||
const visibleParticipants = participants.slice(0, 6);
|
const visibleParticipants = participantNamesForView.slice(0, 6);
|
||||||
const remainingParticipants = Math.max(0, participants.length - visibleParticipants.length);
|
const remainingParticipants = Math.max(0, participantNamesForView.length - visibleParticipants.length);
|
||||||
const totalGuests = Number.isFinite(event.spots) ? event.spots : 0;
|
const totalGuests = Number.isFinite(event.spots) ? event.spots : 0;
|
||||||
const confirmedGuests = participants.length;
|
const confirmedGuests = participants.length;
|
||||||
const freePlaces = Math.max(0, totalGuests - confirmedGuests);
|
const freePlaces = Math.max(0, totalGuests - confirmedGuests);
|
||||||
const isFull = freePlaces === 0;
|
const isFull = freePlaces === 0;
|
||||||
const isRegistrationClosed = isRegistrationClosedForEvent(event);
|
const isRegistrationClosed = isRegistrationClosedForEvent(event);
|
||||||
const isOwnEvent = isEventOwnedByCurrentUser(event, currentUser);
|
|
||||||
const deregInfo = getDeregistrationInfo(event);
|
const deregInfo = getDeregistrationInfo(event);
|
||||||
const userRegistrations = currentUser?.email && Array.isArray(registrationMap[currentUser.email])
|
const userRegistrations = currentUser?.email && Array.isArray(registrationMap[currentUser.email])
|
||||||
? registrationMap[currentUser.email].map(id => Number(id))
|
? registrationMap[currentUser.email].map(id => Number(id))
|
||||||
@ -456,7 +478,7 @@
|
|||||||
${remainingParticipants > 0 ? `<span class="participant-more">+${remainingParticipants}</span>` : ''}
|
${remainingParticipants > 0 ? `<span class="participant-more">+${remainingParticipants}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-participants-full hidden" data-participants-full>
|
<div class="detail-participants-full hidden" data-participants-full>
|
||||||
${participants.map(name => `
|
${participantNamesForView.map(name => `
|
||||||
<div class="detail-participant-item">
|
<div class="detail-participant-item">
|
||||||
<span class="participant-name">${name}</span>
|
<span class="participant-name">${name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -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.
|
// Prüft, ob ein Event dem aktuellen Benutzer gehört.
|
||||||
function isEventOwnedByCurrentUser(event, user) {
|
function isEventOwnedByCurrentUser(event, user) {
|
||||||
if (!event || !user) {
|
if (!event || !user) {
|
||||||
@ -91,8 +96,9 @@
|
|||||||
|
|
||||||
const firstName = String(user.vorname || '').trim();
|
const firstName = String(user.vorname || '').trim();
|
||||||
const lastName = String(user.nachname || '').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) {
|
function getResolvedParticipants(event, registrationMap) {
|
||||||
@ -640,10 +646,11 @@
|
|||||||
|
|
||||||
// Auto-open info modal on first login
|
// Auto-open info modal on first login
|
||||||
if (currentUser && infoModal) {
|
if (currentUser && infoModal) {
|
||||||
const hasShownInfoModal = localStorage.getItem(INFO_MODAL_SHOWN_KEY);
|
const userInfoModalKey = getInfoModalShownKeyForUser(currentUser);
|
||||||
|
const hasShownInfoModal = localStorage.getItem(userInfoModalKey);
|
||||||
if (!hasShownInfoModal) {
|
if (!hasShownInfoModal) {
|
||||||
infoModal.classList.add('show');
|
infoModal.classList.add('show');
|
||||||
localStorage.setItem(INFO_MODAL_SHOWN_KEY, 'true');
|
localStorage.setItem(userInfoModalKey, 'true');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -515,13 +515,20 @@
|
|||||||
const card = document.createElement('article');
|
const card = document.createElement('article');
|
||||||
card.className = 'profile-event-card profile-event-card-clickable';
|
card.className = 'profile-event-card profile-event-card-clickable';
|
||||||
card.setAttribute('data-event-id', String(event.id));
|
card.setAttribute('data-event-id', String(event.id));
|
||||||
const addressMarkup = mode === 'registrations' && event.address && isAddressVisibleWindow(event)
|
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>
|
<div class="profile-event-address-block" aria-label="Event Adresse">
|
||||||
<p class="profile-event-address">${event.address}</p>
|
<p class="profile-event-address-label">Adresse</p>
|
||||||
</div>
|
<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'
|
const actionMarkup = mode === 'registrations'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user