Compare commits
5 Commits
24dc61a887
...
eb537e7d52
| Author | SHA1 | Date | |
|---|---|---|---|
| eb537e7d52 | |||
| 17c26b1cb5 | |||
| 51a07b6347 | |||
|
|
e3ac1a11f0 | ||
|
|
fa8a7f1fc2 |
@ -14,16 +14,9 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.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);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.event-form {
|
||||
@ -34,7 +27,6 @@
|
||||
|
||||
.step {
|
||||
display: none;
|
||||
padding: var(--space-4) 0 var(--space-4);
|
||||
}
|
||||
|
||||
.submission-success {
|
||||
@ -46,10 +38,11 @@
|
||||
}
|
||||
|
||||
.step-layout {
|
||||
width: min(100%, var(--content-width));
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
gap: var(--space-40);
|
||||
gap: 80px;
|
||||
}
|
||||
|
||||
.startseite {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.step-layout--intro {
|
||||
@ -80,13 +73,13 @@ fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
|
||||
.step-text {
|
||||
/* definiert Breite des Beschriebtexts der einzelnen Schritte*/
|
||||
max-width: 600px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.intro-card,
|
||||
@ -121,21 +114,6 @@ fieldset {
|
||||
}
|
||||
|
||||
|
||||
label {
|
||||
font-family: var(--font-main);
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
|
||||
legend {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--ls-sm);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.field-hint {
|
||||
margin: -0.25rem 0 0;
|
||||
color: var(--color-muted);
|
||||
@ -203,7 +181,7 @@ textarea:focus {
|
||||
|
||||
.option-grid {
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.option-card {
|
||||
@ -243,7 +221,7 @@ textarea:focus {
|
||||
.counter {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.counter input {
|
||||
@ -264,7 +242,7 @@ textarea:focus {
|
||||
.review-card--success {
|
||||
display: grid;
|
||||
gap: var(--space-5);
|
||||
padding: var(--space-3) 0 0;
|
||||
padding: var(--space-16) 0 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
@ -349,9 +327,9 @@ textarea:focus {
|
||||
|
||||
.progress-label {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-muted);
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: var(--black);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -377,9 +355,8 @@ textarea:focus {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
width: min(100%, var(--content-width));
|
||||
margin: 0 auto;
|
||||
padding: var(--space-4) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flow-actions-right {
|
||||
@ -464,11 +441,11 @@ textarea:focus-visible {
|
||||
@media (max-width: 767px) {
|
||||
.site-nav {
|
||||
flex-wrap: wrap;
|
||||
padding: var(--space-3) 0;
|
||||
padding: var(--space-16) 0;
|
||||
}
|
||||
|
||||
.site-nav-links {
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.flow-actions,
|
||||
@ -484,7 +461,6 @@ textarea:focus-visible {
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.step-layout--intro {
|
||||
width: min(100%, 56rem);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
align-items: stretch;
|
||||
gap: var(--space-8);
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
.container { max-width: 1100px; margin: 0 auto; padding: 20px; }
|
||||
|
||||
/* ---------------------------------------------------------
|
||||
Shared Typography Tokens
|
||||
Reuse common text styles across nav, controls and buttons
|
||||
--------------------------------------------------------- */
|
||||
|
||||
|
||||
.meta-filter select,
|
||||
.meta-filter input[type="date"],
|
||||
.detail-primary-btn {
|
||||
@ -42,15 +38,19 @@
|
||||
Overview Header + Filters
|
||||
--------------------------------------------------------- */
|
||||
.filter-label {
|
||||
margin: 0 0 var(--space-1);
|
||||
letter-spacing: var(--ls-la);
|
||||
font-family: var(--font-main);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--ls-sm);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@
|
||||
.event-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.event-card {
|
||||
@ -228,7 +228,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
padding-top: 36px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@ -250,15 +250,14 @@
|
||||
|
||||
.event-spots-full, .detail-spots-pill-full {
|
||||
/* Sold-out visual state, intentionally high-contrast and always filled. */
|
||||
border: 1.5px solid var(--tomato);
|
||||
border: 1.5px solid var(--tomato-light);
|
||||
padding: var(--space-01) var(--space-4);
|
||||
border-radius: var(--radius-pill);
|
||||
color: var(--butter-light);
|
||||
background: var(--tomato);
|
||||
background: var(--tomato-light);
|
||||
font-family: var(--font-main);
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@ -358,7 +357,7 @@
|
||||
.detail-side-stack {
|
||||
grid-area: side;
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
@ -400,7 +399,7 @@
|
||||
/* Editorial mosaic: first image spans two rows, side images stack vertically. */
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: repeat(2, minmax(220px, 1fr));
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
@ -649,13 +648,16 @@
|
||||
color: var(--olive);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
.detail-spots-pill-full {
|
||||
border-color: var(--tomato);
|
||||
color: var(--tomato);
|
||||
opacity: 1;
|
||||
font-weight: 600;
|
||||
}*/
|
||||
border: 1.5px solid var(--tomato-light);
|
||||
color: var(--butter-light);
|
||||
background: var(--tomato-light);
|
||||
font-family: var(--font-main);
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.detail-action-btn-wrap {
|
||||
display: flex;
|
||||
@ -717,11 +719,6 @@
|
||||
box-shadow: 0 2px 6px rgba(102, 52, 13, 0.22);
|
||||
}
|
||||
|
||||
.detail-primary-btn:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.detail-primary-btn-own,
|
||||
.detail-primary-btn-own:disabled {
|
||||
border-color: var(--olive-light);
|
||||
|
||||
151
css/index.css
151
css/index.css
@ -6,7 +6,6 @@
|
||||
|
||||
|
||||
/* --- Navigation overrides (index-specific) --- */
|
||||
|
||||
.nav-link {
|
||||
border: 2px solid var(--olive-light);
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
@ -36,10 +35,9 @@
|
||||
|
||||
/* --- Page layout --- */
|
||||
|
||||
.main-content {
|
||||
width: min(100% - 4rem, 1120px);
|
||||
.container {
|
||||
width: min(100% - 4rem, 1200px);
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
|
||||
@ -48,19 +46,10 @@
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 55px;
|
||||
margin-bottom: 88px;
|
||||
align-items: center;
|
||||
padding: 44px 0;
|
||||
gap: 80px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
/*
|
||||
.hero__buttons {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
}*/
|
||||
|
||||
.hero__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -103,7 +92,7 @@
|
||||
/* --- "So funktioniert's" steps --- */
|
||||
|
||||
.how-it-works {
|
||||
margin-bottom: 70px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.how-it-works__header {
|
||||
@ -254,6 +243,7 @@
|
||||
background: var(--butter-light);
|
||||
border-radius: var(--radius-lg);
|
||||
font-family: var(--font-main);
|
||||
display: none;
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
place-items: center;
|
||||
@ -391,4 +381,133 @@
|
||||
text-decoration: underline;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
/* --- FAQ Section: Akkordion --- */
|
||||
|
||||
.faq-section {
|
||||
padding: var(--space-8) var(--space-4);
|
||||
margin: var(--space-8) 0 var(--space-5);
|
||||
}
|
||||
|
||||
.faq-section h2 {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-5);
|
||||
color: var(--brown);
|
||||
}
|
||||
|
||||
.faq-accordion {
|
||||
width: 100%;
|
||||
max-width: 56rem;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.faq-item {
|
||||
border: 1.5px solid var(--olive-light);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
background: var(--white);
|
||||
transition: background-color 0.2s ease, box-shadow var(--shadow-interaction);
|
||||
}
|
||||
|
||||
.faq-item:hover {
|
||||
box-shadow: var(--shadow-interaction);
|
||||
}
|
||||
|
||||
.faq-trigger {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
color: var(--olive);
|
||||
text-align: left;
|
||||
transition: background-color 0.2s ease;
|
||||
font-family: var(--font-main);
|
||||
}
|
||||
|
||||
.faq-trigger:hover {
|
||||
background-color: var(--butter-light);
|
||||
}
|
||||
|
||||
.faq-trigger:focus-visible {
|
||||
outline: 2px solid var(--olive);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.faq-title {
|
||||
flex: 1;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.faq-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 300;
|
||||
color: var(--olive);
|
||||
transition: transform 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.faq-trigger[aria-expanded="true"] .faq-icon {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.faq-content {
|
||||
padding: 0 var(--space-4);
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease, padding 0.3s ease;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.7;
|
||||
color: var(--black);
|
||||
font-family: var(--font-main);
|
||||
}
|
||||
|
||||
.faq-content p {
|
||||
margin: 0;
|
||||
padding: var(--space-3) 0;
|
||||
}
|
||||
|
||||
.faq-trigger[aria-expanded="true"] + .faq-content {
|
||||
display: block;
|
||||
max-height: 500px;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
}
|
||||
|
||||
|
||||
/* --- Responsive: FAQ Section --- */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.faq-section {
|
||||
padding: var(--space-40) var(--space-4);
|
||||
margin: var(--space-40) 0 var(--space-5);
|
||||
}
|
||||
|
||||
.faq-trigger {
|
||||
padding: var(--space-2) var(--space-3);
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.faq-content {
|
||||
padding: 0 var(--space-3);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.faq-content p {
|
||||
padding: var(--space-2) 0;
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
/* --- Page layout --- */
|
||||
|
||||
.main-content {
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -127,7 +127,7 @@ button[type="submit"]:active {
|
||||
.info-box {
|
||||
background-color: var(--butter-light);
|
||||
border-left: 4px solid var(--olive);
|
||||
padding: var(--space-3);
|
||||
padding: var(--space-16);
|
||||
margin-bottom: var(--space-40);
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
@ -232,7 +232,7 @@ button[type="submit"]:active {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
padding: var(--space-3) var(--space-5);
|
||||
padding: var(--space-16) var(--space-5);
|
||||
border: none;
|
||||
margin-top: 40px;
|
||||
}
|
||||
@ -284,7 +284,7 @@ button[type="submit"]:active {
|
||||
transform: translateX(-50%) translateY(100px);
|
||||
background: var(--olive);
|
||||
color: var(--white);
|
||||
padding: var(--space-3) var(--space-40);
|
||||
padding: var(--space-16) var(--space-40);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
.profile-page {
|
||||
/* Reserve a large safe zone below sticky nav so title/actions are never covered. */
|
||||
margin-top: 0;
|
||||
padding-top: 6.5rem;
|
||||
margin-bottom: var(--space-8);
|
||||
}
|
||||
|
||||
|
||||
/* Kopfbereich mit Titel und Logout-Aktion. */
|
||||
.profile-hero {
|
||||
@ -44,6 +39,22 @@
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.btn-count {
|
||||
color: var(--black);
|
||||
background: var(--tomato-light);
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
margin-right: -18px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
|
||||
.category-item.is-active .btn-count {
|
||||
background: var(--butter-light);
|
||||
}
|
||||
|
||||
|
||||
/* Konsistentes Karten-Layout für alle Profilsektionen. */
|
||||
.profile-panel {
|
||||
@ -53,27 +64,10 @@
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
display: none;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
margin: 0;
|
||||
color: var(--brown);
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.panel-count {
|
||||
min-width: 2rem;
|
||||
padding: 0.1rem 0.65rem;
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--olive-light);
|
||||
color: var(--black);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-16);
|
||||
}
|
||||
|
||||
.profile-card-list {
|
||||
@ -100,7 +94,7 @@
|
||||
}
|
||||
|
||||
.profile-event-card-clickable:hover {
|
||||
transform: translateY(-1px);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.profile-event-title h3{
|
||||
@ -191,11 +185,11 @@
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-3);
|
||||
margin-bottom: var(--space-16);
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
@ -250,7 +244,7 @@
|
||||
.profile-cta-row {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-3);
|
||||
margin-top: var(--space-16);
|
||||
}
|
||||
|
||||
.profile-button-secondary {
|
||||
@ -262,7 +256,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 48rem) {
|
||||
.profile-page {
|
||||
.container {
|
||||
padding-top: 5.5rem;
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
|
||||
|
||||
--tomato: #D44B24;
|
||||
--tomato-dark: #D44B24;
|
||||
--tomato-dark: #B53A18;
|
||||
--tomato-light: #E5937C;
|
||||
--olive: #6B6B05;
|
||||
--olive-dark: #545404;
|
||||
--olive-light: #C8CC7A;
|
||||
@ -44,7 +45,7 @@
|
||||
--space-01: 0.375rem; /* 6px */
|
||||
--space-1: 0.5rem; /* 8px */
|
||||
--space-2: 0.75rem; /* 12px */
|
||||
--space-3: 1rem; /* 16px */
|
||||
--space-16: 1rem; /* 16px */
|
||||
--space-20: 1.25rem; /* 20px */
|
||||
--space-4: 1.5rem; /* 24px */
|
||||
--space-5: 2rem; /* 32px */
|
||||
@ -124,6 +125,33 @@ p {
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
.label-input-field {
|
||||
font-family: var(--font-main);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--ls-sm);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-16);
|
||||
}
|
||||
|
||||
label {
|
||||
font-family: var(--font-main);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--ls-sm);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-0);
|
||||
}
|
||||
|
||||
.option {
|
||||
font-family: var(--font-main);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: var(--ls-sm);
|
||||
line-height: 1;
|
||||
margin-bottom: var(--space-16);
|
||||
}
|
||||
|
||||
.link-text a{
|
||||
color: var(--blue);
|
||||
margin-top: var(--space-4);
|
||||
@ -167,7 +195,7 @@ p {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space-3);
|
||||
gap: var(--space-16);
|
||||
padding-top: 36px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@ -188,16 +216,38 @@ p {
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.main-content {
|
||||
margin-top: var(--space-8);
|
||||
|
||||
.layout-wide {
|
||||
width: 75%;
|
||||
max-width: 1200px;
|
||||
margin: 82px auto 0 auto;
|
||||
}
|
||||
|
||||
.layout-narrow {
|
||||
width: 55%;
|
||||
max-width: 900px;
|
||||
margin: 82px auto 0 auto;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.container {
|
||||
width: 90%;
|
||||
width: 80%;
|
||||
max-width: 75rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Media Queries (Responsive) */
|
||||
@media (max-width: 48rem) {
|
||||
.container {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
@ -436,7 +486,8 @@ p {
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.counter-button:hover, .counter-button:focus-visible {
|
||||
.counter-button:hover,
|
||||
.counter-button:focus-visible {
|
||||
background-color: var(--olive-dark);
|
||||
border-color: var(--olive-dark);
|
||||
}
|
||||
@ -456,28 +507,30 @@ p {
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.category-item:hover, .category-item:focus-visible {
|
||||
.category-item:hover,
|
||||
.category-item:focus-visible,
|
||||
.category-item.is-active,
|
||||
.category-item.active {
|
||||
background: var(--tomato);
|
||||
color: var(--butter-light);
|
||||
}
|
||||
|
||||
.category-item.is-active, .category-item.active {
|
||||
background: var(--tomato);
|
||||
color: var(--butter-light);
|
||||
|
||||
.category-items {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.category-item-profile {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
padding: var(--space-1) var(--space-4);
|
||||
|
||||
}
|
||||
|
||||
.category-items {
|
||||
height: 44px;
|
||||
padding: 0 var(--space-4);
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
align-items: center;
|
||||
gap: var(--space-16);
|
||||
}
|
||||
|
||||
.button-small {
|
||||
@ -490,7 +543,7 @@ p {
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
border-radius: var(--radius-pill);
|
||||
padding: 10px var(--space-3);
|
||||
padding: 10px var(--space-16);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -676,7 +729,7 @@ p {
|
||||
transform: translateX(-50%) translateY(100px);
|
||||
background: var(--olive);
|
||||
color: var(--white);
|
||||
padding: var(--space-3) var(--space-40);
|
||||
padding: var(--space-16) var(--space-40);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
@ -754,7 +807,7 @@ p {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
margin-top: 120px;
|
||||
padding: var(--space-3) var(--space-7);
|
||||
padding: var(--space-16) var(--space-7);
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
@ -779,13 +832,3 @@ p {
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
/* Media Queries (Responsive) */
|
||||
@media (max-width: 48rem) {
|
||||
.container {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,11 @@
|
||||
"title": "Italienische Tavolata",
|
||||
"location": "Luzern",
|
||||
"address": "Pilatusstrasse 18, 6003 Luzern",
|
||||
"date": "11. APR. 2026",
|
||||
"date": "22. APR. 2026",
|
||||
"time": "15:30 UHR",
|
||||
"category": "Dinner",
|
||||
"diet": "Vegetarisch",
|
||||
"spots": 6,
|
||||
"spots": 8,
|
||||
"host": {
|
||||
"name": "Ferdinando",
|
||||
"initial": "F"
|
||||
@ -45,7 +45,7 @@
|
||||
"title": "Noche Peruana",
|
||||
"location": "Chur",
|
||||
"address": "Obere Gasse 41, 7000 Chur",
|
||||
"date": "16. Juni 2026",
|
||||
"date": "12. April 2026",
|
||||
"time": "19:00 UHR",
|
||||
"category": "Dinner",
|
||||
"diet": "Omnivore",
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-content" style="padding: 40px 20px; max-width: 800px; margin: 0 auto;">
|
||||
<main class="layout-wide">
|
||||
<h1>Datenschutzerklärung</h1>
|
||||
|
||||
<h3>1. Verantwortliche Stelle</h3>
|
||||
|
||||
@ -35,11 +35,11 @@
|
||||
|
||||
<form id="eventForm" class="event-form" novalidate>
|
||||
<section
|
||||
class="step step--active step--intro"
|
||||
class="step step--active step--intro layout-wide"
|
||||
data-step="0"
|
||||
aria-labelledby="intro-title"
|
||||
>
|
||||
<div class="step-layout step-layout--intro">
|
||||
<div class="step-layout hero startseite">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Event erstellen</p>
|
||||
<h1 id="intro-title">Hey <span id="username">{{username}}</span>, was hast du vor?</h1>
|
||||
@ -52,17 +52,17 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<aside class="intro-card intro-card--image" aria-label="Stimmungsbild zur Event-Erstellung">
|
||||
<div class="intro-card intro-card--image hero__right" aria-label="Stimmungsbild zur Event-Erstellung">
|
||||
<img
|
||||
class="intro-image"
|
||||
src="assets/eventcreate_foodtable.jpg"
|
||||
alt="Ein gedeckter Tisch mit gemeinsamem Essen"
|
||||
/>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="1" aria-labelledby="step1-title">
|
||||
<section class="step layout-narrow" data-step="1" aria-labelledby="step1-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 1</p>
|
||||
@ -75,25 +75,25 @@
|
||||
|
||||
<div class="step-fields">
|
||||
<fieldset class="form-field">
|
||||
<legend>Art des Essens / Eventtyp</legend>
|
||||
<label>Art des Essens / Eventtyp</label>
|
||||
|
||||
<div class="option-grid option-grid--4">
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="radio" name="eventType" value="Brunch" required />
|
||||
<span>Brunch</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="radio" name="eventType" value="Lunch" />
|
||||
<span>Lunch</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="radio" name="eventType" value="Kaffee + Kuchen" />
|
||||
<span>Kaffee + Kuchen</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="radio" name="eventType" value="Dinner" />
|
||||
<span>Dinner</span>
|
||||
</label>
|
||||
@ -101,7 +101,7 @@
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="form-field">
|
||||
<legend>Maximale Personenanzahl</legend>
|
||||
<label>Maximale Personenanzahl</label>
|
||||
|
||||
<div class="counter" data-counter>
|
||||
<button
|
||||
@ -135,7 +135,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="2" aria-labelledby="step2-title">
|
||||
<section class="step layout-narrow" data-step="2" aria-labelledby="step2-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 2</p>
|
||||
@ -147,25 +147,25 @@
|
||||
|
||||
<div class="step-fields">
|
||||
<fieldset class="form-field">
|
||||
<legend>Ernährungsform</legend>
|
||||
<label>Ernährungsform</label>
|
||||
|
||||
<div class="option-grid option-grid--4">
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="dietType" value="Fleisch" />
|
||||
<span>Fleisch</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="dietType" value="Fisch" />
|
||||
<span>Fisch</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="dietType" value="Vegetarisch" />
|
||||
<span>Vegetarisch</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="dietType" value="Vegan" />
|
||||
<span>Vegan</span>
|
||||
</label>
|
||||
@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="3" aria-labelledby="step3-title">
|
||||
<section class="step layout-narrow" data-step="3" aria-labelledby="step3-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 3</p>
|
||||
@ -192,23 +192,23 @@
|
||||
|
||||
<div class="step-fields">
|
||||
<fieldset class="form-field">
|
||||
<legend>Allergene / Unverträglichkeiten</legend>
|
||||
<label>Allergene / Unverträglichkeiten</label>
|
||||
<p class="field-hint">Optional – nur auswählen, wenn es für dein Event relevant ist.</p>
|
||||
|
||||
<div class="option-grid option-grid--3">
|
||||
<label class="option-card option-card--checkbox">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="allergies" value="glutenfrei" />
|
||||
<span>glutenfrei</span>
|
||||
<span>Glutenfrei</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card option-card--checkbox">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="allergies" value="laktosefrei" />
|
||||
<span>laktosefrei</span>
|
||||
<span>Laktosefrei</span>
|
||||
</label>
|
||||
|
||||
<label class="option-card option-card--checkbox">
|
||||
<label class="option-card option">
|
||||
<input type="checkbox" name="allergies" value="ohne Nüsse" />
|
||||
<span>ohne Nüsse</span>
|
||||
<span>Ohne Nüsse</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
@ -221,7 +221,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="4" aria-labelledby="step4-title">
|
||||
<section class="step layout-narrow" data-step="4" aria-labelledby="step4-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 4</p>
|
||||
@ -247,7 +247,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="5" aria-labelledby="step5-title">
|
||||
<section class="step layout-narrow" data-step="5" aria-labelledby="step5-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 5</p>
|
||||
@ -271,7 +271,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="6" aria-labelledby="step6-title">
|
||||
<section class="step layout-narrow" data-step="6" aria-labelledby="step6-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 6</p>
|
||||
@ -305,7 +305,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="step" data-step="7" aria-labelledby="step7-title">
|
||||
<section class="step layout-narrow" data-step="7" aria-labelledby="step7-title">
|
||||
<div class="step-layout">
|
||||
<div class="step-copy">
|
||||
<p class="badge">Schritt 7</p>
|
||||
@ -378,7 +378,7 @@
|
||||
</section>
|
||||
|
||||
|
||||
<div class="flow-footer" id="flowFooter" hidden>
|
||||
<div class="flow-footer layout-narrow" id="flowFooter" hidden>
|
||||
|
||||
<p id="errorMessage" class="error-message" role="alert" aria-live="assertive"></p>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Invité | Event-Detail</title>
|
||||
<title>Invité | Event-Detail</title>
|
||||
|
||||
<!-- Stylesheet für diese Seite-->
|
||||
<link rel="stylesheet" href="css/event_overview.css">
|
||||
@ -28,7 +28,7 @@
|
||||
</header>
|
||||
|
||||
<!-- Main content: detail page gets fully injected by JavaScript -->
|
||||
<main class="container">
|
||||
<main class="container layout-wide">
|
||||
<!-- Render target: loading, error state or full detail layout -->
|
||||
<div id="detail-view">
|
||||
<p>Lädt Event-Details...</p>
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
|
||||
<!-- Globales Stylesheet -->
|
||||
<link rel="stylesheet" href="css/stylesheet_global.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -28,13 +27,14 @@
|
||||
</header>
|
||||
|
||||
<!-- Main content: page headline, filter controls and dynamic event list -->
|
||||
<main class="container">
|
||||
<main class="container layout-wide">
|
||||
<!-- Page headline -->
|
||||
<h1>Events</h1>
|
||||
<p class="badge margin-bottom-40">Event finden</p>
|
||||
<h1>Was darf es sein?</h1>
|
||||
|
||||
<!-- Filter section: category chips + location/date filters -->
|
||||
<section class="filter-section">
|
||||
<p class="filter-label">Was darf es sein?</p>
|
||||
<p class="filter-label">Art des Essens / Eventtyp</p>
|
||||
<div class="filter-row">
|
||||
<!-- Primary category filter buttons -->
|
||||
<div class="category-group">
|
||||
@ -63,6 +63,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="filter-label">Ernährungsform</p>
|
||||
<div class="filter-row">
|
||||
<!-- Primary category filter buttons -->
|
||||
<div class="category-group">
|
||||
@ -73,12 +74,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="filter-label">Allergene</p>
|
||||
<div class="filter-row">
|
||||
<!-- Primary category filter buttons -->
|
||||
<!-- Allergen filter buttons -->
|
||||
<div class="category-group">
|
||||
<button class="category-item" type="button" data-cat="Fleisch">glutenfrei</button>
|
||||
<button class="category-item" type="button" data-cat="Fisch">laktosefrei</button>
|
||||
<button class="category-item" type="button" data-cat="Vegetarisch">ohne Nüsse</button>
|
||||
<button class="category-item" type="button" data-allergie="glutenfrei">glutenfrei</button>
|
||||
<button class="category-item" type="button" data-allergie="laktosefrei">laktosefrei</button>
|
||||
<button class="category-item" type="button" data-allergie="ohne Nüsse">ohne Nüsse</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -92,6 +94,19 @@
|
||||
<!-- Seitenlogik: Daten laden, filtern und Event-Karten rendern -->
|
||||
<script src="js/event_overview.js"></script>
|
||||
|
||||
<!-- Info Modal: Kostenlose Events Info -->
|
||||
<div id="info-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>Warum Invité kostenlos ist</h2>
|
||||
<button type="button" class="modal-close" aria-label="Popup schließen">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Alle Events bei uns sind komplett kostenlos. Invité basiert rein auf Freiwilligkeit und der Freude am Teilen. Kein Geldfluss, keine versteckten Kosten – nur die pure Absicht, die Community zu stärken und den sozialen Zusammenhalt in unserer Nachbarschaft zu fördern. Egal ob du den Kochlöffel schwingst oder dich als Gast dazu gesellst: Bei uns zählt nur die menschliche Begegnung.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Snackbar: Feedback bei An-/Abmeldung -->
|
||||
<div class="snackbar" id="snackbar"></div>
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-content" style="padding: 40px 20px; max-width: 800px; margin: 0 auto;">
|
||||
<main class="layout-wide">
|
||||
<h1>Impressum</h1>
|
||||
|
||||
<h3>Angaben gemäss § 5 TMG</h3>
|
||||
|
||||
100
index.html
100
index.html
@ -29,14 +29,14 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<main class="container layout-wide">
|
||||
<!-- Hero: uses .hero, .btn, .image-card, and .hero-image for a polished first impression -->
|
||||
<section class="hero">
|
||||
<div class="hero__left">
|
||||
<span class="badge margin-bottom-40">einfach. lecker. gemeinsam.</span>
|
||||
<h1>Teile deine Leidenschaft, geniesse gemeinsam.</h1>
|
||||
<p>Ob du als leidenschaftlicher Hobbykoch Gastgeber sein möchtest oder als Feinschmecker einen Platz an einem lokalen Tisch suchst Invité verbindet Menschen durch die Kraft einer gemeinsamen Mahlzeit.</p>
|
||||
<a class="button-primary" href="signup.html">Anmelden</a>
|
||||
<a class="button-primary" href="signup.html">Registrieren</a>
|
||||
</div>
|
||||
|
||||
<div class="hero__right">
|
||||
@ -149,6 +149,77 @@
|
||||
|
||||
<script src="js/index-carousel.js"></script>
|
||||
|
||||
<!-- FAQ Section: Akkordion mit häufig gestellten Fragen -->
|
||||
<section class="faq-section">
|
||||
<div class="container">
|
||||
<h2>Häufig gestellte Fragen</h2>
|
||||
<div class="faq-accordion">
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Wie kann ich bei Invité anfangen?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p><strong>Schritt 1: Kostenloses Konto erstellen</strong><br>Gehe auf Invité, klicke auf "Jetzt beitreten" und fülle das Anmeldeformular aus. Du benötigst nur deine E-Mail und ein Passwort.</p>
|
||||
<p><strong>Schritt 2: Dein Profil ausfüllen</strong><br>Lade ein Profilfoto hoch, schreib ein bisschen über dich und gib deine Allergien/Ernährungspräferenzen an. Das hilft anderen, dich besser kennenzulernen.</p>
|
||||
<p><strong>Schritt 3: Erkunde Events</strong><br>Browsing durch unsere Events, filtere nach Diät oder Allergie-Einstellungen, und melde dich zu den Events an, die dich interessieren!</p>
|
||||
<p><strong>Schritt 4: Erstelle dein eigenes Event</strong><br>Du kannst auch selbst ein Kochevent hosten! Klick auf "Event erstellen", beschreib dein Menü, und lade Gäste ein.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Fallen bei Invité Kosten an?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p>Nein, Invité ist komplett kostenlos. Alle Events basieren auf Freiwilligkeit und der Freude am Teilen. Es gibt keine versteckten Kosten – nur die pure Absicht, die Community zu stärken.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Kann ich ein eigenes Event erstellen?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p>Ja, absolut! Du kannst dein eigenes Kochevent erstellen und Gäste einladen. Beschreibe dein Menü, die Teilnehmerzahl und weitere Details. Es ist deine Küche, dein Event, deine Regeln.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Wie funktioniert die An-/Abmeldung?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p>Bei jedem Event sehen dich die verfügbaren Plätze. Du kannst dich mit einem Klick anmelden. Eine Abmeldung ist bis 24 Stunden vor dem Event möglich – so respektieren wir den Aufwand des Gastgebers.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Was ist mit Allergien und Diäten?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p>Ich kann Informationen zu Allergien und Ernährungseinstellungen in der Event-Beschreibung hinzufügen oder beim Anmelden angeben. So können Gastgeber und Gäste besser zusammenkommen und Überraschungen vermeiden.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="faq-item">
|
||||
<button type="button" class="faq-trigger" aria-expanded="false">
|
||||
<span class="faq-title">Ist Invité sicher und vertrauenswürdig?</span>
|
||||
<span class="faq-icon">+</span>
|
||||
</button>
|
||||
<div class="faq-content">
|
||||
<p>Ja, dein Profil hilft anderen, dich besser kennenzulernen. Wir ermutigen zu Offenheit und gegenseitigem Vertrauen. Allerdings bleibt es deine Entscheidung, wem du deine Adresse mitteilst – die erfolgt nur 12 Stunden vor dem Event.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="footer">
|
||||
<div class="footer-left">
|
||||
<p class="p-small inline">© <img src="assets/logo_invite.svg" alt="Invité Logo" class="footer-invite_logo" /></p>
|
||||
@ -165,5 +236,30 @@
|
||||
<a href="datenschutz.html" class="link-text-footer">Datenschutz</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Akkordion Toggle Script -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const faqTriggers = document.querySelectorAll('.faq-trigger');
|
||||
|
||||
faqTriggers.forEach((trigger) => {
|
||||
trigger.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const isExpanded = this.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
// Close all other items (optional: comment out to allow multiple open)
|
||||
faqTriggers.forEach((otherTrigger) => {
|
||||
if (otherTrigger !== trigger) {
|
||||
otherTrigger.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle current item
|
||||
this.setAttribute('aria-expanded', !isExpanded);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,11 +1,12 @@
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const USERS_STORAGE_KEY = 'socialCookingUsers';
|
||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||
// -------------------------------------------------------------
|
||||
// DOM entry point and shared asset path.
|
||||
// -------------------------------------------------------------
|
||||
const detailContainer = document.getElementById('detail-view');
|
||||
const detailcontainer = document.getElementById('detail-view');
|
||||
const locationIconPath = 'assets/icon_location.svg';
|
||||
const calendarIconPath = 'assets/icon_calendar.svg';
|
||||
const gastIconPath = 'assets/icon_gast.svg';
|
||||
@ -50,6 +51,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getStoredUsers() {
|
||||
try {
|
||||
const stored = localStorage.getItem(USERS_STORAGE_KEY);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch (error) {
|
||||
console.error('Benutzerdaten konnten nicht gelesen werden.', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function getUserDisplayName(user) {
|
||||
if (!user) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const firstName = String(user.vorname || '').trim();
|
||||
const lastName = String(user.nachname || '').trim();
|
||||
|
||||
return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim();
|
||||
}
|
||||
|
||||
function getResolvedParticipants(event, registrationMap) {
|
||||
const baseParticipants = Array.isArray(event.participants)
|
||||
? event.participants.map(name => String(name || '').trim()).filter(Boolean)
|
||||
: [];
|
||||
const usersByEmail = new Map(
|
||||
getStoredUsers().map(user => [String(user.email || '').trim().toLowerCase(), user])
|
||||
);
|
||||
const participantLookup = new Set(baseParticipants.map(name => name.toLowerCase()));
|
||||
|
||||
Object.entries(registrationMap || {}).forEach(([email, ids]) => {
|
||||
const isRegisteredForEvent = Array.isArray(ids)
|
||||
&& ids.map(id => Number(id)).includes(Number(event.id));
|
||||
|
||||
if (!isRegisteredForEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = usersByEmail.get(String(email || '').trim().toLowerCase());
|
||||
const displayName = getUserDisplayName(user) || String(email || '').trim();
|
||||
const normalizedName = displayName.toLowerCase();
|
||||
|
||||
if (displayName && !participantLookup.has(normalizedName)) {
|
||||
baseParticipants.push(displayName);
|
||||
participantLookup.add(normalizedName);
|
||||
}
|
||||
});
|
||||
|
||||
return baseParticipants;
|
||||
}
|
||||
|
||||
function setRegistrationMap(registrationMap) {
|
||||
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
|
||||
}
|
||||
@ -114,7 +166,7 @@
|
||||
}
|
||||
|
||||
const msUntilStart = eventDateTime.getTime() - Date.now();
|
||||
const twentyfourHoursInMs = 12 * 60 * 60 * 1000;
|
||||
const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
|
||||
|
||||
return msUntilStart <= twentyfourHoursInMs;
|
||||
}
|
||||
@ -138,7 +190,7 @@
|
||||
return { daysLeft, isClosed: false };
|
||||
}
|
||||
|
||||
// Adresse ist nur im 12h-Fenster VOR Eventstart sichtbar.
|
||||
// Adresse ist nur im 24h-Fenster VOR Eventstart sichtbar.
|
||||
function isAddressVisibleWindow(event) {
|
||||
const eventDateTime = parseEventDateTime(event);
|
||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||
@ -146,7 +198,7 @@
|
||||
}
|
||||
|
||||
const msUntilStart = eventDateTime.getTime() - Date.now();
|
||||
const twentyfourHoursInMs = 12 * 60 * 60 * 1000;
|
||||
const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
|
||||
|
||||
return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs;
|
||||
}
|
||||
@ -212,7 +264,7 @@
|
||||
if (event) {
|
||||
renderDetailPage(event);
|
||||
} else {
|
||||
detailContainer.innerHTML = "<h1>Event wurde nicht gefunden.</h1><a href='event_overview.html'>Zurück zur Übersicht</a>";
|
||||
detailcontainer.innerHTML = "<h1>Event wurde nicht gefunden.</h1><a href='event_overview.html'>Zurück zur Übersicht</a>";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Laden der Details:", error);
|
||||
@ -283,16 +335,26 @@
|
||||
const specifications = Array.isArray(event.specifications) && event.specifications.length > 0
|
||||
? event.specifications
|
||||
: [];
|
||||
const participants = Array.isArray(event.participants) ? event.participants : [];
|
||||
const galleryImages = Array.isArray(event.gallery) && event.gallery.length > 0
|
||||
? event.gallery
|
||||
: [event.image, event.image, event.image];
|
||||
const visibleParticipants = participants.slice(0, 6);
|
||||
const registrationMap = getRegistrationMap();
|
||||
const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id);
|
||||
const remainingParticipants = Math.max(0, participants.length + extraRegistrations - visibleParticipants.length);
|
||||
const participants = getResolvedParticipants(event, registrationMap);
|
||||
const galleryImages = Array.isArray(event.gallery)
|
||||
? event.gallery.filter(Boolean)
|
||||
: [];
|
||||
const galleryMarkup = galleryImages.length > 0
|
||||
? `
|
||||
<div class="detail-gallery detail-gallery-large">
|
||||
${galleryImages.slice(0, 9).map((img, index) => `
|
||||
<button class="detail-gallery-item" type="button" aria-label="Bild ${index + 1} gross anzeigen" data-fullsrc="${img}">
|
||||
<img src="${img}" alt="${event.title} Bild ${index + 1}" class="detail-gallery-image">
|
||||
</button>
|
||||
`).join('')}
|
||||
</div>
|
||||
`
|
||||
: '';
|
||||
const visibleParticipants = participants.slice(0, 6);
|
||||
const remainingParticipants = Math.max(0, participants.length - visibleParticipants.length);
|
||||
const totalGuests = Number.isFinite(event.spots) ? event.spots : 0;
|
||||
const confirmedGuests = participants.length + extraRegistrations;
|
||||
const confirmedGuests = participants.length;
|
||||
const freePlaces = Math.max(0, totalGuests - confirmedGuests);
|
||||
const isFull = freePlaces === 0;
|
||||
const isRegistrationClosed = isRegistrationClosedForEvent(event);
|
||||
@ -331,7 +393,12 @@
|
||||
<p>${event.address}</p>
|
||||
</article>
|
||||
`
|
||||
: '';
|
||||
: `
|
||||
<article class="detail-panel">
|
||||
<h2 class="detail-section-title">Adresse</h2>
|
||||
<p>Vielen Dank für die Anmeldung! Die Adresse für diesen Event wird 24 Stunden vorher genau hier sichtbar sein.</p>
|
||||
</article>
|
||||
`;
|
||||
const detailChips = [
|
||||
`<span class="event-tag">${eventCategory}</span>`,
|
||||
...event.diet.split(', ').filter(d => d.trim() && d !== 'Keine Angabe').map(d => `<span class="event-tag">${getDietLabel(d.trim())}</span>`),
|
||||
@ -340,7 +407,7 @@
|
||||
|
||||
// Render complete detail page layout including:
|
||||
// hero metadata, host card, menu, participants, gallery and sticky action bar.
|
||||
detailContainer.innerHTML = `
|
||||
detailcontainer.innerHTML = `
|
||||
|
||||
<section class="detail-hero">
|
||||
<div class="detail-top-row">
|
||||
@ -400,13 +467,7 @@
|
||||
${addressPanelMarkup}
|
||||
</div>
|
||||
|
||||
<div class="detail-gallery detail-gallery-large">
|
||||
${galleryImages.slice(0, 9).map((img, index) => `
|
||||
<button class="detail-gallery-item" type="button" aria-label="Bild ${index + 1} gross anzeigen" data-fullsrc="${img}">
|
||||
<img src="${img}" alt="${event.title} Bild ${index + 1}" class="detail-gallery-image">
|
||||
</button>
|
||||
`).join('')}
|
||||
</div>
|
||||
${galleryMarkup}
|
||||
</section>
|
||||
|
||||
<section class="detail-action-bar">
|
||||
@ -430,25 +491,34 @@
|
||||
<strong>${event.title}</strong>
|
||||
</div>
|
||||
|
||||
<div class="detail-action-buttons">
|
||||
<span class="detail-spots-pill${isFull ? ' detail-spots-pill-full' : ''}">
|
||||
${isFull ? 'AUSGEBUCHT' : `${freePlaces} Plätze frei`}
|
||||
</span>
|
||||
<div class="detail-action-btn-wrap">
|
||||
<button class="detail-primary-btn${actionButtonVariantClass}" type="button" data-register-button ${actionButtonDisabled ? 'disabled' : ''}>
|
||||
${actionButtonLabel}
|
||||
</button>
|
||||
${isRegistered && deregInfo.daysLeft !== null ? `
|
||||
<small class="detail-dereg-hint${deregInfo.isClosed ? ' detail-dereg-hint--closed' : ''}">
|
||||
${deregInfo.isClosed
|
||||
? 'Abmeldefrist abgelaufen'
|
||||
: deregInfo.daysLeft === 1
|
||||
? 'Noch 1 Tag zur Abmeldung'
|
||||
: `Noch ${deregInfo.daysLeft} Tage zur Abmeldung`}
|
||||
</small>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-action-btn-wrap">
|
||||
${isFull ? `
|
||||
<button
|
||||
class="detail-primary-btn detail-spots-pill-full"
|
||||
type="button"
|
||||
disabled>
|
||||
Ausgebucht
|
||||
</button>
|
||||
` : `
|
||||
<button
|
||||
class="detail-primary-btn${actionButtonVariantClass}"
|
||||
type="button"
|
||||
data-register-button
|
||||
${actionButtonDisabled ? 'disabled' : ''}>
|
||||
${actionButtonLabel}
|
||||
</button>
|
||||
`}
|
||||
|
||||
${isRegistered && deregInfo.daysLeft !== null ? `
|
||||
<small class="detail-dereg-hint${deregInfo.isClosed ? ' detail-dereg-hint--closed' : ''}">
|
||||
${deregInfo.isClosed
|
||||
? 'Abmeldefrist abgelaufen'
|
||||
: deregInfo.daysLeft === 1
|
||||
? 'Noch 1 Tag zur Abmeldung'
|
||||
: `Noch ${deregInfo.daysLeft} Tage zur Abmeldung`}
|
||||
</small>
|
||||
` : ''}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="detail-lightbox" aria-hidden="true">
|
||||
@ -465,11 +535,11 @@
|
||||
// Lightbox behavior for gallery images:
|
||||
// open on image click, close via backdrop, close button or ESC.
|
||||
// ---------------------------------------------------------
|
||||
const lightbox = detailContainer.querySelector('.detail-lightbox');
|
||||
const lightboxImage = detailContainer.querySelector('.detail-lightbox-image');
|
||||
const lightboxClose = detailContainer.querySelector('.detail-lightbox-close');
|
||||
const galleryButtons = detailContainer.querySelectorAll('.detail-gallery-item');
|
||||
const registerButton = detailContainer.querySelector('[data-register-button]');
|
||||
const lightbox = detailcontainer.querySelector('.detail-lightbox');
|
||||
const lightboxImage = detailcontainer.querySelector('.detail-lightbox-image');
|
||||
const lightboxClose = detailcontainer.querySelector('.detail-lightbox-close');
|
||||
const galleryButtons = detailcontainer.querySelectorAll('.detail-gallery-item');
|
||||
const registerButton = detailcontainer.querySelector('[data-register-button]');
|
||||
|
||||
// Harte Absicherung: Eigene Events sind auf der Detailseite immer deaktiviert.
|
||||
if (registerButton && isOwnEvent) {
|
||||
@ -530,9 +600,9 @@
|
||||
}
|
||||
|
||||
// "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]');
|
||||
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', () => {
|
||||
@ -586,5 +656,12 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Back button navigation: returns to event overview page.
|
||||
if (backButton) {
|
||||
backButton.addEventListener('click', () => {
|
||||
window.location.href = 'event_overview.html';
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const EVENTS_STORAGE_KEY = 'socialCookingEvents';
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const USERS_STORAGE_KEY = 'socialCookingUsers';
|
||||
const REGISTRATION_STORAGE_KEY = 'socialCookingRegistrations';
|
||||
const INFO_MODAL_SHOWN_KEY = 'infoModalShownOnFirstLogin';
|
||||
// -------------------------------------------------------------
|
||||
// DOM references used throughout the page lifecycle.
|
||||
// -------------------------------------------------------------
|
||||
@ -15,10 +17,13 @@
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// In-memory state for fetched events and currently active category.
|
||||
// In-memory state for fetched events and currently active filters.
|
||||
// Separate state for category, diet, and allergie selections.
|
||||
// -------------------------------------------------------------
|
||||
let allEvents = [];
|
||||
let activeCategory = 'ALLE';
|
||||
let activeDiets = new Set();
|
||||
let activeAllergies = new Set();
|
||||
const currentUser = getCurrentUser();
|
||||
|
||||
function getCurrentUser() {
|
||||
@ -69,6 +74,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getStoredUsers() {
|
||||
try {
|
||||
const stored = localStorage.getItem(USERS_STORAGE_KEY);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch (error) {
|
||||
console.error('Benutzerdaten konnten nicht gelesen werden.', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function getUserDisplayName(user) {
|
||||
if (!user) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const firstName = String(user.vorname || '').trim();
|
||||
const lastName = String(user.nachname || '').trim();
|
||||
|
||||
return (firstName || `${firstName} ${lastName}`.trim() || String(user.email || '').trim()).trim();
|
||||
}
|
||||
|
||||
function getResolvedParticipants(event, registrationMap) {
|
||||
const baseParticipants = Array.isArray(event.participants)
|
||||
? event.participants.map(name => String(name || '').trim()).filter(Boolean)
|
||||
: [];
|
||||
const usersByEmail = new Map(
|
||||
getStoredUsers().map(user => [String(user.email || '').trim().toLowerCase(), user])
|
||||
);
|
||||
const participantLookup = new Set(baseParticipants.map(name => name.toLowerCase()));
|
||||
|
||||
Object.entries(registrationMap || {}).forEach(([email, ids]) => {
|
||||
const isRegisteredForEvent = Array.isArray(ids)
|
||||
&& ids.map(id => Number(id)).includes(Number(event.id));
|
||||
|
||||
if (!isRegisteredForEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = usersByEmail.get(String(email || '').trim().toLowerCase());
|
||||
const displayName = getUserDisplayName(user) || String(email || '').trim();
|
||||
const normalizedName = displayName.toLowerCase();
|
||||
|
||||
if (displayName && !participantLookup.has(normalizedName)) {
|
||||
baseParticipants.push(displayName);
|
||||
participantLookup.add(normalizedName);
|
||||
}
|
||||
});
|
||||
|
||||
return baseParticipants;
|
||||
}
|
||||
|
||||
function setRegistrationMap(registrationMap) {
|
||||
localStorage.setItem(REGISTRATION_STORAGE_KEY, JSON.stringify(registrationMap));
|
||||
}
|
||||
@ -91,8 +147,13 @@
|
||||
const savedCategory = sessionStorage.getItem('activeFilter') || 'ALLE';
|
||||
const savedLocation = sessionStorage.getItem('activeLocation') || 'ALLE_ORTE';
|
||||
const savedDate = sessionStorage.getItem('activeDate') || '';
|
||||
const savedDiets = sessionStorage.getItem('activeDiets') || '';
|
||||
const savedAllergies = sessionStorage.getItem('activeAllergies') || '';
|
||||
|
||||
activeCategory = savedCategory;
|
||||
activeDiets = new Set(savedDiets ? savedDiets.split(',') : []);
|
||||
activeAllergies = new Set(savedAllergies ? savedAllergies.split(',') : []);
|
||||
|
||||
if (locationFilter) {
|
||||
locationFilter.value = hasOption(locationFilter, savedLocation) ? savedLocation : 'ALLE_ORTE';
|
||||
}
|
||||
@ -283,26 +344,54 @@
|
||||
return Array.from(selectElement.options).some(option => option.value === value);
|
||||
}
|
||||
|
||||
// Apply all filters together (category, location, date), update button state, render and persist.
|
||||
// Apply all filters together (category, diet, allergie, location, date), update button state, render and persist.
|
||||
function applyFilters() {
|
||||
const selectedLocation = locationFilter ? locationFilter.value : 'ALLE_ORTE';
|
||||
const selectedDate = dateFilter ? dateFilter.value : '';
|
||||
|
||||
// Update active states for all filter types
|
||||
filterButtons.forEach(btn => {
|
||||
if (btn.getAttribute('data-cat') === activeCategory) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
const isCategoryButton = btn.getAttribute('data-cat') !== null;
|
||||
const isDietButton = btn.getAttribute('data-diet') !== null;
|
||||
const isAllergieButton = btn.getAttribute('data-allergie') !== null;
|
||||
|
||||
if (isCategoryButton) {
|
||||
if (btn.getAttribute('data-cat') === activeCategory) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
} else if (isDietButton) {
|
||||
if (activeDiets.has(btn.getAttribute('data-diet'))) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
} else if (isAllergieButton) {
|
||||
if (activeAllergies.has(btn.getAttribute('data-allergie'))) {
|
||||
btn.classList.add('active');
|
||||
} else {
|
||||
btn.classList.remove('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const filtered = allEvents.filter(event => {
|
||||
const categoryMatch = activeCategory === 'ALLE' || event.category === activeCategory;
|
||||
|
||||
// Diet filter: if no diets selected, show all. Otherwise, event MUST have at least one selected diet.
|
||||
const dietMatch = activeDiets.size === 0 ||
|
||||
(event.diet && event.diet.split(', ').some(d => activeDiets.has(d.trim())));
|
||||
|
||||
// Allergie filter: if no allergies selected, show all. Otherwise, event MUST have at least one selected allergie.
|
||||
const allergieMatch = activeAllergies.size === 0 ||
|
||||
(event.specifications && event.specifications.some(spec => activeAllergies.has(spec)));
|
||||
|
||||
const locationMatch = selectedLocation === 'ALLE_ORTE' || event.location === selectedLocation;
|
||||
const eventDateIso = parseEventDateToIso(event.date);
|
||||
const dateMatch = !selectedDate || eventDateIso === selectedDate;
|
||||
|
||||
return categoryMatch && locationMatch && dateMatch;
|
||||
return categoryMatch && dietMatch && allergieMatch && locationMatch && dateMatch;
|
||||
});
|
||||
|
||||
renderEvents(filtered);
|
||||
@ -310,6 +399,8 @@
|
||||
sessionStorage.setItem('activeFilter', activeCategory);
|
||||
sessionStorage.setItem('activeLocation', selectedLocation);
|
||||
sessionStorage.setItem('activeDate', selectedDate);
|
||||
sessionStorage.setItem('activeDiets', Array.from(activeDiets).join(','));
|
||||
sessionStorage.setItem('activeAllergies', Array.from(activeAllergies).join(','));
|
||||
}
|
||||
|
||||
// Render either:
|
||||
@ -353,10 +444,9 @@
|
||||
const displayTime = formatEventTime(event.time);
|
||||
|
||||
// Capacity logic:
|
||||
// spots = total capacity, participants.length = booked seats.
|
||||
const baseParticipants = Array.isArray(event.participants) ? event.participants.length : 0;
|
||||
const extraRegistrations = countRegistrationsForEvent(registrationMap, event.id);
|
||||
const bookedSeats = baseParticipants + extraRegistrations;
|
||||
// spots = total capacity, resolved participants = booked seats.
|
||||
const resolvedParticipants = getResolvedParticipants(event, registrationMap);
|
||||
const bookedSeats = resolvedParticipants.length;
|
||||
const totalCapacity = event.spots;
|
||||
const freePlaces = Math.max(0, totalCapacity - bookedSeats);
|
||||
const isFull = freePlaces === 0;
|
||||
@ -475,10 +565,32 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Category filter interactions.
|
||||
// Category filter interactions: mutually exclusive (radio button behavior).
|
||||
filterButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
activeCategory = button.getAttribute('data-cat');
|
||||
const categoryValue = button.getAttribute('data-cat');
|
||||
const dietValue = button.getAttribute('data-diet');
|
||||
const allergieValue = button.getAttribute('data-allergie');
|
||||
|
||||
if (categoryValue !== null) {
|
||||
// Category filter: exclusive selection
|
||||
activeCategory = categoryValue;
|
||||
} else if (dietValue !== null) {
|
||||
// Diet filter: toggle selection
|
||||
if (activeDiets.has(dietValue)) {
|
||||
activeDiets.delete(dietValue);
|
||||
} else {
|
||||
activeDiets.add(dietValue);
|
||||
}
|
||||
} else if (allergieValue !== null) {
|
||||
// Allergie filter: toggle selection
|
||||
if (activeAllergies.has(allergieValue)) {
|
||||
activeAllergies.delete(allergieValue);
|
||||
} else {
|
||||
activeAllergies.add(allergieValue);
|
||||
}
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
@ -501,6 +613,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Info button modal behavior
|
||||
const infoButton = document.getElementById('info-button');
|
||||
const infoModal = document.getElementById('info-modal');
|
||||
const modalClose = infoModal?.querySelector('.modal-close');
|
||||
|
||||
if (infoButton && infoModal) {
|
||||
infoButton.addEventListener('click', () => {
|
||||
infoModal.classList.add('show');
|
||||
});
|
||||
}
|
||||
|
||||
if (modalClose && infoModal) {
|
||||
modalClose.addEventListener('click', () => {
|
||||
infoModal.classList.remove('show');
|
||||
});
|
||||
}
|
||||
|
||||
if (infoModal) {
|
||||
infoModal.addEventListener('click', (event) => {
|
||||
if (event.target === infoModal) {
|
||||
infoModal.classList.remove('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-open info modal on first login
|
||||
if (currentUser && infoModal) {
|
||||
const hasShownInfoModal = localStorage.getItem(INFO_MODAL_SHOWN_KEY);
|
||||
if (!hasShownInfoModal) {
|
||||
infoModal.classList.add('show');
|
||||
localStorage.setItem(INFO_MODAL_SHOWN_KEY, 'true');
|
||||
}
|
||||
}
|
||||
|
||||
// Kick off initial load/render cycle.
|
||||
fetchEvents();
|
||||
});
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
const carouselTrack = document.querySelector('.gallery__track');
|
||||
const prevArrow = document.querySelector('.gallery__arrow--prev');
|
||||
const nextArrow = document.querySelector('.gallery__arrow--next');
|
||||
const dotsContainer = document.querySelector('.gallery_dots');
|
||||
const dotscontainer = document.querySelector('.gallery_dots');
|
||||
|
||||
// Nur ausführen, wenn die Galerie auf der Seite vorhanden ist.
|
||||
if (carouselTrack) {
|
||||
@ -22,8 +22,8 @@ if (carouselTrack) {
|
||||
var dots = [];
|
||||
|
||||
function buildDots() {
|
||||
if (!dotsContainer) return;
|
||||
dotsContainer.innerHTML = '';
|
||||
if (!dotscontainer) return;
|
||||
dotscontainer.innerHTML = '';
|
||||
dots = [];
|
||||
for (var i = 0; i < pageCount; i++) {
|
||||
var dot = document.createElement('button');
|
||||
@ -36,7 +36,7 @@ if (carouselTrack) {
|
||||
dot.addEventListener('click', function() {
|
||||
goToPage(parseInt(this.dataset.page));
|
||||
});
|
||||
dotsContainer.appendChild(dot);
|
||||
dotscontainer.appendChild(dot);
|
||||
dots.push(dot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,9 @@
|
||||
const profileTabPanels = Array.from(document.querySelectorAll('[data-profile-panel]'));
|
||||
|
||||
const myEventsCount = document.getElementById('my-events-count');
|
||||
const myEventsBtnCount = document.getElementById('btn-my-events-count');
|
||||
const myRegistrationsCount = document.getElementById('my-registrations-count');
|
||||
const myRegistrationsBtnCount = document.getElementById('btn-my-registrations-count');
|
||||
const myEventsList = document.getElementById('my-events-list');
|
||||
const myRegistrationsList = document.getElementById('my-registrations-list');
|
||||
|
||||
@ -459,28 +461,37 @@
|
||||
return events.filter(event => idSet.has(Number(event.id)));
|
||||
}
|
||||
|
||||
// Rendert gehostete Events inkl. Zähler.
|
||||
// Rendert angemeldete Events inkl. Zähler.
|
||||
function renderMyEvents(events, user) {
|
||||
const hostedEvents = getMyHostedEvents(events, user);
|
||||
myEventsCount.textContent = String(hostedEvents.length);
|
||||
renderEventCards(myEventsList, hostedEvents, {
|
||||
title: 'Noch kein eigenes Event',
|
||||
text: 'Starte dein erstes Dinner und lade die Community an deinen Tisch ein.',
|
||||
buttonLabel: 'Event erstellen',
|
||||
href: 'event_create.html'
|
||||
}, 'hosting');
|
||||
const hostedEvents = getMyHostedEvents(events, user);
|
||||
const count = hostedEvents.length;
|
||||
|
||||
myEventsCount.textContent = String(count);
|
||||
if (myEventsBtnCount) myEventsBtnCount.textContent = String(count);
|
||||
|
||||
renderEventCards(myEventsList, hostedEvents, {
|
||||
title: 'Noch kein eigenes Event',
|
||||
text: 'Starte dein erstes Dinner und lade die Community an deinen Tisch ein.',
|
||||
buttonLabel: 'Event erstellen',
|
||||
href: 'event_create.html'
|
||||
}, 'hosting');
|
||||
}
|
||||
|
||||
// Rendert angemeldete Events inkl. Zähler.
|
||||
function renderMyRegistrations(events, user) {
|
||||
const registeredEvents = getMyRegisteredEvents(events, user);
|
||||
myRegistrationsCount.textContent = String(registeredEvents.length);
|
||||
renderEventCards(myRegistrationsList, registeredEvents, {
|
||||
title: 'Noch keine Anmeldungen',
|
||||
text: 'Entdecke spannende Dinner in deiner Naehe und melde dich direkt an.',
|
||||
buttonLabel: 'Events entdecken',
|
||||
href: 'event_overview.html'
|
||||
}, 'registrations');
|
||||
const registeredEvents = getMyRegisteredEvents(events, user);
|
||||
|
||||
const count = registeredEvents.length;
|
||||
|
||||
myRegistrationsCount.textContent = String(count);
|
||||
if (myRegistrationsBtnCount) myRegistrationsBtnCount.textContent = String(count);
|
||||
|
||||
renderEventCards(myRegistrationsList, registeredEvents, {
|
||||
title: 'Noch keine Anmeldungen',
|
||||
text: 'Entdecke spannende Dinner in deiner Naehe und melde dich direkt an.',
|
||||
buttonLabel: 'Events entdecken',
|
||||
href: 'event_overview.html'
|
||||
}, 'registrations');
|
||||
}
|
||||
|
||||
// Baut die Eventkarten für beide Listen in einheitlichem Markup.
|
||||
@ -538,7 +549,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Gibt true zurück, wenn ein Event innerhalb der nächsten 12 Stunden startet.
|
||||
// Gibt true zurück, wenn ein Event innerhalb der nächsten 24 Stunden startet.
|
||||
function isAddressVisibleWindow(event) {
|
||||
const eventDateTime = parseEventDateTime(event);
|
||||
if (!eventDateTime || Number.isNaN(eventDateTime.getTime())) {
|
||||
@ -546,7 +557,7 @@
|
||||
}
|
||||
|
||||
const msUntilStart = eventDateTime.getTime() - Date.now();
|
||||
const twentyfourHoursInMs = 12 * 60 * 60 * 1000;
|
||||
const twentyfourHoursInMs = 24 * 60 * 60 * 1000;
|
||||
|
||||
return msUntilStart >= 0 && msUntilStart <= twentyfourHoursInMs;
|
||||
}
|
||||
|
||||
@ -6,11 +6,11 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const CURRENT_USER_KEY = 'socialCookingCurrentUser';
|
||||
const navContainers = document.querySelectorAll('.nav-tab-links');
|
||||
const navcontainers = document.querySelectorAll('.nav-tab-links');
|
||||
const currentPage = (window.location.pathname.split('/').pop() || 'index.html').toLowerCase();
|
||||
|
||||
// Beendet früh, falls auf einer Seite keine Hauptnavigation vorhanden ist.
|
||||
if (!navContainers.length) {
|
||||
if (!navcontainers.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const nextMarkup = currentUser ? buildLoggedInNavigation(currentUser) : buildLoggedOutNavigation();
|
||||
|
||||
// Wendet das passende Markup auf alle vorhandenen Kopf-Navigationen an.
|
||||
navContainers.forEach(container => {
|
||||
navcontainers.forEach(container => {
|
||||
container.innerHTML = nextMarkup;
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="main-content">
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<div class="image-section">
|
||||
<img src="assets/index_cooking.jpg" alt="Social Cooking">
|
||||
@ -56,7 +56,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- Schliesst main-content -->
|
||||
</div> <!-- Schliesst container -->
|
||||
<div class="snackbar" id="snackbar">Willkommen zurück! Du wirst weitergeleitet...</div>
|
||||
<script src="js/login.js"></script>
|
||||
<div class="footer">
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container profile-page">
|
||||
<main class="layout-wide">
|
||||
<section class="profile-hero" aria-label="Profilübersicht">
|
||||
<div>
|
||||
<p class="badge">Mein Bereich</p>
|
||||
@ -49,8 +49,13 @@
|
||||
|
||||
<section id="logged-in-content" class="profile-grid">
|
||||
<nav class="category-items" aria-label="Profilbereiche">
|
||||
<button type="button" class="category-item is-active category-item-profile" data-category-item="hosting">Meine Events</button>
|
||||
<button type="button" class="category-item category-item-profile" data-category-item="teilnehmen">Meine Anmeldungen</button>
|
||||
<button type="button" class="category-item is-active category-item-profile" data-category-item="hosting">
|
||||
Meine Events <span class="btn-count" id="btn-my-events-count">0</span>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="category-item category-item-profile" data-category-item="teilnehmen">
|
||||
Meine Anmeldungen <span class="btn-count" id="btn-my-registrations-count">0</span>
|
||||
</button>
|
||||
<button type="button" class="category-item category-item-profile" data-category-item="einstellungen">Profil-Einstellungen</button>
|
||||
</nav>
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="main-content">
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<div class="image-section">
|
||||
<img src="assets/index_cooking.jpg" alt="Social Cooking">
|
||||
@ -73,7 +73,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- Schliesst main-content -->
|
||||
</div> <!-- Schliesst container -->
|
||||
|
||||
<!-- Welcome Modal -->
|
||||
<div id="welcomeModal" class="modal">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user