Einfügen Icons + Anpassung Styling Radio-Buttons und Foto-Buttons bei Eventerstellung

This commit is contained in:
Ysabelle Moser 2026-04-23 16:25:23 +02:00
parent ee1c78f5de
commit 4bd4f8046d
3 changed files with 258 additions and 31 deletions

View File

@ -229,6 +229,24 @@ textarea:focus {
transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease; transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
} }
.option-card--with-icon {
justify-items: center;
align-content: center;
gap: var(--space-2);
color: var(--brown);
}
.option-card__icon {
color: var(--brown);
font-size: 1.35rem;
line-height: 1;
pointer-events: none;
}
.option-card--with-icon span {
pointer-events: none;
}
.option-card:hover { .option-card:hover {
background: var(--olive-light); background: var(--olive-light);
@ -236,6 +254,41 @@ textarea:focus {
transform: translateY(-3px); transform: translateY(-3px);
} }
.option-grid--tomato-choices .option-card:hover,
.option-grid--tomato-choices .option-card:has(input:focus-visible) {
border-color: var(--tomato);
background: var(--tomato);
color: var(--butter-light);
}
.option-grid--tomato-choices .option-card:has(input:checked) {
border-color: var(--tomato);
background: var(--tomato);
color: var(--butter-light);
}
.option-grid--icon-choices .option-card--with-icon:hover .option-card__icon,
.option-grid--icon-choices .option-card--with-icon:has(input:focus-visible) .option-card__icon,
.option-grid--icon-choices .option-card--with-icon:has(input:checked) .option-card__icon {
color: var(--butter-light);
}
.option-grid--icon-choices .option-card--with-icon:has(input:disabled) {
opacity: 0.45;
}
.option-grid--icon-choices .option-card--with-icon:has(input:disabled):hover {
border-color: var(--olive-light);
background: var(--butter-light);
color: var(--brown);
box-shadow: none;
transform: none;
}
.option-grid--icon-choices .option-card--with-icon:has(input:disabled):hover .option-card__icon {
color: var(--brown);
}
.option-card input { .option-card input {
position: absolute; position: absolute;
inset: 0; inset: 0;
@ -253,14 +306,37 @@ textarea:focus {
box-shadow: 0 0 0 2px rgba(212, 75, 36, 0.14); box-shadow: 0 0 0 2px rgba(212, 75, 36, 0.14);
} }
.guest-count-icon {
display: flex;
justify-content: center;
width: 100%;
color: var(--brown);
font-size: 3rem;
line-height: 1;
}
.guest-count-icon::before {
display: block;
transform: translateX(1.1rem);
}
.counter { .counter {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: var(--space-16); gap: var(--space-16);
} }
.counter input { .counter-value-group {
display: grid;
justify-items: stretch;
row-gap: var(--space-1);
width: 6rem; width: 6rem;
}
.counter input {
width: 100%;
height: 3rem;
padding-block: 0.75rem;
text-align: center; text-align: center;
} }
@ -327,6 +403,20 @@ textarea:focus {
color: var(--color-text-secondary); color: var(--color-text-secondary);
} }
.review-gallery {
display: flex;
flex-wrap: wrap;
gap: var(--space-1);
}
.review-gallery__thumb {
width: 4.5rem;
height: 4.5rem;
border-radius: var(--radius-sm);
object-fit: cover;
box-shadow: var(--shadow-interaction);
}
.submission-success-actions { .submission-success-actions {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
@ -417,22 +507,58 @@ textarea:focus {
margin-top: var(--space-2); margin-top: var(--space-2);
} }
/* Gallery Upload */
.gallery-upload { .gallery-upload {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
gap: 0.75rem; gap: var(--space-16);
} }
.gallery-preview { .gallery-preview {
display: contents; display: contents;
} }
.gallery-add-button {
width: 7rem;
height: 7rem;
display: grid;
place-items: center;
align-content: center;
gap: var(--space-1);
padding: var(--space-1);
border: 1.5px solid var(--olive-light);
border-radius: var(--radius-md);
background: var(--butter-light);
color: var(--olive);
font-family: var(--font-main);
cursor: pointer;
transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}
.gallery-add-button__icon {
color: var(--brown);
font-size: 2rem;
line-height: 1;
}
.gallery-add-button__text {
color: var(--black);
font-size: 0.95rem;
line-height: 1.15;
text-align: center;
overflow-wrap: anywhere;
}
.gallery-add-button:hover {
background: var(--olive-light);
box-shadow: var(--shadow-interaction);
transform: translateY(-3px);
}
.gallery-thumb { .gallery-thumb {
position: relative; position: relative;
width: 5.5rem; width: 7rem;
height: 5.5rem; height: 7rem;
border-radius: var(--radius-sm, 0.5rem); border-radius: var(--radius-sm, 0.5rem);
overflow: hidden; overflow: hidden;
flex-shrink: 0; flex-shrink: 0;

View File

@ -80,24 +80,28 @@
<fieldset class="form-field"> <fieldset class="form-field">
<label>Art des Essens / Eventtyp</label> <label>Art des Essens / Eventtyp</label>
<div class="option-grid option-grid--4"> <div class="option-grid option-grid--4 option-grid--event-type option-grid--icon-choices option-grid--tomato-choices">
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="radio" name="eventType" value="Brunch" required /> <input type="radio" name="eventType" value="Brunch" required />
<i class="fa-solid fa-bread-slice option-card__icon" aria-hidden="true"></i>
<span>Brunch</span> <span>Brunch</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="radio" name="eventType" value="Lunch" /> <input type="radio" name="eventType" value="Lunch" />
<i class="fa-solid fa-pizza-slice option-card__icon" aria-hidden="true"></i>
<span>Lunch</span> <span>Lunch</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="radio" name="eventType" value="Kaffee + Kuchen" /> <input type="radio" name="eventType" value="Kaffee + Kuchen" />
<i class="fa-solid fa-mug-hot option-card__icon" aria-hidden="true"></i>
<span>Kaffee + Kuchen</span> <span>Kaffee + Kuchen</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="radio" name="eventType" value="Dinner" /> <input type="radio" name="eventType" value="Dinner" />
<i class="fa-solid fa-martini-glass option-card__icon" aria-hidden="true"></i>
<span>Dinner</span> <span>Dinner</span>
</label> </label>
</div> </div>
@ -115,15 +119,18 @@
> >
</button> </button>
<div class="counter-value-group">
<i class="fa-solid fa-user-group guest-count-icon" aria-hidden="true"></i>
<input <input
type="number" type="number"
id="maxGuests" id="maxGuests"
name="maxGuests" name="maxGuests"
min="1" min="1"
step="1" step="1"
value="4" value="0"
required required
/> />
</div>
<button <button
type="button" type="button"
class="counter-button" class="counter-button"
@ -152,24 +159,28 @@
<fieldset class="form-field"> <fieldset class="form-field">
<label>Ernährungsform</label> <label>Ernährungsform</label>
<div class="option-grid option-grid--4"> <div class="option-grid option-grid--4 option-grid--icon-choices option-grid--tomato-choices">
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="checkbox" name="dietType" value="Fleisch" /> <input type="checkbox" name="dietType" value="Fleisch" />
<i class="fa-solid fa-drumstick-bite option-card__icon" aria-hidden="true"></i>
<span>Fleisch</span> <span>Fleisch</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="checkbox" name="dietType" value="Fisch" /> <input type="checkbox" name="dietType" value="Fisch" />
<i class="fa-solid fa-fish option-card__icon" aria-hidden="true"></i>
<span>Fisch</span> <span>Fisch</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="checkbox" name="dietType" value="Vegetarisch" /> <input type="checkbox" name="dietType" value="Vegetarisch" />
<i class="fa-solid fa-seedling option-card__icon" aria-hidden="true"></i>
<span>Vegetarisch</span> <span>Vegetarisch</span>
</label> </label>
<label class="option-card option"> <label class="option-card option option-card--with-icon">
<input type="checkbox" name="dietType" value="Vegan" /> <input type="checkbox" name="dietType" value="Vegan" />
<i class="fa-solid fa-leaf option-card__icon" aria-hidden="true"></i>
<span>Vegan</span> <span>Vegan</span>
</label> </label>
</div> </div>
@ -198,7 +209,7 @@
<label>Allergene / Unverträglichkeiten</label> <label>Allergene / Unverträglichkeiten</label>
<p class="field-hint">Optional nur auswählen, wenn es für dein Event relevant ist.</p> <p class="field-hint">Optional nur auswählen, wenn es für dein Event relevant ist.</p>
<div class="option-grid option-grid--3"> <div class="option-grid option-grid--3 option-grid--tomato-choices">
<label class="option-card option"> <label class="option-card option">
<input type="checkbox" name="allergies" value="glutenfrei" /> <input type="checkbox" name="allergies" value="glutenfrei" />
<span>Glutenfrei</span> <span>Glutenfrei</span>
@ -243,7 +254,7 @@
<div class="form-field"> <div class="form-field">
<label for="eventTime">Uhrzeit</label> <label for="eventTime">Uhrzeit</label>
<input type="time" id="eventTime" name="eventTime" value="00:00" required /> <input type="time" id="eventTime" name="eventTime" required />
</div> </div>
</div> </div>
</div> </div>
@ -297,10 +308,13 @@
</div> </div>
<div class="form-field"> <div class="form-field">
<label>Fotos hinzufügen <span class="field-hint-inline">(optional)</span></label> <label>Wie wird dein Event aussehen? <span class="field-hint-inline">(optional)</span></label>
<div class="gallery-upload"> <div class="gallery-upload">
<div class="gallery-preview" id="galleryPreview"></div> <div class="gallery-preview" id="galleryPreview"></div>
<button type="button" class="button-primary" id="galleryAddBtn" aria-label="Foto hinzufügen">Foto hinzufügen</button> <button type="button" class="gallery-add-button" id="galleryAddBtn" aria-label="Foto hinzufügen">
<i class="fa-solid fa-plus gallery-add-button__icon" aria-hidden="true"></i>
<span class="gallery-add-button__text">Foto<br>hinzufügen</span>
</button>
<input type="file" id="galleryFileInput" accept="image/*" multiple hidden /> <input type="file" id="galleryFileInput" accept="image/*" multiple hidden />
</div> </div>
</div> </div>
@ -375,6 +389,15 @@
<dt>Event-Abend</dt> <dt>Event-Abend</dt>
<dd data-review="eventDescription"></dd> <dd data-review="eventDescription"></dd>
</div> </div>
<div class="review-item" data-edit-step="6" data-edit-field="galleryAddBtn" role="button" tabindex="0" aria-label="Fotos bearbeiten">
<dt>Fotos</dt>
<dd>
<div class="review-gallery" data-review-gallery>
<span>Keine Fotos hinzugefügt</span>
</div>
</dd>
</div>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -270,6 +270,29 @@ function updateReviewField(fieldName, value) {
} }
} }
/**
* Zeigt hochgeladene Fotos als kleine Vorschaubilder in der Review.
*/
function updateReviewGallery() {
const target = document.querySelector("[data-review-gallery]");
if (!target) return;
target.innerHTML = "";
if (galleryImages.length === 0) {
target.textContent = "Keine Fotos hinzugefügt";
return;
}
galleryImages.forEach((src, index) => {
const image = document.createElement("img");
image.className = "review-gallery__thumb";
image.src = src;
image.alt = `Foto ${index + 1}`;
target.appendChild(image);
});
}
/** /**
* Baut den Text für Allergien / Hinweise zusammen. * Baut den Text für Allergien / Hinweise zusammen.
* Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert. * Dabei werden Checkboxen und zusätzliches Freitextfeld kombiniert.
@ -297,6 +320,8 @@ function updateReview() {
Object.entries(reviewValues).forEach(([key, value]) => { Object.entries(reviewValues).forEach(([key, value]) => {
updateReviewField(key, value); updateReviewField(key, value);
}); });
updateReviewGallery();
} }
/** /**
@ -539,6 +564,52 @@ function validateDietType() {
return { isValid: true }; return { isValid: true };
} }
/**
* Verhindert widersprüchliche Ernährungsformen:
* Fleisch/Fisch dürfen zusammen, schliessen aber vegetarisch/vegan aus.
*/
function registerDietConflictHandlers() {
const dietOptions = Array.from(form.querySelectorAll('input[name="dietType"]'));
const meatFishOptions = dietOptions.filter(input => ["Fleisch", "Fisch"].includes(input.value));
const plantOptions = dietOptions.filter(input => ["Vegetarisch", "Vegan"].includes(input.value));
const updateDietAvailability = changedInput => {
if (changedInput?.checked && changedInput.value === "Vegetarisch") {
dietOptions.forEach(input => {
if (input.value === "Vegan") input.checked = false;
});
}
if (changedInput?.checked && changedInput.value === "Vegan") {
dietOptions.forEach(input => {
if (input.value === "Vegetarisch") input.checked = false;
});
}
const hasMeatOrFish = meatFishOptions.some(input => input.checked);
const selectedPlantDiet = plantOptions.find(input => input.checked);
meatFishOptions.forEach(input => {
input.disabled = Boolean(selectedPlantDiet);
});
plantOptions.forEach(input => {
input.disabled = hasMeatOrFish || Boolean(selectedPlantDiet && input !== selectedPlantDiet);
});
};
dietOptions.forEach(input => {
input.addEventListener("change", () => {
dietOptions.forEach(option => {
option.closest(".option-card")?.classList.remove("option-card--invalid");
});
updateDietAvailability(input);
});
});
updateDietAvailability();
}
/** /**
* Prüft alle Pflichtfelder ausser Radios und Checkboxen. * Prüft alle Pflichtfelder ausser Radios und Checkboxen.
* Rückgabe: * Rückgabe:
@ -648,11 +719,17 @@ function registerCounterHandlers() {
/** /**
* Erhöht oder verringert den Wert eines Zahlenfelds. * Erhöht oder verringert den Wert eines Zahlenfelds.
* Der Wert darf dabei nie kleiner als das definierte Minimum werden. * 0 bleibt als bewusster Startwert erlaubt; gültig ist erst eine Auswahl ab min.
*/ */
function updateCounterValue(input, change) { function updateCounterValue(input, change) {
const min = Number(input.min || 1); const min = Number(input.min || 1);
const currentValue = Number(input.value || min); const currentValue = Number(input.value || 0);
if (currentValue < min && change < 0) {
input.value = currentValue;
return;
}
input.value = Math.max(min, currentValue + change); input.value = Math.max(min, currentValue + change);
} }
@ -765,7 +842,7 @@ function registerValidationFeedbackHandlers() {
* Setzt den Fokus auf ein bestimmtes Feld oder die erste Option einer Radio-Gruppe. * Setzt den Fokus auf ein bestimmtes Feld oder die erste Option einer Radio-Gruppe.
*/ */
function focusFieldByName(fieldName) { function focusFieldByName(fieldName) {
const field = form.elements[fieldName]; const field = form.elements[fieldName] || document.getElementById(fieldName);
if (!field) return; if (!field) return;
@ -862,6 +939,7 @@ function initEventCreationFlow() {
// Counter aktivieren // Counter aktivieren
registerCounterHandlers(); registerCounterHandlers();
registerDietConflictHandlers();
registerMenuBulletHandler(); registerMenuBulletHandler();
registerValidationFeedbackHandlers(); registerValidationFeedbackHandlers();
registerReviewEditHandlers(); registerReviewEditHandlers();