feat: lightbox gallery, event create UX improvements, cancel modal, footer consistency, Swiss German fixes
This commit is contained in:
parent
4b54c48311
commit
e805abbf12
@ -187,6 +187,7 @@ h2 {
|
|||||||
font-size: clamp(2rem, 4vw, 4rem);
|
font-size: clamp(2rem, 4vw, 4rem);
|
||||||
line-height: 1.03;
|
line-height: 1.03;
|
||||||
letter-spacing: -0.03em;
|
letter-spacing: -0.03em;
|
||||||
|
color: var(--brown);
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-text {
|
.step-text {
|
||||||
@ -204,7 +205,6 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.intro-card {
|
.intro-card {
|
||||||
max-width: 24rem;
|
|
||||||
padding: var(--space-6);
|
padding: var(--space-6);
|
||||||
border-radius: 1.75rem;
|
border-radius: 1.75rem;
|
||||||
background: linear-gradient(135deg, var(--color-surface), var(--color-surface-soft));
|
background: linear-gradient(135deg, var(--color-surface), var(--color-surface-soft));
|
||||||
@ -221,7 +221,7 @@ h2 {
|
|||||||
|
|
||||||
.intro-image {
|
.intro-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 10;
|
height: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 1.875rem;
|
border-radius: 1.875rem;
|
||||||
@ -457,57 +457,36 @@ textarea:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress-wrap {
|
.progress-wrap {
|
||||||
position: relative;
|
|
||||||
width: min(100%, var(--content-width));
|
width: min(100%, var(--content-width));
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-top: 4.35rem;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-muted);
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
width: 100%;
|
flex: 1;
|
||||||
height: 0.375rem;
|
height: 0.3rem;
|
||||||
background: var(--color-progress-bg);
|
background: var(--color-progress-bg);
|
||||||
|
border-radius: 999px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
display: block;
|
display: block;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--tomato);
|
background: var(--olive);
|
||||||
transition: width 0.25s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-marker {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
display: grid;
|
|
||||||
justify-items: center;
|
|
||||||
gap: 0.2rem;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-marker::after {
|
|
||||||
content: "";
|
|
||||||
width: 0.125rem;
|
|
||||||
height: 1rem;
|
|
||||||
background: var(--tomato);
|
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
}
|
transition: width 0.25s ease;
|
||||||
|
|
||||||
.progress-marker__circle {
|
|
||||||
width: 2.9rem;
|
|
||||||
height: 2.9rem;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--tomato);
|
|
||||||
color: var(--butter-light);
|
|
||||||
font-size: 1.35rem;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1;
|
|
||||||
box-shadow: 0 10px 24px rgba(212, 75, 36, 0.18);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-actions {
|
.flow-actions {
|
||||||
@ -550,8 +529,15 @@ textarea:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button--text {
|
.button--text {
|
||||||
border: 0;
|
border: 2px solid var(--olive);
|
||||||
padding-left: 0;
|
color: var(--olive);
|
||||||
|
background: transparent;
|
||||||
|
padding-left: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button--text:hover {
|
||||||
|
background: var(--olive-light);
|
||||||
|
color: var(--black);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--primary {
|
.button--primary {
|
||||||
@ -625,7 +611,7 @@ textarea:focus-visible {
|
|||||||
.step-layout--intro {
|
.step-layout--intro {
|
||||||
width: min(100%, 56rem);
|
width: min(100%, 56rem);
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
gap: var(--space-8);
|
gap: var(--space-8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -492,6 +492,7 @@
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,6 +669,40 @@
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detail-participants-full {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-participant-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.participant-name {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-participants-link {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--olive);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-participants-link:hover {
|
||||||
|
color: var(--olive-dark);
|
||||||
|
}
|
||||||
|
|
||||||
.detail-action-bar {
|
.detail-action-bar {
|
||||||
/* Sticky bottom CTA bar with summary and booking controls. */
|
/* Sticky bottom CTA bar with summary and booking controls. */
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -733,8 +768,8 @@
|
|||||||
.detail-spots-pill {
|
.detail-spots-pill {
|
||||||
border: 2px solid var(--olive-light);
|
border: 2px solid var(--olive-light);
|
||||||
border-radius: var(--radius-pill);
|
border-radius: var(--radius-pill);
|
||||||
opacity: 0.5;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
letter-spacing: var(--ls-ui);
|
letter-spacing: var(--ls-ui);
|
||||||
padding: 7px 14px;
|
padding: 7px 14px;
|
||||||
color: var(--olive);
|
color: var(--olive);
|
||||||
|
|||||||
@ -247,6 +247,7 @@
|
|||||||
background: var(--white);
|
background: var(--white);
|
||||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.06);
|
||||||
aspect-ratio: 2 / 3;
|
aspect-ratio: 2 / 3;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gallery__item img {
|
.gallery__item img {
|
||||||
|
|||||||
@ -435,6 +435,56 @@ p {
|
|||||||
background: var(--tomato);
|
background: var(--tomato);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lightbox */
|
||||||
|
.lightbox {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 200;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox.is-open {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox__backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox__content {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
max-width: min(96vw, 1100px);
|
||||||
|
max-height: 90vh;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox__image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 90vh;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox__close {
|
||||||
|
position: absolute;
|
||||||
|
top: -42px;
|
||||||
|
right: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--white);
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
.footer {
|
.footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
"hostMessage": [
|
"hostMessage": [
|
||||||
"¡Hola a todos! Ich lade euch ein auf eine kulinarische Reise nach Peru.",
|
"¡Hola a todos! Ich lade euch ein auf eine kulinarische Reise nach Peru.",
|
||||||
"Ich koche für euch ein authentisches peruanisches Sharing-Menü, das vor Lebensfreude nur so sprüht. Freut euch auf eine Explosion aus leuchtenden Farben, fein abgestimmter Schärfe und der unverwechselbaren Frische verschiedenster Kräuter.",
|
"Ich koche für euch ein authentisches peruanisches Sharing-Menü, das vor Lebensfreude nur so sprüht. Freut euch auf eine Explosion aus leuchtenden Farben, fein abgestimmter Schärfe und der unverwechselbaren Frische verschiedenster Kräuter.",
|
||||||
"Wir genießen den Abend gemeinsam in mehreren kleinen Gängen, ganz nach dem Sharing-Prinzip. Dabei entdecken wir die klassischen Aromen meiner Heimatstadt Lima – von traditionell bis modern interpretiert.",
|
"Wir geniessen den Abend gemeinsam in mehreren kleinen Gängen, ganz nach dem Sharing-Prinzip. Dabei entdecken wir die klassischen Aromen meiner Heimatstadt Lima – von traditionell bis modern interpretiert.",
|
||||||
"Es wird gesellig, aromatisch und ein echtes Erlebnis für alle Sinne. ¡Buen provecho!"
|
"Es wird gesellig, aromatisch und ein echtes Erlebnis für alle Sinne. ¡Buen provecho!"
|
||||||
],
|
],
|
||||||
"menu": [
|
"menu": [
|
||||||
|
|||||||
@ -41,8 +41,8 @@
|
|||||||
<p class="step-kicker">Event erstellen</p>
|
<p class="step-kicker">Event erstellen</p>
|
||||||
<h1 id="intro-title">Hey <span id="username">{{username}}</span>, was hast du vor?</h1>
|
<h1 id="intro-title">Hey <span id="username">{{username}}</span>, was hast du vor?</h1>
|
||||||
<p class="step-text">
|
<p class="step-text">
|
||||||
Erzähl uns von deiner Idee – vom Essen bis zur Stimmung. Ob Dinner, Brunch
|
Erzähl uns von deiner Idee, vom Essen bis zur Stimmung. Ob Dinner, Brunch
|
||||||
oder etwas ganz Eigenes – wir helfen dir dabei, dein Event in sieben Schritten aufzubauen.
|
oder etwas ganz Eigenes wir helfen dir dabei, dein Event in sieben Schritten aufzubauen.
|
||||||
</p>
|
</p>
|
||||||
<button type="button" class="button button--primary button--intro" data-start-flow>
|
<button type="button" class="button button--primary button--intro" data-start-flow>
|
||||||
Los geht’s!
|
Los geht’s!
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<h2 id="step1-title">Was hast du vor?</h2>
|
<h2 id="step1-title">Was hast du vor?</h2>
|
||||||
<p class="step-text">
|
<p class="step-text">
|
||||||
Erzähl uns, was für ein Event du planst. Ist es ein gemütlicher Brunch,
|
Erzähl uns, was für ein Event du planst. Ist es ein gemütlicher Brunch,
|
||||||
ein Dinner mit Wow-Effekt oder einfach ein entspannter Abend mit gutem Essen?
|
ein Dinner mit Wow-Effekt oder einfach ein entspanntes Mittagessen mit gutem Essen?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -277,12 +277,12 @@
|
|||||||
|
|
||||||
<div class="step-fields">
|
<div class="step-fields">
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label for="eventTitle">Wie soll dein Event heißen?</label>
|
<label for="eventTitle">Wie soll dein Event heissen?</label>
|
||||||
<input type="text" id="eventTitle" name="eventTitle" required />
|
<input type="text" id="eventTitle" name="eventTitle" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label for="eventDescription">Beschreibung des Event-Abends</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>
|
</div>
|
||||||
@ -363,9 +363,7 @@
|
|||||||
|
|
||||||
<div class="flow-footer" id="flowFooter" hidden>
|
<div class="flow-footer" id="flowFooter" hidden>
|
||||||
<div class="progress-wrap" aria-hidden="true">
|
<div class="progress-wrap" aria-hidden="true">
|
||||||
<div class="progress-marker" id="progressMarker">
|
<span class="progress-label" id="progressMarkerLabel">Schritt 1 von 7</span>
|
||||||
<span class="progress-marker__circle" id="progressMarkerLabel">1</span>
|
|
||||||
</div>
|
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<span id="progressBar" class="progress-bar"></span>
|
<span id="progressBar" class="progress-bar"></span>
|
||||||
</div>
|
</div>
|
||||||
@ -400,7 +398,7 @@
|
|||||||
|
|
||||||
<div class="review-card review-card--success">
|
<div class="review-card review-card--success">
|
||||||
<div class="submission-success-actions">
|
<div class="submission-success-actions">
|
||||||
<a class="button button--primary" href="event_overview.html">Weiter zu deinem Profil</a>
|
<a class="button button--primary" href="my_profil.html">Weiter zu deinem Profil</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -35,6 +35,11 @@
|
|||||||
|
|
||||||
<!-- Page logic: fetch by URL id, compose detail UI, handle gallery lightbox -->
|
<!-- Page logic: fetch by URL id, compose detail UI, handle gallery lightbox -->
|
||||||
<script src="js/event_detail.js"></script>
|
<script src="js/event_detail.js"></script>
|
||||||
|
|
||||||
|
<!-- Snackbar: Feedback bei An-/Abmeldung -->
|
||||||
|
<div class="snackbar" id="snackbar"></div>
|
||||||
|
|
||||||
|
<!-- Instagram Einladung -->
|
||||||
<div class="instagram-invite">
|
<div class="instagram-invite">
|
||||||
<a href="https://www.instagram.com" target="_blank" rel="noopener noreferrer" class="instagram-invite__link">
|
<a href="https://www.instagram.com" target="_blank" rel="noopener noreferrer" class="instagram-invite__link">
|
||||||
<img src="assets/Icon_instagram.png" alt="Instagram" class="instagram-invite__icon" />
|
<img src="assets/Icon_instagram.png" alt="Instagram" class="instagram-invite__icon" />
|
||||||
|
|||||||
@ -148,6 +148,15 @@
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<!-- Lightbox: Bildansicht vergrössert -->
|
||||||
|
<div class="lightbox" id="gallery-lightbox" aria-hidden="true">
|
||||||
|
<div class="lightbox__backdrop" data-close-lightbox></div>
|
||||||
|
<figure class="lightbox__content" role="dialog" aria-modal="true" aria-label="Bildansicht">
|
||||||
|
<button class="lightbox__close" type="button" aria-label="Schliessen">×</button>
|
||||||
|
<img class="lightbox__image" src="" alt="Grossansicht">
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="js/index-carousel.js"></script>
|
<script src="js/index-carousel.js"></script>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<a href="impressum.html" class="footer__link">Impressum</a>
|
<a href="impressum.html" class="footer__link">Impressum</a>
|
||||||
|
|||||||
@ -8,7 +8,6 @@ const steps = Array.from(document.querySelectorAll(".step"));
|
|||||||
const backButton = document.getElementById("backButton");
|
const backButton = document.getElementById("backButton");
|
||||||
const nextButton = document.getElementById("nextButton");
|
const nextButton = document.getElementById("nextButton");
|
||||||
const progressBar = document.getElementById("progressBar");
|
const progressBar = document.getElementById("progressBar");
|
||||||
const progressMarker = document.getElementById("progressMarker");
|
|
||||||
const progressMarkerLabel = document.getElementById("progressMarkerLabel");
|
const progressMarkerLabel = document.getElementById("progressMarkerLabel");
|
||||||
const errorMessage = document.getElementById("errorMessage");
|
const errorMessage = document.getElementById("errorMessage");
|
||||||
const usernameElement = document.getElementById("username");
|
const usernameElement = document.getElementById("username");
|
||||||
@ -121,7 +120,7 @@ function markRadioGroupInvalid(group) {
|
|||||||
* Zeigt den gewünschten Schritt an.
|
* Zeigt den gewünschten Schritt an.
|
||||||
* Dabei werden auch Buttons, Progress Bar und Review aktualisiert.
|
* Dabei werden auch Buttons, Progress Bar und Review aktualisiert.
|
||||||
*/
|
*/
|
||||||
function showStep(index) {
|
function showStep(index, pushHistory = true) {
|
||||||
currentStep = index;
|
currentStep = index;
|
||||||
submissionSuccess.hidden = true;
|
submissionSuccess.hidden = true;
|
||||||
clearStepInvalidState(index);
|
clearStepInvalidState(index);
|
||||||
@ -136,6 +135,11 @@ function showStep(index) {
|
|||||||
updateProgressBar(index, lastStep);
|
updateProgressBar(index, lastStep);
|
||||||
setErrorMessage("");
|
setErrorMessage("");
|
||||||
|
|
||||||
|
// Browser-History aktualisieren, damit Zurück-Taste funktioniert
|
||||||
|
if (pushHistory) {
|
||||||
|
history.pushState({ step: index }, "");
|
||||||
|
}
|
||||||
|
|
||||||
// Für bessere UX: bei jedem Schritt wieder nach oben scrollen
|
// Für bessere UX: bei jedem Schritt wieder nach oben scrollen
|
||||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
}
|
}
|
||||||
@ -168,22 +172,17 @@ function updateFlowVisibility(stepIndex) {
|
|||||||
* - letzter Schritt = 100%
|
* - letzter Schritt = 100%
|
||||||
*/
|
*/
|
||||||
function updateProgressBar(stepIndex, totalStepIndex) {
|
function updateProgressBar(stepIndex, totalStepIndex) {
|
||||||
|
const totalFormSteps = totalStepIndex;
|
||||||
let progress = 0;
|
let progress = 0;
|
||||||
let markerPosition = 0;
|
|
||||||
let markerStep = 1;
|
let markerStep = 1;
|
||||||
let markerTransform = "translateX(-50%)";
|
|
||||||
|
|
||||||
if (stepIndex > 0) {
|
if (stepIndex > 0) {
|
||||||
progress = ((stepIndex - 1) / (totalStepIndex - 1)) * 100;
|
progress = ((stepIndex) / totalFormSteps) * 100;
|
||||||
markerPosition = ((stepIndex - 1) / (totalStepIndex - 1)) * 100;
|
|
||||||
markerStep = stepIndex;
|
markerStep = stepIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar.style.width = `${progress}%`;
|
progressBar.style.width = `${progress}%`;
|
||||||
progressMarker.style.left = `${markerPosition}%`;
|
progressMarkerLabel.textContent = `Schritt ${markerStep} von ${totalFormSteps}`;
|
||||||
progressMarker.style.transform = markerTransform;
|
|
||||||
progressMarker.hidden = stepIndex === 0;
|
|
||||||
progressMarkerLabel.textContent = String(markerStep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -767,9 +766,21 @@ function initEventCreationFlow() {
|
|||||||
registerValidationFeedbackHandlers();
|
registerValidationFeedbackHandlers();
|
||||||
registerReviewEditHandlers();
|
registerReviewEditHandlers();
|
||||||
|
|
||||||
|
// Browser-Zurück-Taste: vorherigen Schritt wiederherstellen
|
||||||
|
window.addEventListener("popstate", (e) => {
|
||||||
|
if (e.state && typeof e.state.step === "number") {
|
||||||
|
showStep(e.state.step, false);
|
||||||
|
} else {
|
||||||
|
showStep(0, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Startzustand: Intro anzeigen
|
// Startzustand: Intro anzeigen
|
||||||
submissionSuccess.hidden = true;
|
submissionSuccess.hidden = true;
|
||||||
showStep(0);
|
showStep(0);
|
||||||
|
|
||||||
|
// Initialen History-Eintrag ersetzen, damit Step 0 im Verlauf ist
|
||||||
|
history.replaceState({ step: 0 }, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Startpunkt des Skripts
|
// Startpunkt des Skripts
|
||||||
|
|||||||
@ -6,7 +6,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// DOM entry point and shared asset path.
|
// DOM entry point and shared asset path.
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
const detailContainer = document.getElementById('detail-view');
|
const detailContainer = document.getElementById('detail-view');
|
||||||
const locationIconPath = 'assets/location-pin.svg';
|
const locationIconPath = 'assets/icon_location-pin.svg';
|
||||||
const currentUser = getCurrentUser();
|
const currentUser = getCurrentUser();
|
||||||
|
|
||||||
// Read event id from query string (detail page deep-link support).
|
// Read event id from query string (detail page deep-link support).
|
||||||
@ -358,12 +358,20 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
<article class="detail-panel detail-panel-compact">
|
<article class="detail-panel detail-panel-compact">
|
||||||
<div class="detail-participants-head">
|
<div class="detail-participants-head">
|
||||||
<h2 class="detail-section-title">Teilnehmer</h2>
|
<h2 class="detail-section-title">Teilnehmer</h2>
|
||||||
<a href="#" class="detail-participants-link">Alle ansehen</a>
|
<button type="button" class="detail-participants-link" data-show-all-participants>Alle ansehen</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-avatar-row">
|
<div class="detail-avatar-row" data-participants-row>
|
||||||
${visibleParticipants.map(name => `<span class="participant-avatar">${name.charAt(0).toUpperCase()}</span>`).join('')}
|
${visibleParticipants.map(name => `<span class="participant-avatar">${name.charAt(0).toUpperCase()}</span>`).join('')}
|
||||||
${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>
|
||||||
|
${participants.map(name => `
|
||||||
|
<div class="detail-participant-item">
|
||||||
|
<span class="participant-avatar">${name.charAt(0).toUpperCase()}</span>
|
||||||
|
<span class="participant-name">${name}</span>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
${addressPanelMarkup}
|
${addressPanelMarkup}
|
||||||
@ -392,7 +400,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
<div class="detail-action-buttons">
|
<div class="detail-action-buttons">
|
||||||
<span class="detail-spots-pill${isFull ? ' detail-spots-pill-full' : ''}">
|
<span class="detail-spots-pill${isFull ? ' detail-spots-pill-full' : ''}">
|
||||||
${isFull ? 'AUSGEBUCHT' : `${freePlaces} Plaetze frei`}
|
${isFull ? 'AUSGEBUCHT' : `${freePlaces} Plätze frei`}
|
||||||
</span>
|
</span>
|
||||||
<button class="detail-primary-btn${actionButtonVariantClass}" type="button" data-register-button ${actionButtonDisabled ? 'disabled' : ''}>
|
<button class="detail-primary-btn${actionButtonVariantClass}" type="button" data-register-button ${actionButtonDisabled ? 'disabled' : ''}>
|
||||||
${actionButtonLabel}
|
${actionButtonLabel}
|
||||||
@ -447,8 +455,27 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
if (registrationSet.has(Number(event.id))) {
|
if (registrationSet.has(Number(event.id))) {
|
||||||
registrationSet.delete(Number(event.id));
|
registrationSet.delete(Number(event.id));
|
||||||
|
|
||||||
|
// Snackbar: Feedback bei Abmeldung.
|
||||||
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
if (snackbar) {
|
||||||
|
snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
|
||||||
|
snackbar.classList.add('snackbar--danger', 'snackbar--visible');
|
||||||
|
setTimeout(() => {
|
||||||
|
snackbar.classList.remove('snackbar--visible');
|
||||||
|
setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
} else if (!isFull && !isRegistrationClosed) {
|
} else if (!isFull && !isRegistrationClosed) {
|
||||||
registrationSet.add(Number(event.id));
|
registrationSet.add(Number(event.id));
|
||||||
|
|
||||||
|
// Snackbar: Feedback bei Anmeldung.
|
||||||
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
if (snackbar) {
|
||||||
|
snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
|
||||||
|
snackbar.classList.add('snackbar--visible');
|
||||||
|
setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRegistrationMap[currentUser.email] = Array.from(registrationSet);
|
nextRegistrationMap[currentUser.email] = Array.from(registrationSet);
|
||||||
@ -459,6 +486,20 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Alle ansehen": Teilnehmerliste aufklappen / zuklappen.
|
||||||
|
const showAllBtn = detailContainer.querySelector('[data-show-all-participants]');
|
||||||
|
const avatarRow = detailContainer.querySelector('[data-participants-row]');
|
||||||
|
const fullList = detailContainer.querySelector('[data-participants-full]');
|
||||||
|
|
||||||
|
if (showAllBtn && avatarRow && fullList) {
|
||||||
|
showAllBtn.addEventListener('click', () => {
|
||||||
|
const isExpanded = !fullList.classList.contains('hidden');
|
||||||
|
fullList.classList.toggle('hidden');
|
||||||
|
avatarRow.classList.toggle('hidden');
|
||||||
|
showAllBtn.textContent = isExpanded ? 'Alle ansehen' : 'Weniger anzeigen';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Central close helper to keep all close paths consistent.
|
// Central close helper to keep all close paths consistent.
|
||||||
function closeLightbox() {
|
function closeLightbox() {
|
||||||
if (!lightbox) {
|
if (!lightbox) {
|
||||||
|
|||||||
@ -294,11 +294,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const filtered = allEvents.filter(event => {
|
const filtered = allEvents.filter(event => {
|
||||||
// Lokal erstellte Events werden nicht in der allgemeinen Event-Uebersicht angezeigt.
|
|
||||||
if (event.source === 'local') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const categoryMatch = activeCategory === 'ALLE' || event.category === activeCategory;
|
const categoryMatch = activeCategory === 'ALLE' || event.category === activeCategory;
|
||||||
const locationMatch = selectedLocation === 'ALLE_ORTE' || event.location === selectedLocation;
|
const locationMatch = selectedLocation === 'ALLE_ORTE' || event.location === selectedLocation;
|
||||||
const eventDateIso = parseEventDateToIso(event.date);
|
const eventDateIso = parseEventDateToIso(event.date);
|
||||||
|
|||||||
@ -97,4 +97,47 @@ if (carouselTrack) {
|
|||||||
buildDots();
|
buildDots();
|
||||||
updateTrack();
|
updateTrack();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// Lightbox: Bild vergroessern bei Klick
|
||||||
|
// =============================================
|
||||||
|
const lightbox = document.getElementById('gallery-lightbox');
|
||||||
|
const lightboxImage = lightbox ? lightbox.querySelector('.lightbox__image') : null;
|
||||||
|
|
||||||
|
function openLightbox(src, alt) {
|
||||||
|
if (!lightbox || !lightboxImage) return;
|
||||||
|
lightboxImage.src = src;
|
||||||
|
lightboxImage.alt = alt || 'Grossansicht';
|
||||||
|
lightbox.classList.add('is-open');
|
||||||
|
lightbox.setAttribute('aria-hidden', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLightbox() {
|
||||||
|
if (!lightbox) return;
|
||||||
|
lightbox.classList.remove('is-open');
|
||||||
|
lightbox.setAttribute('aria-hidden', 'true');
|
||||||
|
lightboxImage.src = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Klick auf Galerie-Bild oeffnet die Lightbox.
|
||||||
|
items.forEach(function(item) {
|
||||||
|
var img = item.querySelector('img');
|
||||||
|
if (img) {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
openLightbox(img.src, img.alt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lightbox schliessen: Backdrop, Close-Button oder ESC-Taste.
|
||||||
|
if (lightbox) {
|
||||||
|
lightbox.querySelector('.lightbox__close').addEventListener('click', closeLightbox);
|
||||||
|
lightbox.querySelector('[data-close-lightbox]').addEventListener('click', closeLightbox);
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Escape' && lightbox.classList.contains('is-open')) {
|
||||||
|
closeLightbox();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -177,7 +177,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (cancelButton && currentUser?.email) {
|
if (cancelButton && currentUser?.email) {
|
||||||
const eventId = Number(cancelButton.getAttribute('data-cancel-event-id'));
|
const eventId = Number(cancelButton.getAttribute('data-cancel-event-id'));
|
||||||
if (Number.isFinite(eventId)) {
|
if (Number.isFinite(eventId)) {
|
||||||
cancelHostedEvent(eventId, currentUser.email);
|
openCancelEventModal(eventId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -265,6 +265,34 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
|
|
||||||
// Sagt ein gehostetes Event ab (aus eigener Profilansicht entfernen).
|
// Sagt ein gehostetes Event ab (aus eigener Profilansicht entfernen).
|
||||||
|
let pendingCancelEventId = null;
|
||||||
|
|
||||||
|
function openCancelEventModal(eventId) {
|
||||||
|
pendingCancelEventId = eventId;
|
||||||
|
const modal = document.getElementById('cancelEventModal');
|
||||||
|
modal.classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
window.closeCancelEventModal = function() {
|
||||||
|
pendingCancelEventId = null;
|
||||||
|
const modal = document.getElementById('cancelEventModal');
|
||||||
|
modal.classList.remove('show');
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('confirmCancelEventBtn').addEventListener('click', function() {
|
||||||
|
if (pendingCancelEventId !== null && currentUser?.email) {
|
||||||
|
cancelHostedEvent(pendingCancelEventId, currentUser.email);
|
||||||
|
}
|
||||||
|
closeCancelEventModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schliesst das Modal bei Klick ausserhalb des Inhalts.
|
||||||
|
document.getElementById('cancelEventModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeCancelEventModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function cancelHostedEvent(eventId, userEmail) {
|
function cancelHostedEvent(eventId, userEmail) {
|
||||||
// Lokal erstellte, eigene Events werden direkt aus dem Storage geloescht.
|
// Lokal erstellte, eigene Events werden direkt aus dem Storage geloescht.
|
||||||
const storedEvents = getStoredEvents();
|
const storedEvents = getStoredEvents();
|
||||||
|
|||||||
@ -42,7 +42,7 @@ function openWelcomeModal() {
|
|||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funktion zum Schließen des Welcome Modals
|
// Funktion zum Schliessen des Welcome Modals
|
||||||
function closeWelcomeModal() {
|
function closeWelcomeModal() {
|
||||||
welcomeModal.classList.remove('show');
|
welcomeModal.classList.remove('show');
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.overflow = 'auto';
|
||||||
@ -172,7 +172,7 @@ passwortInput.addEventListener('input', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Modal schließen wenn außerhalb geklickt wird
|
// Modal schliessen wenn ausserhalb geklickt wird
|
||||||
welcomeModal.addEventListener('click', function(event) {
|
welcomeModal.addEventListener('click', function(event) {
|
||||||
if (event.target === welcomeModal) {
|
if (event.target === welcomeModal) {
|
||||||
closeWelcomeModal();
|
closeWelcomeModal();
|
||||||
|
|||||||
@ -123,6 +123,34 @@
|
|||||||
<!-- Snackbar: Feedback bei Abmeldung von Events -->
|
<!-- Snackbar: Feedback bei Abmeldung von Events -->
|
||||||
<div class="snackbar" id="snackbar"></div>
|
<div class="snackbar" id="snackbar"></div>
|
||||||
|
|
||||||
|
<!-- Event-Absage Confirmation Modal -->
|
||||||
|
<div id="cancelEventModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button class="close-btn" onclick="closeCancelEventModal()">×</button>
|
||||||
|
<h2>Event absagen?</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Bist du sicher, dass du dieses Event absagen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button button--outline" type="button" onclick="closeCancelEventModal()">Abbrechen</button>
|
||||||
|
<button class="button" type="button" id="confirmCancelEventBtn" style="background-color: var(--tomato); border-color: var(--tomato);">Event absagen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="instagram-invite">
|
||||||
|
<a href="https://www.instagram.com" target="_blank" rel="noopener noreferrer" class="instagram-invite__link">
|
||||||
|
<img src="assets/Icon_instagram.png" alt="Instagram" class="instagram-invite__icon" />
|
||||||
|
<img src="assets/logo_invite.svg" alt="Invité Logo" class="instagram-invite__logo" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<footer class="footer">
|
||||||
|
<a href="impressum.html" class="footer__link">Impressum</a>
|
||||||
|
<a href="datenschutz.html" class="footer__link">Datenschutz</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<script src="js/my_profil.js"></script>
|
<script src="js/my_profil.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- Schließt main-content -->
|
</div> <!-- Schliesst main-content -->
|
||||||
|
|
||||||
<!-- Welcome Modal -->
|
<!-- Welcome Modal -->
|
||||||
<div id="welcomeModal" class="modal">
|
<div id="welcomeModal" class="modal">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user