Initial commit

This commit is contained in:
2025-03-13 16:05:09 +01:00
commit 5950d5ae9d
44 changed files with 5505 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Account Bearbeiten</title>
<link rel="stylesheet" href="../../style/generalStyle.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Account</h1>
<h2>Ändere deine Benutzerdaten uns speichere sie ab!</h2>
<div class="buttonMenu container">
<form action="/api/account/update" method="post" class="container">
<h2 class="error" id="errorMsg"></h2>
<div class="splitContainerX">
<div>
<div class="formSection">
<p>Username:</p>
<input id="username" name="username" type="text" placeholder="Username">
</div>
<div class="formSection">
<p>Email:</p>
<input id="email" name="email" type="email" placeholder="E-mail">
</div>
</div>
<div>
<div class="formSection">
<p>Voller Name:</p>
<input id="fullName" name="fullName" type="text" placeholder="Name">
</div>
<div class="formSection">
<p>Neues Passwort:</p>
<input id="password" name="password" type="password" placeholder="Neues Password">
</div>
</div>
</div>
<input type="submit" value="Speichern">
</form>
<div class="container navButtons">
<button id="dashboardBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M520-200 80-480l440-280-137 240h497v80H383l137 240Z" />
</svg>
</div>
<div class="buttonText">
Dashboard
</div>
</button>
</div>
</div>
</div>
</body>
<script src="../../scripts/ButtonManager.js"></script>
<script src="../../scripts/ErrorHandler.js"></script>
<script src="./index.js"></script>
</html>

View File

@@ -0,0 +1,20 @@
class AccountManager{
constructor(){
this.username = document.getElementById("username");
this.email = document.getElementById("email");
this.fullName = document.getElementById("fullName");
this.setUserData();
}
async setUserData(){
const respone = await fetch("/api/dashboard");
this.data = await respone.json();
this.username.value = this.data.username;
this.email.value = this.data.email;
this.fullName.value = this.data.fullName;
}
}
new AccountManager();

View File

@@ -0,0 +1,3 @@
#dashboardBtn{
background-color: orange;
}

View File

@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
<link rel="stylesheet" href="../style/generalStyle.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Dashboard</h1>
<div class="container buttonMenu">
<h2 id="data" class="message"></h2>
<button id="lobbyBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path d="M640-200q-27 0-52.5-5T538-219q58-49 90-117t32-144q0-76-32-144t-90-117q24-9 49.5-14t52.5-5q117 0 198.5 81.5T920-480q0 117-81.5
198.5T640-200Zm-320 0q-117 0-198.5-81.5T40-480q0-117 81.5-198.5T320-760q27 0 52.5 5t49.5 14q-17 14-32 30.5T362-676q-10-2-20.5-3t-21.5-1q-83
0-141.5 58.5T120-480q0 83 58.5 141.5T320-280q11 0 21.5-1t20.5-3q13 18 28 34.5t32 30.5q-24 9-49.5 14t-52.5 5Zm160-50q-57-39-88.5-100T360-480q0-69
31.5-130T480-710q57 39 88.5 100T600-480q0 69-31.5 130T480-250Z" />
</svg>
</div>
<div class="buttonText">
Lobby
</div>
</button>
<button id="accountBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path d="M480-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM160-160v-112q0-34
17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11
-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T560
-640q0-33-23.5-56.5T480-720q-33 0-56.5 23.5T400-640q0 33 23.5 56.5T480-560Zm0-80Zm0 400Z" />
</svg>
</div>
<div class="buttonText">
Account
</div>
</button>
<div class="container navButtons">
<button id="homeBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M520-200 80-480l440-280-137 240h497v80H383l137 240Z" />
</svg>
</div>
<div class="buttonText">
Startseite
</div>
</button>
<button id="logoutBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h280v80H200Zm440-160-55-58
102-102H360v-80h327L585-622l55-58 200 200-200 200Z" />
</svg>
</div>
<div class="buttonText">
Ausloggen
</div>
</button>
</div>
</div>
</div>
</body>
<script src="../scripts/ButtonManager.js"></script>
<script src="./index.js"></script>
</html>

View File

@@ -0,0 +1,15 @@
class DataFetcher {
constructor() {
this.greetingText = document.getElementById("data");
this.init();
}
async init() {
const reponse = await fetch("/api/dashboard");
this.data = await reponse.json();
this.greetingText.innerText = `Hallo ${this.data.fullName ? this.data.fullName : this.data.username}, starte hier Double-Snake!`
}
}
new DataFetcher();

View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lobby</title>
<link rel="stylesheet" href="../../style/generalStyle.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Lobby</h1>
<main class="container buttonMenu">
<h2 class="error" id="errorMsg"></h2>
<div class="container navButtons" id="mainDiv">
<button id="createBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path
d="m272-440 208 120 208-120-168-97v137h-80v-137l-168 97Zm168-189v-17q-44-13-72-49.5T340-780q0-58 41-99t99-41q58
0 99 41t41 99q0 48-28 84.5T520-646v17l280 161q19 11 29.5 29.5T840-398v76q0 22-10.5 40.5T800-252L520-91q-19 11-40 11t-40
-11L160-252q-19-11-29.5-29.5T120-322v-76q0-22 10.5-40.5T160-468l280-161Zm0 378L200-389v67l280 162 280-162v-67L520-251q-19
11-40 11t-40-11Zm40-469q25 0 42.5-17.5T540-780q0-25-17.5-42.5T480-840q-25 0-42.5 17.5T420-780q0 25 17.5 42.5T480-720Zm0 560Z" />
</svg>
</div>
<div class="buttonText">
Code Erstellen
</div>
</button>
<button id="joinBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path
d="M220-520 80-600v-160l140-80 140 80v160l-140 80Zm0-92 60-34v-68l-60-34-60 34v68l60 34Zm440 123v-93l140 82v280L560-80
320-220v-280l140-82v93l-60 35v188l160 93 160-93v-188l-60-35Zm-140 89v-480h360l-80 120 80 120H600v240h-80Zm40 69ZM220-680Z" />
</svg>
</div>
<div class="buttonText">
Mit Code Beitreten
</div>
</button>
</div>
<div class="container">
<button id="leaveBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#FFFFFF">
<path
d="M200-120q-33 0-56.5-23.5T120-200v-160h80v160h560v-560H200v160h-80v-160q0-33 23.5-56.5T200-840h560q33 0
56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm220-160-56-58 102-102H120v-80h346L364-622l56-58 200 200-200 200Z" />
</svg>
</div>
<div class="buttonText">
Verlassen
</div>
</button>
</div>
</main>
</div>
</body>
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
<script src="./scripts/index.js" type="module"></script>
</html>

View File

@@ -0,0 +1,86 @@
class LobbyHandler {
/**@param {import("../../../../../backend/node_modules/socket.io-client".Socket} socket Autocompletions VSC*/
constructor(socket) {
this.socket = socket;
this.errorMsg = document.getElementById("errorMsg");
this.code = null;
this.playerList = [];
this.user = null;
this.socket.emit("requestIdentification");
this.socket.on("identification", (user) => { this.user = user });
// Für das Erstellen
this.socket.on("lobbyCreated", (code) => { this.joinedLobby(code) });
// Für das Beitreten
this.socket.on("lobbyJoinError", (msg) => { this.showJoinError(msg) });
this.socket.on("lobbyJoined", (code) => { this.joinedLobby(code) });
// Für das Aktualisieren
this.socket.on("lobbyUserUpdate", (data) => { this.lobbyUserUpdate(data) });
}
handleCreateClick() {
this.socket.emit("createLobby");
}
handleJoinClick(){
const code = prompt("Bitte gib den 6 Stelligen Code ein");
this.socket.emit("joinLobby", code);
}
showJoinError(msg){
this.errorMsg.innerText = msg;
this.errorMsg.style.display = "block";
}
joinedLobby(code) {
this.code = code;
this.updateUI();
console.log(`Lobby beigerteten mit Code: ${code}`);
}
updateUI() {
const lobbyContainer = document.getElementById("mainDiv");
let playerHTML = "";
this.playerList.forEach((player, index) => {
const amI = player.id === this.user.id ? " (Ich)" : "";
playerHTML += `
<div class="player" id="player${index + 1}">
<h1>Spieler ${index + 1}${amI}</h1>
<h1>${player.username}</h1>
</div>
`;
lobbyContainer.innerHTML = `
<div class="screen">
<nav>
<h1>Spiel-Code:</h1>
<h1 class="message">${this.code}</h1>
</nav>
<div id="playerList">
${playerHTML}
</div>
</div>
`;
});
this.errorMsg.style.display = "none";
}
lobbyUserUpdate(data) {
this.playerList = data.users;
this.updateUI();
}
}
export default LobbyHandler;

View File

@@ -0,0 +1,52 @@
import LobbyHandler from "./Handler/LobbyHandler.js";
class ServerConnectionManager{
constructor(){
/**@type {import("../../../../backend/node_modules/socket.io-client".Socket} für Autocompletions VSC*/
this.socket = io(`http://${window.location.hostname}:${window.location.port}`);
this.createBtn = document.getElementById("createBtn");
this.joinBtn = document.getElementById("joinBtn");
this.leaveBtn = document.getElementById("leaveBtn");
this.lobbyHandler = new LobbyHandler(this.socket);
this.basicSetup();
this.addButtonHandler();
}
basicSetup(){
this.socket.emit("hereForLobby");
this.socket.on("connect", () => {
console.log("Verbindung zum Server hergestellt!");
});
this.socket.on("connect_error", (error) => {
console.log(error);
window.location.pathname = "/dashboard";
});
this.socket.on("disconnect", () => {
console.log("Die verbindung wurde unterbrochen!");
window.location.pathname = "/dashboard";
})
}
addButtonHandler(){
this.createBtn.addEventListener("click", () => {
this.lobbyHandler.handleCreateClick();
});
this.joinBtn.addEventListener("click", () => {
this.lobbyHandler.handleJoinClick();
});
this.leaveBtn.addEventListener("click", () => {
this.socket.disconnect();
window.location.pathname = "/dashboard";
});
}
}
new ServerConnectionManager();

View File

@@ -0,0 +1,66 @@
button {
width: 350px;
}
#joinBtn{
background-color: rgb(0, 119, 255);
}
#leaveBtn{
background-color: orange;
}
.screen{
background-color: rgba(0, 0, 0, 0.6);
border: 2px solid rgba(255, 255, 255, 0.6);
border-radius: 15px;
height: 35vh;
width: 700px;
}
.screen nav{
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
height: 20%;
background-color: rgba(255, 255, 255, 0.377);
border-radius: 10px 10px 0 0;
}
#playerList{
display: flex;
flex-direction: column;
justify-content: start;
align-items: center;
height: 80%;
width: 100%;
}
.player{
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
width: 100%;
height: 50%;
}
.player h1{
width: 50%;
text-align: center;
}
#player1{
background-color: rgba(255, 8, 0, 0.377);
border-radius: 0 0 0 0;
}
#player2{
background-color: rgba(0, 89, 255, 0.377);
border-radius: 0 0 10px 10px;
}

View File

@@ -0,0 +1,23 @@
button{
width: 280px;
}
.buttonMenu{
height: 60%;
}
#joinBtn{
background-color: rgb(0, 119, 255);
}
#homeBtn{
background-color: rgb(122, 122, 0);
}
#accountBtn{
background-color: orange;
}
#logoutBtn{
background-color: rgb(103, 11, 156);
}

78
frontend/index.html Normal file
View File

@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test</title>
<link rel="stylesheet" href="./style/generalStyle.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Double-Snake</h1>
<div class="buttonMenu container">
<button id="tutorialBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M320-200v-560l440 280-440 280Zm80-280Zm0 134 210-134-210-134v268Z" />
</svg>
</div>
<div class="buttonText">
Anleitung
</div>
</button>
<button id="loginBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path
d="M480-120v-80h280v-560H480v-80h280q33
0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H480Zm-80-160-55-58 102-102H120v-80h327L345-622l55-58 200 200-200 200Z" />
</svg>
</div>
<div class="buttonText">
Login
</div>
</button>
<button id="registerBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path
d="M80-160v-112q0-33
17-62t47-44q51-26 115-44t141-18q30 0 58.5 3t55.5 9l-70 70q-11-2-21.5-2H400q-71 0-127.5 17T180-306q-9 5-14.5 14t-5.5 20v32h250l80 80H80Zm542
16L484-282l56-56 82 82 202-202 56 56-258 258ZM400-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113
47Zm10 240Zm-10-320q33 0 56.5-23.5T480-640q0-33-23.5-56.5T400-720q-33 0-56.5 23.5T320-640q0 33 23.5 56.5T400-560Zm0-80Z" />
</svg>
</div>
<div class="buttonText">
Registrieren
</div>
</button>
<button id="dashboardBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M480-320q48 0 85.5-28.5T620-422H340q17 45 54.5 73.5T480-320ZM380-480q25 0 42.5-17.5T440-540q0-25-17.5-42.5T380-600q-25
0-42.5 17.5T320-540q0 25 17.5 42.5T380-480Zm200 0q25 0 42.5-17.5T640-540q0-25-17.5-42.5T580-600q-25 0-42.5 17.5T520-540q0 25 17.5
42.5T580-480ZM305-704l112-145q12-16 28.5-23.5T480-880q18 0 34.5 7.5T543-849l112 145 170 57q26 8 41 29.5t15 47.5q0 12-3.5 24T866-523L756-367l4
164q1 35-23 59t-56 24q-2 0-22-3l-179-50-179 50q-5 2-11 2.5t-11 .5q-32 0-56-24t-23-59l4-165L95-523q-8-11-11.5-23T80-570q0-25 14.5-46.5T135-647l170-57Zm49
69-194 64 124 179-4 191 200-55 200 56-4-192 124-177-194-66-126-165-126 165Zm126 135Z" />
</svg>
</div>
<div class="buttonText">
Dashboard
</div>
</button>
</div>
</div>
</body>
<script src="./scripts/ButtonManager.js"></script>
<script src="./index.js"></script>
</html>

43
frontend/index.js Normal file
View File

@@ -0,0 +1,43 @@
class ButtonLoginChecker{
constructor(){
this.loggedOutButtons = [
{ id: "loginBtn", route: "/login" },
{ id: "registerBtn", route: "/register" }
];
this.loggedInButtons = [
{ id: "dashboardBtn", route: "/dashboard" },
];
this.init();
}
async init(){
const isLoggedIn = await this.checkIsLoggedIn();
this.showButton(isLoggedIn);
}
showButton(isLoggedIn){
const buttons = isLoggedIn ? this.loggedOutButtons : this.loggedInButtons;
buttons.forEach(button => {
document.getElementById(button.id).style.display = "none";
})
}
async checkIsLoggedIn(){
try{
const response = await fetch("/api/dashboard");
return !response.redirected;
}
catch(error){
console.error(error);
return false;
}
}
}
new ButtonLoginChecker();

65
frontend/login/index.html Normal file
View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Einloggen</title>
<link rel="stylesheet" href="../style/generalStyle.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Einloggen</h1>
<div class="buttonMenu container">
<h2 class="error" id="errorMsg"></h2>
<form action="/api/account/login" method="post" class="container">
<div class="formSection">
<p>Username:</p>
<input name="username" type="text" placeholder="Username">
</div>
<div class="formSection">
<p>Passwort:</p>
<input name="password" type="password" placeholder="Password">
</div>
<input type="submit" value="Einloggen" id="loginBtn">
</form>
<div class="container navButtons">
<button id="homeBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M520-200 80-480l440-280-137 240h497v80H383l137 240Z" />
</svg>
</div>
<div class="buttonText">
Startseite
</div>
</button>
<button id="registerBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path
d="M80-160v-112q0-33
17-62t47-44q51-26 115-44t141-18q30 0 58.5 3t55.5 9l-70 70q-11-2-21.5-2H400q-71 0-127.5 17T180-306q-9 5-14.5 14t-5.5 20v32h250l80
80H80Zm542
16L484-282l56-56 82 82 202-202 56 56-258 258ZM400-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113
47Zm10 240Zm-10-320q33 0 56.5-23.5T480-640q0-33-23.5-56.5T400-720q-33 0-56.5 23.5T320-640q0 33 23.5 56.5T400-560Zm0-80Z" />
</svg>
</div>
<div class="buttonText">
Registieren
</div>
</button>
</div>
</div>
</div>
</body>
<script src="../scripts/ButtonManager.js"></script>
<script src="../scripts/ErrorHandler.js"></script>
</html>

11
frontend/login/style.css Normal file
View File

@@ -0,0 +1,11 @@
#homeBtn{
background-color: rgb(0, 119, 255);
}
#registerBtn{
background-color: rgb(122, 122, 0);
}
#loginBtn{
width: 234px;
}

View File

@@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registieren</title>
<link rel="stylesheet" href="../style/generalStyle.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container menu">
<h1 class="title">Registieren</h1>
<div class="buttonMenu container">
<form action="/api/account/register" method="post" class="container">
<h2 class="error" id="errorMsg"></h2>
<div class="splitContainerX">
<div>
<div class="formSection">
<p>Username:</p>
<input name="username" type="text" placeholder="Username">
</div>
<div class="formSection">
<p>Email:</p>
<input name="email" type="email" placeholder="E-mail">
</div>
</div>
<div>
<div class="formSection">
<p>Voller Name:</p>
<input name="fullName" type="text" placeholder="Name">
</div>
<div class="formSection">
<p>Passwort:</p>
<input name="password" type="password" placeholder="Password">
</div>
</div>
</div>
<input type="submit" value="Registieren" id="registerBtn">
</form>
<div class="container navButtons">
<button id="homeBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path d="M520-200 80-480l440-280-137 240h497v80H383l137 240Z" />
</svg>
</div>
<div class="buttonText">
Startseite
</div>
</button>
<button id="loginBtn">
<div class="buttonIcon">
<svg xmlns="http://www.w3.org/2000/svg" height="35px" viewBox="0 -960 960 960" width="35px"
fill="#ffffff">
<path
d="M480-120v-80h280v-560H480v-80h280q33
0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H480Zm-80-160-55-58 102-102H120v-80h327L345-622l55-58 200 200-200 200Z" />
</svg>
</div>
<div class="buttonText">
Login
</div>
</button>
</div>
</div>
</div>
</body>
<script src="../scripts/ButtonManager.js"></script>
<script src="../scripts/ErrorHandler.js"></script>
</html>

View File

@@ -0,0 +1,11 @@
#homeBtn{
background-color: rgb(0, 119, 255);
}
#loginBtn{
background-color: rgb(122, 122, 0);
}
#registerBtn{
width: 234px;
}

View File

@@ -0,0 +1,27 @@
class ButtonManager {
constructor() {
this.buttons = [
{ id: "homeBtn", route: "/" },
{ id: "loginBtn", route: "/login" },
{ id: "registerBtn", route: "/register" },
{ id: "dashboardBtn", route: "/dashboard" },
{ id: "lobbyBtn", route: "/dashboard/lobby" },
{ id: "accountBtn", route: "/dashboard/account" },
{ id: "logoutBtn", route: "/api/account/logout" },
{ id: "tutorialBtn", route: "https://www.youtube.com/watch?v=1fkV5rB13jQ" }
];
this.addEventListener();
}
addEventListener() {
this.buttons.forEach(button => {
const element = document.getElementById(button.id);
if (!element) return;
element.addEventListener("click", () => { window.location.href = button.route });
});
}
}
new ButtonManager();

View File

@@ -0,0 +1,54 @@
class ErrorHandler {
constructor() {
this.errorH2 = document.getElementById("errorMsg");
this.errorList = [
{ route: "/login",
errors: [
{ code: 1, msg: "Du musst ein Username und ein Passwort eingeben!", errorHighligher: ["username", "password"] },
{ code: 2, msg: "Username oder Passwort falsch!", errorHighligher: ["username", "password"] }
]
},
{ route: "/register",
errors: [
{ code: 1, msg: "Du musst zumindest Username und Passwort angeben!", errorHighligher: ["username", "password"] },
{ code: 2, msg: "Username ist schon vergeben!", errorHighligher: ["username"] }
]
},
{ route: "/dashboard/account",
errors: [
{ code: 1, msg: "Dieser Username ist schon vergeben!", errorHighligher: ["username"] },
]
}
];
this.showPossibleError();
}
showPossibleError() {
const route = this.getCurrentRoute();
const error = this.checkError();
if(!error) return;
const errorJSON= this.errorList.find(x => x.route === route).errors.find(x => x.code === error);
this.errorH2.innerText = errorJSON.msg;
this.errorH2.style.display = "block";
errorJSON.errorHighligher.forEach(element => {
document.getElementsByName(element)[0].classList.add("important");
});
}
getCurrentRoute() {
return window.location.pathname.slice(0, -1);
}
checkError() {
const urlParams = new URLSearchParams(window.location.search);
return parseInt(urlParams.get("error"));
}
}
new ErrorHandler();

11
frontend/style.css Normal file
View File

@@ -0,0 +1,11 @@
#loginBtn{
background-color: rgb(0, 119, 255);
}
#registerBtn{
background-color: rgb(122, 122, 0);
}
#dashboardBtn{
background-color: orange;
}

View File

@@ -0,0 +1,207 @@
@import url('https://fonts.googleapis.com/css2?family=Sigmar&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Preahvihear&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Preahvihear&family=Sigmar&display=swap');
* {
margin: 0;
padding: 0;
font-family: "Preahvihear", serif;
font-weight: 400;
font-style: normal;
}
body {
background-color: rgb(40, 85, 51);
background-image: linear-gradient(rgba(0, 0, 0, 0.5) 2px, transparent 1px),
linear-gradient(90deg, rgba(0, 0, 0, 0.5) 2px, transparent 1px);
background-size: 55px 55px;
color: white;
}
.container {
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
}
.splitContainerX {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.navButtons{
flex-direction: row;
justify-content: space-evenly;
width: 50%;
}
@keyframes rainbow-glow {
0% {
text-shadow: 0 0 10px red, 0 0 20px red, 0 0 30px red;
}
20% {
text-shadow: 0 0 10px orange, 0 0 20px orange, 0 0 30px orange;
}
40% {
text-shadow: 0 0 10px rgb(204, 0, 255), 0 0 20px rgb(204, 0, 255), 0 0 30px rgb(204, 0, 255);
}
60% {
text-shadow: 0 0 10px pink, 0 0 20px pink, 0 0 30px pink;
}
80% {
text-shadow: 0 0 10px blue, 0 0 20px blue, 0 0 30px blue;
}
100% {
text-shadow: 0 0 10px purple, 0 0 20px purple, 0 0 30px purple;
}
}
.title {
font-family: "Sigmar", serif;
font-weight: 400;
font-style: normal;
font-size: 100px;
animation: rainbow-glow 15s infinite alternate;
user-select: none;
}
button,
.button,
input[type=submit] {
display: flex;
flex-direction: row;
align-items: center;
justify-content: start;
background-color: rgb(233, 47, 47);
border: 2px solid rgba(255, 255, 255, 0.6);
border-radius: 10px;
height: 60px;
width: 250px;
color: white;
font-size: 25px;
transition: transform 0.2s ease-in-out;
}
.buttonIcon,
.buttonText {
height: 100%;
width: 25%;
display: flex;
align-items: center;
justify-content: center;
}
.buttonText {
width: 75%;
}
button:hover,
.button:hover,
input[type=submit]:hover {
transform: scale(1.1);
}
button:active,
.button:active,
input[type=submit]:active {
transform: translateY(1px);
}
.menu {
height: 100vh;
justify-content: center;
}
.buttonMenu {
height: 50vh;
width: 100vw;
}
input[type=text],
input[type=email],
input[type=password] {
background-color: rgba(255, 255, 255, 0.75);
border: 2px solid rgba(0, 0, 0, 0.6);
border-radius: 10px;
height: 25px;
width: 220px;
padding: 5px;
color: black;
font-weight: 600px;
font-size: 20px;
transition: transform 0.2s ease-in-out;
}
input[type=submit] {
margin-top: 15px;
}
input[type=text]:focus,
input[type=email]:focus,
input[type=password]:focus {
outline: none;
transform: scale(1.05);
}
.formSection {
display: flex;
flex-direction: column;
margin: 10px;
}
.formSection p {
font-size: 20px;
}
.important {
border-color: red !important;
}
.important:focus {
outline: none;
border-color: red !important;
}
.error {
display: none;
font-family: "Kanit", serif;
font-weight: 600;
font-style: normal;
font-size: 25px;
color: red;
background-color: rgba(255, 255, 255, 0.6);
padding: 5px;
border-radius: 15px;
}
.message{
font-size: 25px;
background-color: rgba(0, 0, 0, 0.6);
border: 2px solid rgba(255, 255, 255, 0.6);
padding: 5px;
border-radius: 15px;
}