Add snackbar feedback, logout modal, profile pill nav, calendar styling, fix image paths and signup flow
This commit is contained in:
parent
221aa90649
commit
4b54c48311
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"chat.tools.terminal.autoApprove": {
|
||||||
|
"git remote": true,
|
||||||
|
"git push": true,
|
||||||
|
"ssh": true,
|
||||||
|
"git add": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -147,6 +147,33 @@
|
|||||||
outline-offset: 1px;
|
outline-offset: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.meta-filter input[type="date"] {
|
||||||
|
color-scheme: light;
|
||||||
|
accent-color: var(--olive);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-filter input[type="date"]::-webkit-calendar-picker-indicator {
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
filter: invert(35%) sepia(60%) saturate(600%) hue-rotate(22deg) brightness(90%) contrast(95%);
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-filter input[type="date"]::-webkit-calendar-picker-indicator:hover {
|
||||||
|
background-color: var(--olive-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-filter select {
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%236B6B05' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
padding-right: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------
|
/* ---------------------------------------------------------
|
||||||
Overview Event Cards
|
Overview Event Cards
|
||||||
--------------------------------------------------------- */
|
--------------------------------------------------------- */
|
||||||
|
|||||||
@ -327,6 +327,114 @@ p {
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modal / Popup */
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
animation: modalFadeIn 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes modalFadeIn {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.show {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: var(--white);
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
text-align: center;
|
||||||
|
animation: modalSlideIn 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes modalSlideIn {
|
||||||
|
from { transform: translateY(-50px); opacity: 0; }
|
||||||
|
to { transform: translateY(0); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header h2 {
|
||||||
|
color: var(--olive);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
color: var(--black);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
color: var(--black);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Snackbar */
|
||||||
|
.snackbar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) translateY(100px);
|
||||||
|
background: var(--olive);
|
||||||
|
color: var(--white);
|
||||||
|
padding: var(--space-3) var(--space-6);
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: var(--font-main);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
||||||
|
opacity: 0;
|
||||||
|
transition: transform 0.4s ease, opacity 0.4s ease;
|
||||||
|
z-index: 9999;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snackbar--visible {
|
||||||
|
transform: translateX(-50%) translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snackbar--danger {
|
||||||
|
background: var(--tomato);
|
||||||
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
.footer {
|
.footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -64,8 +64,13 @@
|
|||||||
<section id="event-grid" class="event-list"></section>
|
<section id="event-grid" class="event-list"></section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Page logic: data loading, filtering and card rendering -->
|
<!-- Seitenlogik: Daten laden, filtern und Event-Karten rendern -->
|
||||||
<script src="js/event_overview.js"></script>
|
<script src="js/event_overview.js"></script>
|
||||||
|
|
||||||
|
<!-- Snackbar: Feedback bei An-/Abmeldung -->
|
||||||
|
<div class="snackbar" id="snackbar"></div>
|
||||||
|
|
||||||
|
<!-- Instagram Einladung -->
|
||||||
<div class="instagram-invite">
|
<div class="instagram-invite">
|
||||||
<a href="https://www.instagram.com" target="_blank" rel="noopener noreferrer" class="instagram-invite__link">
|
<a href="https://www.instagram.com" target="_blank" rel="noopener noreferrer" class="instagram-invite__link">
|
||||||
<img src="assets/Icon_instagram.png" alt="Instagram" class="instagram-invite__icon" />
|
<img src="assets/Icon_instagram.png" alt="Instagram" class="instagram-invite__icon" />
|
||||||
|
|||||||
@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const filterButtons = document.querySelectorAll('.category-item');
|
const filterButtons = document.querySelectorAll('.category-item');
|
||||||
const locationFilter = document.getElementById('location-filter');
|
const locationFilter = document.getElementById('location-filter');
|
||||||
const dateFilter = document.getElementById('date-filter');
|
const dateFilter = document.getElementById('date-filter');
|
||||||
const locationIconPath = 'assets/location-pin.svg';
|
const locationIconPath = 'assets/icon_location-pin.svg';
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// In-memory state for fetched events and currently active category.
|
// In-memory state for fetched events and currently active category.
|
||||||
@ -329,7 +329,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<p class="empty-state-kicker">Keine Treffer</p>
|
<p class="empty-state-kicker">Keine Treffer</p>
|
||||||
<h3>Schade, aktuell gibt es hier keine Events.</h3>
|
<h3>Schade, aktuell gibt es hier keine Events.</h3>
|
||||||
<p>Starte dein eigenes Dinner und bringe die Community an deinen Tisch.</p>
|
<p>Starte dein eigenes Event und bringe die Community an deinen Tisch.</p>
|
||||||
<a class="empty-state-link" href="event_create.html">
|
<a class="empty-state-link" href="event_create.html">
|
||||||
<button class="empty-state-btn" type="button">Event erstellen</button>
|
<button class="empty-state-btn" type="button">Event erstellen</button>
|
||||||
</a>
|
</a>
|
||||||
@ -435,12 +435,29 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
: [];
|
: [];
|
||||||
const idSet = new Set(currentIds);
|
const idSet = new Set(currentIds);
|
||||||
|
|
||||||
|
// Abmeldung: Benutzer vom Event entfernen und Snackbar anzeigen.
|
||||||
if (action === 'unregister') {
|
if (action === 'unregister') {
|
||||||
idSet.delete(Number(event.id));
|
idSet.delete(Number(event.id));
|
||||||
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
if (snackbar) {
|
||||||
|
snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
|
||||||
|
snackbar.classList.add('snackbar--danger', 'snackbar--visible');
|
||||||
|
setTimeout(() => {
|
||||||
|
snackbar.classList.remove('snackbar--visible');
|
||||||
|
setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anmeldung: Benutzer zum Event hinzufuegen und Snackbar anzeigen.
|
||||||
if (action === 'register' && !isFull && !isRegistrationClosed) {
|
if (action === 'register' && !isFull && !isRegistrationClosed) {
|
||||||
idSet.add(Number(event.id));
|
idSet.add(Number(event.id));
|
||||||
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
if (snackbar) {
|
||||||
|
snackbar.textContent = 'Du wurdest erfolgreich angemeldet.';
|
||||||
|
snackbar.classList.add('snackbar--visible');
|
||||||
|
setTimeout(() => snackbar.classList.remove('snackbar--visible'), 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRegistrationMap[currentUser.email] = Array.from(idSet);
|
nextRegistrationMap[currentUser.email] = Array.from(idSet);
|
||||||
|
|||||||
@ -148,11 +148,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
logoutButton.addEventListener('click', () => {
|
logoutButton.addEventListener('click', () => {
|
||||||
localStorage.removeItem(CURRENT_USER_KEY);
|
const logoutModal = document.getElementById('logoutModal');
|
||||||
window.location.href = 'login.html';
|
logoutModal.classList.add('show');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Globale Funktionen fuer das Logout-Modal.
|
||||||
|
window.closeLogoutModal = function() {
|
||||||
|
const logoutModal = document.getElementById('logoutModal');
|
||||||
|
logoutModal.classList.remove('show');
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
};
|
||||||
|
|
||||||
|
window.confirmLogout = function() {
|
||||||
|
localStorage.removeItem(CURRENT_USER_KEY);
|
||||||
|
window.location.href = 'index.html';
|
||||||
|
};
|
||||||
|
|
||||||
// Reagiert auf Aktionen in der Liste "Meine Events" per Event Delegation.
|
// Reagiert auf Aktionen in der Liste "Meine Events" per Event Delegation.
|
||||||
function handleHostedListClick(event) {
|
function handleHostedListClick(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
@ -219,6 +232,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unregisterFromEvent(eventId, currentUser.email);
|
unregisterFromEvent(eventId, currentUser.email);
|
||||||
|
|
||||||
|
// Snackbar: Feedback bei erfolgreicher Abmeldung.
|
||||||
|
const snackbar = document.getElementById('snackbar');
|
||||||
|
if (snackbar) {
|
||||||
|
snackbar.textContent = 'Du wurdest erfolgreich abgemeldet.';
|
||||||
|
snackbar.classList.add('snackbar--danger', 'snackbar--visible');
|
||||||
|
setTimeout(() => {
|
||||||
|
snackbar.classList.remove('snackbar--visible');
|
||||||
|
setTimeout(() => snackbar.classList.remove('snackbar--danger'), 400);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,8 +31,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const signupIsActive = currentPage === 'signup.html';
|
const signupIsActive = currentPage === 'signup.html';
|
||||||
const isIndex = currentPage === 'index.html' || currentPage === '';
|
const isIndex = currentPage === 'index.html' || currentPage === '';
|
||||||
|
|
||||||
// Auf der Startseite nur Login anzeigen.
|
// Auf der Startseite, Login und Signup nur Login anzeigen.
|
||||||
if (isIndex) {
|
if (isIndex || loginIsActive || signupIsActive) {
|
||||||
return `
|
return `
|
||||||
<a
|
<a
|
||||||
class="button-small"
|
class="button-small"
|
||||||
@ -61,20 +61,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
>
|
>
|
||||||
Signup
|
Signup
|
||||||
</a>
|
</a>
|
||||||
`;`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baut die Navigation fuer eingeloggte Benutzer.
|
// Baut die Navigation fuer eingeloggte Benutzer.
|
||||||
function buildLoggedInNavigation() {
|
function buildLoggedInNavigation(user) {
|
||||||
|
const initial = (user.vorname || 'U').charAt(0).toUpperCase();
|
||||||
|
const isEventOverview = currentPage === 'event_overview.html';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<a class="nav-tab" href="event_overview.html">Event finden</a>
|
${isEventOverview ? '' : '<a class="nav-tab" href="event_overview.html">Event finden</a>'}
|
||||||
<a class="nav-tab" href="event_create.html">Event erstellen</a>
|
<a class="button-small" href="event_create.html">Event erstellen</a>
|
||||||
<a class="button-small" href="my_profil.html" aria-label="Mein Profil">Mein Profil</a>
|
<a class="profile-pill" href="my_profil.html" aria-label="Mein Profil" title="${user.vorname || 'Profil'}">${initial}</a>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentUser = getCurrentUser();
|
const currentUser = getCurrentUser();
|
||||||
const nextMarkup = currentUser ? buildLoggedInNavigation() : buildLoggedOutNavigation();
|
const nextMarkup = currentUser ? buildLoggedInNavigation(currentUser) : buildLoggedOutNavigation();
|
||||||
|
|
||||||
// Wendet das passende Markup auf alle vorhandenen Kopf-Navigationen an.
|
// Wendet das passende Markup auf alle vorhandenen Kopf-Navigationen an.
|
||||||
navContainers.forEach(container => {
|
navContainers.forEach(container => {
|
||||||
|
|||||||
@ -46,6 +46,7 @@ function openWelcomeModal() {
|
|||||||
function closeWelcomeModal() {
|
function closeWelcomeModal() {
|
||||||
welcomeModal.classList.remove('show');
|
welcomeModal.classList.remove('show');
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.overflow = 'auto';
|
||||||
|
window.location.href = 'event_overview.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hauptfunktion fuer Formularvalidierung und Speicherung.
|
// Hauptfunktion fuer Formularvalidierung und Speicherung.
|
||||||
@ -138,10 +139,7 @@ function validateForm(event) {
|
|||||||
setCurrentUser(newUser);
|
setCurrentUser(newUser);
|
||||||
|
|
||||||
openWelcomeModal();
|
openWelcomeModal();
|
||||||
// Hier koennte spaeter ein echter API-Call zum Backend stehen.
|
// Weiterleitung erfolgt beim Klick auf "Weiter zu den Events".
|
||||||
|
|
||||||
// Weiterleitung zur Event-Overview-Seite.
|
|
||||||
window.location.href = 'event_overview.html';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,8 +20,7 @@
|
|||||||
<img src="assets/logo_invite.svg" alt="Invité">
|
<img src="assets/logo_invite.svg" alt="Invité">
|
||||||
</a>
|
</a>
|
||||||
<nav class="nav-tab-links" aria-label="Hauptnavigation">
|
<nav class="nav-tab-links" aria-label="Hauptnavigation">
|
||||||
<a class="button-small auth-nav-button auth-nav-button--active" href="login.html" aria-label="Login" aria-current="page">Login</a>
|
<a class="button-small" href="login.html" aria-label="Login">Login</a>
|
||||||
<a class="button-small auth-nav-button auth-nav-button--default" href="signup.html" aria-label="Signup">Signup</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -30,7 +29,7 @@
|
|||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="image-section">
|
<div class="image-section">
|
||||||
<img src="assets/cooking.jpg" alt="Social Cooking">
|
<img src="assets/index_cooking.jpg" alt="Social Cooking">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
|
|||||||
@ -103,6 +103,26 @@
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<!-- Logout Confirmation Modal -->
|
||||||
|
<div id="logoutModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button class="close-btn" onclick="closeLogoutModal()">×</button>
|
||||||
|
<h2>Abmelden?</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Bist du sicher, dass du dich abmelden möchtest?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button button--outline" type="button" onclick="closeLogoutModal()">Abbrechen</button>
|
||||||
|
<button class="button" type="button" onclick="confirmLogout()">Abmelden</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Snackbar: Feedback bei Abmeldung von Events -->
|
||||||
|
<div class="snackbar" id="snackbar"></div>
|
||||||
|
|
||||||
<script src="js/my_profil.js"></script>
|
<script src="js/my_profil.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
11
signup.html
11
signup.html
@ -20,8 +20,7 @@
|
|||||||
<img src="assets/logo_invite.svg" alt="Invite Logo">
|
<img src="assets/logo_invite.svg" alt="Invite Logo">
|
||||||
</a>
|
</a>
|
||||||
<nav class="nav-tab-links" aria-label="Hauptnavigation">
|
<nav class="nav-tab-links" aria-label="Hauptnavigation">
|
||||||
<a class="button-small auth-nav-button auth-nav-button--default" href="login.html" aria-label="Login">Login</a>
|
<a class="button-small" href="login.html" aria-label="Login">Login</a>
|
||||||
<a class="button-small auth-nav-button auth-nav-button--active" href="signup.html" aria-label="Signup" aria-current="page">Signup</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -30,7 +29,7 @@
|
|||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="image-section">
|
<div class="image-section">
|
||||||
<img src="assets/cooking.jpg" alt="Social Cooking">
|
<img src="assets/index_cooking.jpg" alt="Social Cooking">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
@ -81,13 +80,13 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button class="close-btn" onclick="closeWelcomeModal()">×</button>
|
<button class="close-btn" onclick="closeWelcomeModal()">×</button>
|
||||||
<h2>🎉 Willkommen bei Invité!</h2>
|
<h2>Konto erfolgreich erstellt!</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Hier findest du die Übersicht zu den aktuellsten Events.
|
Willkommen bei Invité! Dein Account wurde erfolgreich erstellt. Entdecke jetzt die neuesten Events in deiner Nähe.
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn-primary" onclick="closeWelcomeModal()">Weiter zu den Events</button>
|
<button class="button" onclick="closeWelcomeModal()">Weiter zu den Events</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user