diff --git a/event-create.css b/event-create.css new file mode 100644 index 0000000..e118a3e --- /dev/null +++ b/event-create.css @@ -0,0 +1,504 @@ +:root { + --color-bg: #f7f7f2; + --color-surface: #ffffff; + --color-surface-soft: #f0eee7; + --color-text: #1f1f1f; + --color-text-secondary: #303030; + --color-muted: #6b6b6b; + --color-border: #d8d8d2; + --color-border-strong: #202020; + --color-primary: #222222; + --color-primary-hover: #111111; + --color-focus: #2f6fed; + --color-error: #b42318; + --color-progress-bg: #ddddda; + --color-divider: #ecece7; + + --shadow-soft: 0 10px 30px rgba(0, 0, 0, 0.06); + + --radius-sm: 0.875rem; + --radius-md: 1.25rem; + --radius-lg: 1.5rem; + --radius-pill: 999px; + + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --space-6: 2rem; + --space-7: 3rem; + --space-8: 4rem; + + --max-width: 1120px; + --content-width: 760px; + --header-height: 4.5rem; + + --control-min-height: 3rem; + --input-min-height: 3.5rem; + --card-min-height: 6rem; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + font-size: 100%; +} + +body { + margin: 0; + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: var(--color-bg); + color: var(--color-text); + line-height: 1.5; +} + +a, +button, +input, +textarea { + font: inherit; +} + +a { + color: inherit; + text-decoration: none; +} + +.site-header { + background: var(--color-bg); + border-top: 2px solid #232323; + border-bottom: 1px solid var(--color-border); +} + +.site-nav { + width: min(100% - 2rem, var(--max-width)); + margin: 0 auto; + min-height: var(--header-height); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-4); +} + +.site-logo { + font-size: 2rem; + font-weight: 800; + letter-spacing: 0.02em; +} + +.site-nav-links { + display: flex; + align-items: center; + gap: var(--space-5); + margin: 0; + padding: 0; + list-style: none; +} + +.site-nav-links a { + font-weight: 500; +} + +.site-nav-links li:last-child a { + width: 2.25rem; + height: 2.25rem; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: #231f20; + color: #ffffff; + font-weight: 700; +} + +.event-create-page { + width: min(100% - 2rem, var(--max-width)); + margin: 0 auto; + padding: var(--space-5) 0 0; +} + +.event-flow-header { + display: flex; + justify-content: flex-end; + margin-bottom: var(--space-4); +} + +.event-form { + min-height: calc(100vh - var(--header-height) - 9rem); + display: flex; + flex-direction: column; +} + +.step { + display: none; + padding: var(--space-4) 0 var(--space-7); +} + +.step--active { + display: block; +} + +.step-layout { + width: min(100%, var(--content-width)); + margin: 0 auto; + display: grid; + gap: var(--space-6); +} + +.step-layout--intro { + min-height: 60vh; + align-content: center; + grid-template-columns: 1fr; +} + +.step-copy, +.step-fields, +.form-field, +fieldset { + display: grid; + gap: var(--space-4); +} + +.step-copy { + gap: var(--space-4); +} + +.step-fields { + gap: var(--space-5); +} + +.form-field, +fieldset { + margin: 0; + padding: 0; + border: 0; + gap: var(--space-3); +} + +.step-kicker { + margin: 0; + font-weight: 700; + color: var(--color-muted); + letter-spacing: 0.02em; +} + +h1, +h2 { + margin: 0; + font-size: clamp(2rem, 4vw, 4rem); + line-height: 1.03; + letter-spacing: -0.03em; +} + +.step-text { + margin: 0; + max-width: 42rem; + color: var(--color-text-secondary); + font-size: clamp(1rem, 1.4vw, 1.2rem); +} + +.intro-card, +.review-card { + border: 1px solid var(--color-border); + background: var(--color-surface); + box-shadow: var(--shadow-soft); +} + +.intro-card { + max-width: 24rem; + padding: var(--space-6); + border-radius: 1.75rem; + background: linear-gradient(135deg, var(--color-surface), var(--color-surface-soft)); +} + +.intro-card-emoji { + font-size: 2rem; + margin-bottom: var(--space-3); +} + +label, +legend { + font-weight: 700; +} + +.field-hint { + margin: -0.25rem 0 0; + color: var(--color-muted); + font-size: 0.95rem; +} + +input[type="text"], +input[type="date"], +input[type="time"], +input[type="number"], +textarea { + width: 100%; + min-height: var(--input-min-height); + padding: 0.95rem 1rem; + border: 1px solid var(--color-border); + border-radius: 1rem; + background: var(--color-surface); + color: var(--color-text); +} + +textarea { + min-height: 9rem; + resize: vertical; +} + +.field-row { + display: grid; + gap: var(--space-4); +} + +.option-grid { + display: grid; + gap: var(--space-3); +} + +.option-card { + position: relative; + display: grid; + gap: 0.15rem; + min-height: var(--card-min-height); + padding: 1rem 1rem 1rem 1.05rem; + border: 1px solid var(--color-border); + border-radius: 1rem; + background: var(--color-surface); + transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease; +} + +.option-card small { + color: var(--color-muted); +} + +.option-card:hover { + transform: translateY(-1px); + box-shadow: var(--shadow-soft); +} + +.option-card input { + position: absolute; + inset: 0; + opacity: 0; + cursor: pointer; +} + +.option-card:has(input:checked) { + border: 2px solid var(--color-border-strong); +} + +.counter { + display: inline-flex; + align-items: center; + gap: var(--space-3); +} + +.counter input { + width: 6rem; + text-align: center; +} + +.counter-button, +.button { + min-height: var(--control-min-height); +} + +.counter-button { + width: var(--control-min-height); + height: var(--control-min-height); + border: 1px solid var(--color-border); + border-radius: 50%; + background: var(--color-surface); + font-size: 1.5rem; +} + +.review-card { + padding: var(--space-5); + border-radius: var(--radius-lg); +} + +.review-list { + display: grid; + gap: var(--space-4); + margin: 0; +} + +.review-item { + display: grid; + gap: var(--space-1); + padding-bottom: var(--space-4); + border-bottom: 1px solid var(--color-divider); +} + +.review-item:last-child { + border-bottom: 0; + padding-bottom: 0; +} + +.review-item dt { + font-weight: 700; +} + +.review-item dd { + margin: 0; + white-space: pre-wrap; + color: var(--color-text-secondary); +} + +.flow-footer { + position: sticky; + bottom: 0; + z-index: 5; + margin-top: auto; + background: rgba(247, 247, 242, 0.96); + backdrop-filter: blur(8px); + padding-bottom: env(safe-area-inset-bottom); +} + +.progress { + width: 100%; + height: 0.375rem; + background: var(--color-progress-bg); +} + +.progress-bar { + display: block; + width: 0; + height: 100%; + background: var(--color-primary); + transition: width 0.25s ease; +} + +.flow-actions { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-4); + padding: var(--space-4) 0; +} + +.flow-actions-right { + display: flex; + align-items: center; + gap: var(--space-4); +} + +.error-message { + min-height: 1.5rem; + margin: 0; + color: var(--color-error); + font-size: 0.95rem; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.9rem 1.35rem; + border-radius: var(--radius-pill); + border: 1px solid var(--color-border); + background: transparent; + color: var(--color-text); + cursor: pointer; +} + +.button--ghost:hover { + background: rgba(0, 0, 0, 0.03); +} + +.button--text { + border: 0; + padding-left: 0; +} + +.button--primary { + min-width: 10rem; + border-color: var(--color-primary); + background: var(--color-primary); + color: #ffffff; + font-weight: 700; +} + +.button--primary:hover { + background: var(--color-primary-hover); +} + +.button--primary:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.button--intro { + justify-self: start; + margin-top: var(--space-2); +} + +.site-footer { + width: min(100% - 2rem, var(--max-width)); + margin: 0 auto; + padding: var(--space-5) 0 var(--space-6); + color: var(--color-muted); + text-align: center; +} + +a:focus-visible, +button:focus-visible, +input:focus-visible, +textarea:focus-visible { + outline: 3px solid var(--color-focus); + outline-offset: 3px; +} + +@media (max-width: 767px) { + .site-nav { + flex-wrap: wrap; + padding: var(--space-3) 0; + } + + .site-nav-links { + gap: var(--space-3); + } + + .flow-actions, + .flow-actions-right { + flex-direction: column; + align-items: stretch; + } + + .button--text { + justify-content: flex-start; + } + + .button--primary { + width: 100%; + } + + .event-flow-header { + justify-content: flex-start; + } +} + +@media (min-width: 768px) { + .step-layout--intro { + grid-template-columns: 1.25fr 0.8fr; + align-items: center; + } + + .field-row { + grid-template-columns: 1fr 1fr; + } + + .option-grid--3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .option-grid--4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} \ No newline at end of file diff --git a/event-create.html b/event-create.html new file mode 100644 index 0000000..da5d6b0 --- /dev/null +++ b/event-create.html @@ -0,0 +1,352 @@ + + + + + + Event erstellen | Invité + + + + + + +
+
+ Abbrechen +
+ +
+
+
+
+

Event erstellen

+

Hey {{username}}, was hast du vor?

+

+ Erzähl uns von deiner Idee – vom Essen bis zur Stimmung. Ob Dinner, Brunch + oder etwas ganz Eigenes – wir helfen dir dabei, dein Event Schritt für Schritt aufzubauen. +

+ +
+ + +
+
+ +
+
+
+

Schritt 1

+

Was hast du vor?

+

+ 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? +

+
+ +
+
+ + +
+ +
+ Art des Essens / Eventtyp + +
+ + + + + + + +
+
+
+
+
+ +
+
+
+

Schritt 2

+

Was kommt auf den Tisch?

+

+ Mach uns neugierig. Was kochst du – und wie fühlt sich dein Abend an? + Hier entsteht die Geschichte, auf die sich deine Gäste freuen. +

+
+ +
+
+ + +
+ +
+ + +
+
+
+
+ +
+
+
+

Schritt 3

+

Wen lädst du ein?

+

+ Wie viele Gäste passen zu deinem Event? Und gibt es etwas, das du bei + Ernährung oder Unverträglichkeiten beachten möchtest? +

+
+ +
+
+ Maximale Personenanzahl + +
+ + + +
+
+ +
+ Ernährungsform + +
+ + + + + +
+
+ +
+ Allergene / Unverträglichkeiten +

Optional – nur auswählen, wenn es für dein Event relevant ist.

+ +
+ + + + + +
+ +
+ + +
+
+
+
+
+ +
+
+
+

Schritt 4

+

Wann findet dein Event statt?

+

+ Wähle Datum und Uhrzeit – und sag uns, wo dein Event stattfindet. + Keine Sorge: Die genaue Adresse sehen Gäste erst nach der Buchung. +

+
+ +
+
+
+ + +
+ +
+ + +
+
+ +
+ + +
+ +
+ + +
+
+
+
+ +
+
+
+

Schritt 5

+

Alles bereit für deine Gäste?

+

+ Schau dir dein Event nochmal in Ruhe an. Passt alles? + Dann kannst du es jetzt veröffentlichen und Gäste einladen. +

+
+ +
+
+
+
Eventtitel
+
+
+ +
+
Eventtyp
+
+
+ +
+
Menü
+
+
+ +
+
Event-Abend
+
+
+ +
+
Maximale Personenanzahl
+
+
+ +
+
Ernährungsform
+
+
+ +
+
Allergene / Unverträglichkeiten
+
Keine Angabe
+
+ +
+
Datum
+
+
+ +
+
Uhrzeit
+
+
+ +
+
Adresse
+
+
+ +
+
Ort
+
+
+
+
+
+
+ + +
+
+ + + + + + \ No newline at end of file diff --git a/event-create.js b/event-create.js new file mode 100644 index 0000000..5735a3f --- /dev/null +++ b/event-create.js @@ -0,0 +1,443 @@ +// ============================= +// SETUP: Wichtige HTML-Elemente holen +// Diese Konstanten verbinden unser JavaScript mit dem HTML. +// So können wir später Buttons, Formularfelder und Bereiche steuern. +// ============================= +const form = document.getElementById("eventForm"); +const steps = Array.from(document.querySelectorAll(".step")); +const backButton = document.getElementById("backButton"); +const nextButton = document.getElementById("nextButton"); +const progressBar = document.getElementById("progressBar"); +const errorMessage = document.getElementById("errorMessage"); +const usernameElement = document.getElementById("username"); +const flowFooter = document.getElementById("flowFooter"); + +// ============================= +// STATE: aktueller Schritt im Flow +// currentStep merkt sich, auf welchem Schritt der User gerade ist. +// lastStep ist der letzte Schritt im Formular. +// ============================= +let currentStep = 0; +const lastStep = steps.length - 1; + +// Text für den Weiter-Button je nach Schritt +const nextLabels = { + 0: "Weiter", + 1: "Weiter", + 2: "Weiter", + 3: "Weiter", + 4: "Weiter", + 5: "Event veröffentlichen" +}; + +// Demo-Wert: Später könnte der Name z. B. aus einem User-Profil kommen +usernameElement.textContent = "Mia"; + + +// ============================= +// STEP 1: Kleine Hilfsfunktionen +// Diese Funktionen helfen uns später an mehreren Stellen im Code. +// ============================= + +/** + * Gibt alle Eingabefelder eines bestimmten Schritts zurück. + * Rückgabe: Array mit input-, textarea- und select-Feldern. + */ +function getStepFields(stepIndex) { + return Array.from( + steps[stepIndex].querySelectorAll("input, textarea, select") + ); +} + +/** + * Zeigt eine Fehlermeldung im Formular an. + * Wenn keine Nachricht übergeben wird, wird die Meldung geleert. + */ +function setErrorMessage(message = "") { + errorMessage.textContent = message; +} + + +// ============================= +// STEP 2: Schritt anzeigen & Oberfläche aktualisieren +// showStep() ist eine der wichtigsten Funktionen: +// Sie bestimmt, welcher Schritt sichtbar ist, +// und aktualisiert gleichzeitig die restliche Oberfläche. +// ============================= + +/** + * Zeigt den gewünschten Schritt an. + * Dabei werden auch Buttons, Progress Bar und Review aktualisiert. + */ +function showStep(index) { + currentStep = index; + + // Nur der aktuelle Schritt soll sichtbar sein + steps.forEach((step, stepIndex) => { + step.classList.toggle("step--active", stepIndex === index); + }); + + updateFlowVisibility(index); + updateReviewIfNeeded(index); + updateProgressBar(index, lastStep); + setErrorMessage(""); + + // Für bessere UX: bei jedem Schritt wieder nach oben scrollen + window.scrollTo({ top: 0, behavior: "smooth" }); +} + +/** + * Steuert Sichtbarkeit von Footer und Buttons. + * Im Intro-Schritt werden Footer und Zurück-Button versteckt. + * Zusätzlich bekommt der Weiter-Button je nach Schritt ein anderes Label. + */ +function updateFlowVisibility(stepIndex) { + const isIntroStep = stepIndex === 0; + + flowFooter.hidden = isIntroStep; + backButton.hidden = isIntroStep; + nextButton.textContent = nextLabels[stepIndex]; +} + + +// ============================= +// STEP 3: Fortschrittsanzeige +// Die Progress Bar zeigt, wie weit der User im Flow ist. +// Das Intro zählt noch nicht als eigentlicher Formularschritt. +// ============================= + +/** + * Berechnet den Fortschritt in Prozent und setzt die Breite der Progress Bar. + * Beispiel: + * - Intro = 0% + * - erster echter Formularschritt = 0% + * - letzter Schritt = 100% + */ +function updateProgressBar(stepIndex, totalStepIndex) { + let progress = 0; + + if (stepIndex > 0) { + progress = ((stepIndex - 1) / (totalStepIndex - 1)) * 100; + } + + progressBar.style.width = `${progress}%`; +} + + +// ============================= +// STEP 4: Review-Daten vorbereiten +// Im letzten Schritt werden alle eingegebenen Daten nochmals angezeigt. +// Dafür brauchen wir Funktionen, die Feldwerte sauber auslesen und formatieren. +// ============================= + +/** + * Führt das Update der Review nur aus, + * wenn wirklich der letzte Schritt geöffnet ist. + */ +function updateReviewIfNeeded(stepIndex) { + if (stepIndex === lastStep) { + updateReview(); + } +} + +/** + * Gibt den Wert eines Formularfeldes zurück. + * Rückgabe: + * - eingegebener Text / ausgewählte Option + * - oder "–", falls nichts vorhanden ist + */ +function getFieldValue(name) { + const field = form.elements[name]; + + if (!field) return "–"; + + // Spezialfall: Radio-Gruppen verhalten sich anders als normale Inputs + if (field instanceof RadioNodeList) { + return field.value || "–"; + } + + return field.value.trim() || "–"; +} + +/** + * Gibt alle ausgewählten Checkbox-Werte als Text zurück. + * Beispiel: "Vegetarisch, Vegan" + * Falls nichts ausgewählt wurde: "Keine Angabe" + */ +function getCheckboxValues(name) { + const checked = Array.from( + form.querySelectorAll(`input[name="${name}"]:checked`) + ); + + return checked.length + ? checked.map(item => item.value).join(", ") + : "Keine Angabe"; +} + +/** + * Formatiert ein Datum für die Review-Anzeige. + * Beispiel: aus "2026-03-26" wird "26.03.2026" + */ +function formatDate(value) { + if (!value || value === "–") return "–"; + + const date = new Date(value); + if (Number.isNaN(date.getTime())) return value; + + return new Intl.DateTimeFormat("de-CH", { + day: "2-digit", + month: "2-digit", + year: "numeric" + }).format(date); +} + +/** + * Schreibt einen Wert in das passende Feld der Review-Ansicht. + * Gesucht wird ein HTML-Element mit data-review="..." + */ +function updateReviewField(fieldName, value) { + const target = document.querySelector(`[data-review="${fieldName}"]`); + + if (target) { + target.textContent = value; + } +} + +/** + * Baut den Text für Allergien / Hinweise zusammen. + * Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert. + */ +function buildAllergiesReviewValue() { + const selected = getCheckboxValues("allergies"); + const notes = getFieldValue("allergiesOther"); + + if (selected === "Keine Angabe" && notes === "–") return "Keine Angabe"; + + if (selected !== "Keine Angabe" && notes !== "–") { + return `${selected}, ${notes}`; + } + + return selected !== "Keine Angabe" ? selected : notes; +} + +/** + * Liest alle wichtigen Formularwerte aus + * und schreibt sie gesammelt in die Review-Ansicht. + */ +function updateReview() { + const reviewValues = { + eventTitle: getFieldValue("eventTitle"), + eventType: getFieldValue("eventType"), + menuDescription: getFieldValue("menuDescription"), + eventDescription: getFieldValue("eventDescription"), + maxGuests: getFieldValue("maxGuests"), + dietType: getFieldValue("dietType"), + allergies: buildAllergiesReviewValue(), + eventDate: formatDate(getFieldValue("eventDate")), + eventTime: getFieldValue("eventTime"), + eventAddress: getFieldValue("eventAddress"), + eventCity: getFieldValue("eventCity") + }; + + Object.entries(reviewValues).forEach(([key, value]) => { + updateReviewField(key, value); + }); +} + + +// ============================= +// STEP 5: Validierung +// Bevor der User weitergehen darf, prüfen wir: +// 1. Sind Pflichtfelder ausgefüllt? +// 2. Wurde bei Pflicht-Radios etwas ausgewählt? +// ============================= + +/** + * Prüft, ob der aktuelle Schritt gültig ist. + * Rückgabe: + * - true = alles okay + * - false = es gibt einen Fehler + */ +function validateCurrentStep() { + // Intro und Review müssen nicht validiert werden + if (currentStep === 0 || currentStep === lastStep) return true; + + const fields = getStepFields(currentStep); + + // Zuerst Radio-Gruppen prüfen + const radioCheck = validateRadioGroups(fields); + if (!radioCheck.isValid) { + setErrorMessage(radioCheck.message); + return false; + } + + // Danach normale Pflichtfelder prüfen + const requiredCheck = validateRequiredFields(fields); + if (!requiredCheck.isValid) { + setErrorMessage(requiredCheck.message); + return false; + } + + setErrorMessage(""); + return true; +} + +/** + * Prüft alle Radio-Gruppen eines Schritts. + * Rückgabe: + * - Objekt mit isValid: true/false + * - bei Fehler zusätzlich eine passende Meldung + */ +function validateRadioGroups(fields) { + const names = [...new Set(fields.filter(f => f.type === "radio").map(f => f.name))]; + + for (const name of names) { + const group = Array.from(form.querySelectorAll(`input[name="${name}"]`)); + const required = group.some(f => f.required); + const selected = group.some(f => f.checked); + + if (required && !selected) { + return { + isValid: false, + message: "Bitte wähle eine Option aus." + }; + } + } + + return { isValid: true }; +} + +/** + * Prüft alle Pflichtfelder ausser Radios und Checkboxen. + * Rückgabe: + * - Objekt mit isValid: true/false + * - bei Fehler zusätzlich eine passende Meldung + */ +function validateRequiredFields(fields) { + for (const field of fields) { + if (field.type === "radio" || field.type === "checkbox") continue; + + if (!field.checkValidity()) { + return { + isValid: false, + message: "Bitte fülle alle Pflichtfelder aus." + }; + } + } + + return { isValid: true }; +} + + +// ============================= +// STEP 6: Navigation mit Zurück / Weiter +// Diese Funktionen bestimmen, was beim Klicken auf die Buttons passiert. +// ============================= + +/** + * Einen Schritt zurückgehen. + * Wenn der User im ersten Formularschritt ist, geht es zurück zum Intro. + */ +function handleBackClick() { + if (currentStep > 1) { + showStep(currentStep - 1); + } else { + showStep(0); + } +} + +/** + * Einen Schritt weitergehen. + * Vorher wird geprüft, ob der aktuelle Schritt gültig ist. + * Im letzten Schritt wird stattdessen das Formular abgeschickt. + */ +function handleNextClick() { + if (!validateCurrentStep()) return; + + if (currentStep < lastStep) { + showStep(currentStep + 1); + } else { + form.requestSubmit(); + } +} + + +// ============================= +// STEP 7: Submit +// Aktuell ist das nur eine Demo. +// Später könnte hier ein API-Call oder Speichern in einer Datenbank passieren. +// ============================= + +/** + * Reagiert auf das Absenden des Formulars. + * preventDefault verhindert, dass die Seite neu lädt. + */ +function handleFormSubmit(event) { + event.preventDefault(); + alert("Event würde jetzt veröffentlicht werden."); +} + + +// ============================= +// STEP 8: Counter-Felder (+ / -) +// Für Zahlenfelder wie z. B. Anzahl Gäste. +// ============================= + +/** + * Sucht alle Counter-Komponenten + * und verbindet die Plus-/Minus-Buttons mit den passenden Funktionen. + */ +function registerCounterHandlers() { + document.querySelectorAll("[data-counter]").forEach(counter => { + const input = counter.querySelector("input[type='number']"); + const dec = counter.querySelector("[data-counter-action='decrease']"); + const inc = counter.querySelector("[data-counter-action='increase']"); + + dec.addEventListener("click", () => updateCounterValue(input, -1)); + inc.addEventListener("click", () => updateCounterValue(input, 1)); + }); +} + +/** + * Erhöht oder verringert den Wert eines Zahlenfelds. + * Der Wert darf dabei nie kleiner als das definierte Minimum werden. + */ +function updateCounterValue(input, change) { + const min = Number(input.min || 1); + const currentValue = Number(input.value || min); + input.value = Math.max(min, currentValue + change); +} + + +// ============================= +// STEP 9: Alles starten +// Hier werden alle Event Listener registriert +// und der Flow startet mit dem Intro-Schritt. +// ============================= + +/** + * Initialisiert den kompletten Event-Erstellungs-Flow. + * Diese Funktion wird einmal beim Laden der Seite aufgerufen. + */ +function initEventCreationFlow() { + // Buttons, die den Flow starten + document.querySelectorAll("[data-start-flow]").forEach(btn => { + btn.addEventListener("click", () => showStep(1)); + }); + + // Navigation + backButton.addEventListener("click", handleBackClick); + nextButton.addEventListener("click", handleNextClick); + + // Formular absenden + form.addEventListener("submit", handleFormSubmit); + + // Counter aktivieren + registerCounterHandlers(); + + // Startzustand: Intro anzeigen + showStep(0); +} + +// Startpunkt des Skripts +initEventCreationFlow(); \ No newline at end of file