diff --git a/assets/css/custom.css b/assets/css/custom.css index e69de29..a9b6183 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -0,0 +1,215 @@ + +body { + background: #f0f4f8; + color: #1b1b2f; + font-family: 'Gill Sans', 'Gill Sans MT', 'Calibri', 'Trebuchet MS', sans-serif; + line-height: 1.6; + margin-bottom: 1rem; + padding: 0; +} + +/* Navigation Styles */ +.navbar { + background: linear-gradient(90deg, #1b1b2f, #4a6fa5) +} +.navbar .nav-link { + color: #fff; + transition: color 0.3s, background-color 0.3s; + margin: 0 5px; +} +.navbar .nav-link:hover { + background-color: #ffd166; + color: #1b1b2f; + border-radius: 6px; + padding: 5px 10px; +} + +.navbar .nav-link.active { + background-color: #ffd166; + color: #1b1b2f; + font-weight: bold; + border-radius: 6px; + padding: 5px 10px; +} + +/* Main content styles */ +.container-dashboard { + flex-wrap: wrap; + justify-content: center; + gap: 20px; + padding: 20px; +} +/* Cards/Scores styles */ +.container > div:not(.modal) { + background-color:#ffffff; + border-radius: 12px; + box-shadow: 0 4px 15px rgba(0,0,0,0.1); + padding: 25px; + font-size: 30px; + flex: 1 1 100%; + text-align: center; + transition: transform 0.3s, box-shadow 0.3s; +} +.container > div:not(.modal):hover { + transform: translateY(-5px); + box-shadow: 0 10px 25px rgba(0,0,0,0.2); +} + +/* Keep Bootstrap modal sizing/layout intact */ +#password-modal { + padding: 0; + background: transparent; + box-shadow: none; + border-radius: 0; + font-size: 1rem; +} + +#password-modal .modal-dialog { + max-width: 560px; +} + +/* Überschriften und Abstände */ +h1, h2, h3, h4, h5, h6 { + margin-top: 1rem; + margin-bottom: 20px; + color: #1b1b2f; +} +p { + margin-top: 0.5rem; + margin-bottom: 1rem; + color: #333; +} +/* Button Styles */ +.btn { + background-color: #4a6fa5; + color: #fff; + border: none; + padding: 10px 20px; + border-radius: 6px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; +} +.btn:hover { + background-color: #2b4a7c; +} +.btn-danger { + background-color: #a84848; + color: #fff; + border: none; + padding: 10px 20px; + border-radius: 6px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; +} +.btn-danger:hover { + background-color: #8a3b3b; +} +#page-wrapper { + display: flex; + min-height: 100vh; + font-family: 'Segoe UI', sans-serif; +} +/* Sidebar Styles */ +#sidebar { + width: 240px; + min-height: auto; + background: linear-gradient(180deg, #1b1b2f, #4a6fa5); + color: white; + padding: 25px; +} +#sidebar .nav-link { + margin: 0.5rem 0; + transition: color 0.3s, background-color 0.3s; + color: white; + padding: 5px 10px; + border-radius: 6x; +} +#sidebar .nav-link:hover { + color: #1b1b2f; + border-radius: 6px; +} +#sidebar .nav-link.active { + color: #1b1b2f; + font-weight: bold; + background-color: #ffd166; + border-radius: 6px; + padding: 5px 10px; +} +#logo-img { + max-width: 500px; + width: 100%; + height: auto; +} +#main-area { + flex: 1; + background: #f3f4f6; + display: flex; + flex-direction: column; +} +/* Topbar Styles */ +#topbar { + height: 70px; + background: white; + padding: 0px 30px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} +#main-content { + background-color: #f0f4f8; + padding: 30px; +} +/* Card Styles */ +.card { + background: white; + border-radius: 12px; + box-shadow: 0 5px 15px rgba(0,0,0,0.08); + padding: 25px; + margin-bottom: 20px; +} +.card h2 { + margin-bottom: 10px; +} + +/* Responsive Styles */ +@media (max-width: 768px) { + body { + font-size: 0.9rem; + } + .container > div:not(.modal) { + flex: 1 1 calc(50% - 40px); + } + #page-wrapper { + flex-direction: column; + } + #sidebar { + width: 100%; + display: flex; + overflow-x: auto; + } + #sidebar .nav-link { + flex: 0 0 auto; + margin: 0 10px; + } +} +@media (min-width: 1200px) { + body { + font-size: 1.1rem; + } + .container > div:not(.modal) { + flex: 1 1 calc(25% - 40px); + } + p.columns{ + column-count: 2; + column-gap: 2rem; + } + #sidebar .nav-link { + flex: 0 0 auto; + margin: 0 15px; + } + +} + diff --git a/image/Logo_loremIpsum.png b/image/Logo_loremIpsum.png new file mode 100644 index 0000000..2e2b42c Binary files /dev/null and b/image/Logo_loremIpsum.png differ diff --git a/image/icon_l.png b/image/icon_l.png new file mode 100644 index 0000000..84ae9f7 Binary files /dev/null and b/image/icon_l.png differ diff --git a/image/icon_loremIpsum.png b/image/icon_loremIpsum.png new file mode 100644 index 0000000..012b05d Binary files /dev/null and b/image/icon_loremIpsum.png differ diff --git a/image/icon_loremIpsum2.png b/image/icon_loremIpsum2.png new file mode 100644 index 0000000..df644c9 Binary files /dev/null and b/image/icon_loremIpsum2.png differ diff --git a/index.html b/index.html index 5ea1fd1..d9b72dd 100644 --- a/index.html +++ b/index.html @@ -1,21 +1,65 @@ - My Web Page + + Lorem Ipsum - Das Spiel + + + -

Hello From Main Page

- Go to Main Page - Go to Second Page -
+ + +
+ + + +
+ +
+

Dashboard

+
+ + +
+
+
+ + - + + + + + + + + \ No newline at end of file diff --git a/js/login.js b/js/login.js new file mode 100644 index 0000000..73aaf38 --- /dev/null +++ b/js/login.js @@ -0,0 +1,288 @@ +(function () { + const AUTH_STORAGE_KEY = "loremIpsumAuth"; + + function readAuth() { + const raw = localStorage.getItem(AUTH_STORAGE_KEY); + if (!raw) { + return null; + } + + try { + const parsed = JSON.parse(raw); + if (!parsed.username || !parsed.password) { + return null; + } + return parsed; + } catch { + return null; + } + } + + function saveAuth(username, password) { + localStorage.setItem( + AUTH_STORAGE_KEY, + JSON.stringify({ username: username, password: password }), + ); + } + + function clearAuth() { + localStorage.removeItem(AUTH_STORAGE_KEY); + } + + function updateHeaderUsername() { + const usernameDisplay = document.getElementById("username-display"); + const navbarLogin = document.getElementById("navbar-login"); + const auth = readAuth(); + + if (usernameDisplay) { + usernameDisplay.textContent = auth ? "User: " + auth.username : "User: Guest"; + } + + if (navbarLogin) { + navbarLogin.textContent = auth ? auth.username : "Login / Registrieren"; + } + } + + function setFeedback(message, type) { + const feedback = document.getElementById("auth-feedback"); + if (!feedback) { + return; + } + + feedback.className = "alert alert-" + type; + feedback.textContent = message; + feedback.classList.remove("d-none"); + } + + function updateSessionBox() { + const sessionText = document.getElementById("current-session-text"); + const logoutButton = document.getElementById("logout-button"); + const deleteAccountButton = document.getElementById("delete-account-button"); + const currentSessionBox = document.getElementById("current-session-box"); + const authFormsRow = document.getElementById("auth-forms-row"); + + if (!sessionText || !logoutButton || !deleteAccountButton || !currentSessionBox || !authFormsRow) { + return; + } + + const auth = readAuth(); + if (auth) { + sessionText.textContent = "Eingeloggt als " + auth.username + "."; + logoutButton.disabled = false; + deleteAccountButton.disabled = false; + currentSessionBox.classList.remove("d-none"); + authFormsRow.classList.add("d-none"); + } else { + sessionText.textContent = "Nicht eingeloggt."; + logoutButton.disabled = true; + deleteAccountButton.disabled = true; + currentSessionBox.classList.add("d-none"); + authFormsRow.classList.remove("d-none"); + } + } + + function getUserService() { + if (!window.config || !window.UserService) { + return null; + } + + return new window.UserService(window.config); + } + + async function handleLoginSubmit(event) { + event.preventDefault(); + + const userService = getUserService(); + if (!userService) { + setFeedback("User-Service konnte nicht geladen werden.", "danger"); + return; + } + + const usernameInput = document.getElementById("login-username"); + const passwordInput = document.getElementById("login-password"); + const username = usernameInput.value.trim(); + const password = passwordInput.value.trim(); + + if (!username || !password) { + setFeedback("Bitte Username und Passwort eingeben.", "warning"); + return; + } + + const result = await userService.getUser(username, password); + if (result.ok) { + saveAuth(username, password); + setFeedback("Login erfolgreich.", "success"); + updateSessionBox(); + updateHeaderUsername(); + setTimeout(function() { + if (typeof window.loadPage === "function") { + window.loadPage("home", "nav-home"); + } + }, 500); + return; + } + + if (result.status === 401) { + setFeedback("Login fehlgeschlagen: Username oder Passwort ist falsch.", "danger"); + return; + } + + setFeedback("Login fehlgeschlagen (Status " + result.status + ").", "danger"); + } + + async function handleRegisterSubmit(event) { + event.preventDefault(); + + const userService = getUserService(); + if (!userService) { + setFeedback("User-Service konnte nicht geladen werden.", "danger"); + return; + } + + const usernameInput = document.getElementById("register-username"); + const username = usernameInput.value.trim(); + + if (!username) { + setFeedback("Bitte einen Username eingeben.", "warning"); + return; + } + + const result = await userService.postUser(username); + if (result.ok && result.body) { + const createdName = result.body.name || username; + const createdPassword = result.body.password || ""; + + saveAuth(createdName, createdPassword); + updateSessionBox(); + updateHeaderUsername(); + + // Modal mit Daten füllen und anzeigen + const modalUsername = document.getElementById("modal-username"); + const modalPassword = document.getElementById("modal-password"); + if (modalUsername) modalUsername.textContent = createdName; + if (modalPassword) modalPassword.textContent = createdPassword; + + const passwordModalElement = document.getElementById("password-modal"); + if (passwordModalElement) { + const passwordModal = new window.bootstrap.Modal(passwordModalElement); + + // Listener für Modals-Schließen: zur Startseite navigieren + passwordModalElement.addEventListener("hidden.bs.modal", function handleClose() { + if (typeof window.loadPage === "function") { + window.loadPage("home", "nav-home"); + } + passwordModalElement.removeEventListener("hidden.bs.modal", handleClose); + }); + + passwordModal.show(); + } else { + // Fallback wenn Modal nicht gefunden + setFeedback( + "Account erstellt. Username: " + createdName + ", Passwort: " + createdPassword, + "success", + ); + setTimeout(function() { + if (typeof window.loadPage === "function") { + window.loadPage("home", "nav-home"); + } + }, 1500); + } + + const loginUsernameInput = document.getElementById("login-username"); + const loginPasswordInput = document.getElementById("login-password"); + if (loginUsernameInput && loginPasswordInput) { + loginUsernameInput.value = createdName; + loginPasswordInput.value = createdPassword; + } + + return; + } + + if (result.status === 400) { + const errorMessage = result.body && result.body.message + ? result.body.message + : "Dieser Username existiert bereits."; + setFeedback(errorMessage, "danger"); + return; + } + + setFeedback( + "Account konnte nicht erstellt werden (Status " + result.status + ").", + "danger", + ); + } + + function handleLogout() { + clearAuth(); + setFeedback("Du wurdest ausgeloggt.", "info"); + updateSessionBox(); + updateHeaderUsername(); + } + + async function handleDeleteAccount() { + const auth = readAuth(); + if (!auth) { + setFeedback("Du bist nicht eingeloggt.", "warning"); + return; + } + + const wantsDelete = window.confirm( + "Möchtest du den Account \"" + auth.username + "\" wirklich löschen?", + ); + if (!wantsDelete) { + return; + } + + const userService = getUserService(); + if (!userService) { + setFeedback("User-Service konnte nicht geladen werden.", "danger"); + return; + } + + const result = await userService.deleteUser(auth.username, auth.password); + if (result.ok) { + clearAuth(); + updateSessionBox(); + updateHeaderUsername(); + setFeedback("Account wurde gelöscht.", "success"); + return; + } + + if (result.status === 401) { + setFeedback("Account konnte nicht gelöscht werden: nicht autorisiert.", "danger"); + return; + } + + setFeedback( + "Account konnte nicht gelöscht werden (Status " + result.status + ").", + "danger", + ); + } + + function initLoginPage() { + const loginForm = document.getElementById("login-form"); + const registerForm = document.getElementById("register-form"); + const logoutButton = document.getElementById("logout-button"); + const deleteAccountButton = document.getElementById("delete-account-button"); + + if (!loginForm || !registerForm || !logoutButton || !deleteAccountButton) { + return; + } + + loginForm.addEventListener("submit", handleLoginSubmit); + registerForm.addEventListener("submit", handleRegisterSubmit); + logoutButton.addEventListener("click", handleLogout); + deleteAccountButton.addEventListener("click", handleDeleteAccount); + + updateSessionBox(); + updateHeaderUsername(); + } + + window.initLoginPage = initLoginPage; + window.AppAuth = { + getAuth: readAuth, + clearAuth: clearAuth, + }; + + document.addEventListener("DOMContentLoaded", updateHeaderUsername); +})(); diff --git a/js/navigation.js b/js/navigation.js new file mode 100644 index 0000000..6111ac0 --- /dev/null +++ b/js/navigation.js @@ -0,0 +1,49 @@ +document.addEventListener("DOMContentLoaded", () => { + function setActiveMenu(id) { + //Alle Sidebar-Links zurücksetzen + document.querySelectorAll("#sidebar .nav-link").forEach(link => link.classList.remove("active")); + // Alle Navbar-Links zurücksetzen + document.querySelectorAll(".navbar-nav .nav-link").forEach(link => link.classList.remove("active")); + + //Aktiven Link setzen + const activeLink = document.getElementById(id); + if (activeLink) activeLink.classList.add("active"); + } + window.loadPage = function loadPage(page, menuId) { + fetch("pages/" + page + ".html") + .then(response => { + if (!response.ok) { + throw new Error("HTTP " + response.status); + } + return response.text(); + }) + .then(data => { + document.getElementById("main-content").innerHTML = data; + setActiveMenu(menuId); + if (page === "login" && typeof window.initLoginPage === "function") { + window.initLoginPage(); + } + }) + .catch(error => { + console.error("Fehler beim Laden von " + page + ":", error); + document.getElementById("main-content").innerHTML = "
Fehler beim Laden der Seite: " + error.message + "
"; + }); + }; + + const navHome = document.getElementById("nav-home"); + const navPlay = document.getElementById("nav-play"); + const navMyScores = document.getElementById("nav-my-scores"); + const navLeaderboard = document.getElementById("nav-leaderboard"); + const navbarLogin = document.getElementById("navbar-login"); + const navbarMessages = document.getElementById("navbar-messages"); + + if (navHome) navHome.onclick = (e) => { e.preventDefault(); loadPage("home", "nav-home"); }; + if (navPlay) navPlay.onclick = (e) => { e.preventDefault(); loadPage("play", "nav-play"); }; + if (navMyScores) navMyScores.onclick = (e) => { e.preventDefault(); loadPage("scores", "nav-my-scores"); }; + if (navLeaderboard) navLeaderboard.onclick = (e) => { e.preventDefault(); loadPage("leaderboard", "nav-leaderboard"); }; + if (navbarLogin) navbarLogin.onclick = (e) => { e.preventDefault(); loadPage("login", "navbar-login"); }; + if (navbarMessages) navbarMessages.onclick = (e) => { e.preventDefault(); loadPage("messages", "navbar-messages"); }; + + //Startseite laden + loadPage("home", "nav-home"); +}); \ No newline at end of file diff --git a/pages/home.html b/pages/home.html new file mode 100644 index 0000000..731056c --- /dev/null +++ b/pages/home.html @@ -0,0 +1,8 @@ +
+

Willkommen beim Lorem Ipsum Game

+

Teste deine Fähigkeiten im Umgang mit Lorem Ipsum Texten! Je schneller und genauer du bist, desto höher ist dein Score. + Viel Spaß beim Spielen!

+ +

Wähle eine Option aus der Navigation, um zu starten.

+ Lorem Ipsum Game +
\ No newline at end of file diff --git a/pages/leaderboard.html b/pages/leaderboard.html new file mode 100644 index 0000000..7fbb136 --- /dev/null +++ b/pages/leaderboard.html @@ -0,0 +1,5 @@ +
+

Leaderboard

+ +

Hier kannst du die besten Spieler und ihre Scores sehen.

+
diff --git a/pages/login.html b/pages/login.html new file mode 100644 index 0000000..3f0b3ae --- /dev/null +++ b/pages/login.html @@ -0,0 +1,73 @@ + +
+

Account

+ +
+ + +
+

Aktuelle Sitzung

+

Nicht eingeloggt.

+
+ + +
+
+ + +
+
+
+

Login

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

Neuen Account erstellen

+
+
+ + +
+ +
+

Hinweis: Das Passwort wird vom Backend erstellt und bei Erfolg angezeigt.

+
+
+
+
+ + + + \ No newline at end of file diff --git a/pages/messages.html b/pages/messages.html new file mode 100644 index 0000000..cf65402 --- /dev/null +++ b/pages/messages.html @@ -0,0 +1,6 @@ +
+

Nachrichten

+ +

Hier kannst du deine Nachrichten ansehen und verwalten.

+ +
\ No newline at end of file diff --git a/pages/play.html b/pages/play.html new file mode 100644 index 0000000..a28877a --- /dev/null +++ b/pages/play.html @@ -0,0 +1,7 @@ +
+

Spiel Starten

+

Hier kannst du das Spiel starten. Viel Erfolg!

+ + + +
\ No newline at end of file diff --git a/pages/scores.html b/pages/scores.html new file mode 100644 index 0000000..78eb95e --- /dev/null +++ b/pages/scores.html @@ -0,0 +1,6 @@ +
+

Meine Scores

+ +

Hier kannst du deine bisherigen Scores einsehen.

+ +
\ No newline at end of file