diff options
Diffstat (limited to 'WebInterface/NodeJSServer/src')
21 files changed, 620 insertions, 444 deletions
diff --git a/WebInterface/NodeJSServer/src/about.js b/WebInterface/NodeJSServer/src/about.js new file mode 100644 index 0000000..1561a2f --- /dev/null +++ b/WebInterface/NodeJSServer/src/about.js @@ -0,0 +1,4 @@ +import Backdrop from './modules/ui/backdrop.js'; + +let backdrop = new Backdrop('menu', 'front-layer', 'show-menu'); +backdrop.register(); diff --git a/WebInterface/NodeJSServer/src/index.js b/WebInterface/NodeJSServer/src/index.js index 01a9ba1..a37ae5f 100644 --- a/WebInterface/NodeJSServer/src/index.js +++ b/WebInterface/NodeJSServer/src/index.js @@ -1,7 +1,7 @@ import Backdrop from './modules/ui/backdrop.js'; import BannerController from './modules/ui/notification-banner.js'; import ServerClient from './modules/server-client.js' -import Modal from './modules/ui/modal.js'; // TODO: DEBUGGING +import LoginModal from './modules/ui/login-modal.js'; // TODO: JUST FOR DEBUGGING let backdrop = new Backdrop('menu', 'front-layer', 'show-menu'); backdrop.register(); @@ -10,8 +10,10 @@ let notifications = new BannerController('notifications', 'banner-info', 'dismiss-banner'); notifications.register(); -let client = new ServerClient('http://89.183.117.197:5000/chatHub', 'server-list', true); +let client = new ServerClient('http://89.183.8.51:5000/chatHub', 'server-list', true); document.getElementById('refresh-button') .addEventListener('click', client.loadServers.bind(client)); -new Modal('Test Titel'); +new LoginModal('The Crew', client); + +window.client = client; //TODO: REMOVE, JUST FOR DEBUGGING diff --git a/WebInterface/NodeJSServer/src/modules/hash.js b/WebInterface/NodeJSServer/src/modules/hash.js new file mode 100644 index 0000000..826c8ee --- /dev/null +++ b/WebInterface/NodeJSServer/src/modules/hash.js @@ -0,0 +1,17 @@ +String.prototype.getHash = async function() { + let data = new ArrayBuffer(this.length * 2); + let bufferView = new Uint16Array(data); + for (let i = 0; i < this.length; i++) { + bufferView[i] = this.charCodeAt(i); + } + + let encrypted = await crypto.subtle.digest('SHA-256', bufferView); + let byteArray = new Uint8Array(encrypted); + let base64String = ''; + + for (let byte of byteArray) { + base64String += String.fromCharCode(byte); + } + + return btoa(base64String); +} diff --git a/WebInterface/NodeJSServer/src/modules/server-client.js b/WebInterface/NodeJSServer/src/modules/server-client.js index e550bb7..0a257ba 100644 --- a/WebInterface/NodeJSServer/src/modules/server-client.js +++ b/WebInterface/NodeJSServer/src/modules/server-client.js @@ -1,6 +1,5 @@ import * as signalR from '@aspnet/signalr'; import ServerListing from './ui/server-listing.js'; -import ServerCreator from './ui/server-creator.js'; export default class ServerClient { constructor(url, serverListingId, debug = false) { @@ -21,6 +20,8 @@ export default class ServerClient { this.refreshing = false; this.serverListing = new ServerListing(serverListingId); + + this.messageHandling(); //TODO: REMOVE, JUST FOR DEBUGGING } loadServers() { @@ -43,7 +44,11 @@ export default class ServerClient { } createServer(){ + // TODO: Create + } + sendLogin(group, password, username){ + this.connection.invoke('Login', group, username, password); } messageHandling(){ @@ -52,6 +57,7 @@ export default class ServerClient { .replace(/</g, "<") .replace(/>/g, ">"); let encodedMsg = user + " sagt: " + msg; + console.log(encodedMsg); //TODO: REMOVE, JUST FOR DEBUGGING }); } } diff --git a/WebInterface/NodeJSServer/src/modules/ui/login-modal.js b/WebInterface/NodeJSServer/src/modules/ui/login-modal.js new file mode 100644 index 0000000..cb1f2ac --- /dev/null +++ b/WebInterface/NodeJSServer/src/modules/ui/login-modal.js @@ -0,0 +1,67 @@ +import Modal from './modal.js'; +import '../hash.js'; + +export default class LoginModal extends Modal { + constructor(serverName, serverClient) { + super(serverName); + this.serverName = serverName; + this.serverClient = serverClient; + + let passBox = document.createElement('div'); + let nameBox = document.createElement('div'); + let sendBox = document.createElement('div'); + + let passwordLabel = document.createElement('label'); + let passwordInput = document.createElement('input'); + passwordLabel.setAttribute('for', 'password-input'); + passwordLabel.textContent = 'Passwort:'; + passwordLabel.title = 'Das Passwort des Spiels' + passwordInput.id = 'password-input'; + passwordInput.type = 'password'; + passwordInput.placeholder = 'Passwort'; + + let nameLabel = document.createElement('label'); + let nameInput = document.createElement('input'); + nameLabel.setAttribute('for', 'name-input'); + nameLabel.textContent = 'Benutzername:'; + nameLabel.title = 'Dein Anzeigename' + nameInput.id = 'name-input'; + nameInput.type = 'text'; + nameInput.autocomplete = 'on'; + nameInput.placeholder = 'Name'; + + let sendButton = document.createElement('button'); + sendButton.className = 'btn'; + sendButton.textContent = 'Login'; + sendButton.id = 'login-button'; + + + passBox.appendChild(passwordLabel); + passBox.appendChild(passwordInput); + nameBox.appendChild(nameLabel); + nameBox.appendChild(nameInput); + sendBox.appendChild(sendButton); + + this.body.appendChild(passBox); + this.body.appendChild(nameBox); + this.body.appendChild(sendBox); + + this.nameInput = nameInput; + this.passwordInput = passwordInput; + this.loginButton = sendButton; + + this.registerLoginBtn(); + } + + registerLoginBtn() { + this.loginButton.addEventListener('click', () => { + console.log('button pressed') + let userName = this.nameInput.value; + this.passwordInput.value.getHash() + .then((result) => { + this.serverClient.sendLogin(this.serverName, result, userName); + this.close(); + }); + }); + } +} diff --git a/WebInterface/NodeJSServer/src/modules/ui/modal.js b/WebInterface/NodeJSServer/src/modules/ui/modal.js index e1aa8a2..55e38bd 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/modal.js +++ b/WebInterface/NodeJSServer/src/modules/ui/modal.js @@ -13,6 +13,7 @@ export default class Modal { title.textContent = titleString; modal.appendChild(title); + modal.appendChild(body); modalBackground.appendChild(modal); document.body.appendChild(modalBackground); @@ -25,11 +26,19 @@ export default class Modal { } registerEvents() { + this.modal.addEventListener('click', (e) => { + e.stopPropagation(); + }); + this.bg.addEventListener('click', () => { - this.bg.classList.add('hidden'); - this.bg.addEventListener('transitionend', () => { - document.body.removeChild(this.bg); - }); + this.close(); + }); + } + + close() { + this.bg.classList.add('hidden'); + this.bg.addEventListener('transitionend', () => { + document.body.removeChild(this.bg); }); } diff --git a/WebInterface/NodeJSServer/src/modules/ui/server-creator.js b/WebInterface/NodeJSServer/src/modules/ui/server-creator.js deleted file mode 100644 index 4203dfe..0000000 --- a/WebInterface/NodeJSServer/src/modules/ui/server-creator.js +++ /dev/null @@ -1,7 +0,0 @@ -import Modal from './modal.js'; - -export default class ServerCreator extends Modal { - constructor() { - super('Neues Spiel') - } -} diff --git a/WebInterface/NodeJSServer/src/modules/ui/server-listing.js b/WebInterface/NodeJSServer/src/modules/ui/server-listing.js index be66573..2c501fd 100644 --- a/WebInterface/NodeJSServer/src/modules/ui/server-listing.js +++ b/WebInterface/NodeJSServer/src/modules/ui/server-listing.js @@ -15,12 +15,14 @@ export default class ServerListing { let serverDiv = document.createElement('div'); let nameSpan = document.createElement('span'); + let rightAlignDiv = document.createElement('div'); let onlineDot = document.createElement('div'); let playerCountSpan = document.createElement('span'); let playerCountStaticSpan = document.createElement('span'); let joinButton = document.createElement('button'); serverDiv.className = 'server'; nameSpan.className = 'server-name'; + rightAlignDiv.className = 'right-aligned-items'; onlineDot.className = 'player-count-dot'; playerCountSpan.className = 'player-count'; playerCountStaticSpan.className = 'player-count-static'; @@ -31,11 +33,12 @@ export default class ServerListing { playerCountStaticSpan.textContent = 'Spieler online'; joinButton.textContent = 'Beitreten'; + rightAlignDiv.appendChild(onlineDot); + rightAlignDiv.appendChild(playerCountSpan); + rightAlignDiv.appendChild(playerCountStaticSpan); + rightAlignDiv.appendChild(joinButton); serverDiv.appendChild(nameSpan); - serverDiv.appendChild(onlineDot); - serverDiv.appendChild(playerCountSpan); - serverDiv.appendChild(playerCountStaticSpan); - serverDiv.appendChild(joinButton); + serverDiv.appendChild(rightAlignDiv) this.serverListing.appendChild(serverDiv); } } diff --git a/WebInterface/NodeJSServer/src/play.js b/WebInterface/NodeJSServer/src/play.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/WebInterface/NodeJSServer/src/play.js diff --git a/WebInterface/NodeJSServer/src/style/about.scss b/WebInterface/NodeJSServer/src/style/about.scss new file mode 100644 index 0000000..9d8ad50 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/about.scss @@ -0,0 +1,5 @@ +@import 'partials/base'; +@import 'partials/backdrop/base'; +@import 'partials/backdrop/menu'; +@import 'partials/front-layer/base'; +@import 'partials/front-layer/copyright'; diff --git a/WebInterface/NodeJSServer/src/style/index.scss b/WebInterface/NodeJSServer/src/style/index.scss index b5ca607..04c896a 100644 --- a/WebInterface/NodeJSServer/src/style/index.scss +++ b/WebInterface/NodeJSServer/src/style/index.scss @@ -1,425 +1,10 @@ -@import 'partials/_colors.scss'; - -html,body { - height: 100vh; - margin: 0; - padding: 0; - font-family: 'Roboto', sans-serif; - font-display: swap; - overflow: hidden; - background-color: $primary; - color: $primary-text; - user-select: none; -} - -body { - display: flex; - flex-direction: column; - background-color: $secondary; - position: relative; -} - -.btn { - border: none; - border-radius: 4px; - padding: 8px; - margin: 0; - font-size: 1rem; - font-family: 'Roboto Condensed', sans-serif; - font-weight: bold; - display: inline-block; - background-color: $secondary; - color: $secondary-text; - text-transform: uppercase; - box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); - cursor: pointer; - letter-spacing: 0.25rem; - - background-position: center; - transition: background 800ms ease, box-shadow 100ms ease, color 200ms ease; - - &:hover { - background: $secondary-dark radial-gradient(circle, transparent 1%, $secondary-dark 1%) center/15000%; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); - } - - &:active { - background-color: $secondary-light; - background-size: 100%; - box-shadow: 0 1px 3px rgba(0,0,0,0.12); - transition: background 0s, box-shadow 0s; - } - - &:disabled { - color: $secondary-text-disabled; - background: $secondary-disabled; - box-shadow: none; - transition: background 200ms ease, box-shadow 200ms ease, color 200ms ease; - } -} - -.text-btn { - padding: 8px; - margin: 0; - font-size: 1rem; - font-family: 'Roboto Condensed', sans-serif; - font-weight: bold; - display: inline-block; - color: $secondary-text; - background-color: rgba(0, 0, 0, 0); - text-transform: uppercase; - box-shadow: none; - - background-position: center; - transition: background 800ms ease, box-shadow 100ms ease, color 200ms ease; - - &:hover { - background: $secondary-dark-transparent radial-gradient(circle, transparent 1%, $secondary-dark-transparent 1%) center/15000%; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); - } - - &:active { - background-color: $secondary-light; - background-size: 100%; - box-shadow: none; - transition: background 0s, box-shadow 0s; - } - - &:disabled { - background: rgba(0,0,0,0); - color: $secondary-text-disabled; - box-shadow: none; - transition: background 200ms ease, box-shadow 200ms ease, color 200ms ease; - } -} - -.backdrop { - background-color: $secondary; - color: $secondary-text; - font-size: 1rem; - - .header-bar { - display: flex; - align-items: center; - - @media (max-height: 550px) { - margin-top: 0.125rem; - } - - .menu-icon { - background-image: url("./ressources/menu.png"); - background-position: center; - background-repeat: no-repeat; - width: 36px; - height: 36px; - padding: 4px; - margin: 1rem; - display: inline-block; - border: none; - border-radius: 32px; - transition: background-color 100ms ease; - - @media (max-height: 550px) { - padding: 0; - margin: 0.125rem; - } - - &:hover { - background-color: $secondary-dark; - } - - &.open { - background-image: url("./ressources/menu_close.png"); - } - } - - .header { - margin: 0; - padding: 16px; - text-align: center; - flex-grow: 1; - - @media (min-width: 450px) { - margin-right: 56px; - } - - @media (max-height: 550px) { - padding: 0; - } - } - } - - .menu-actions { - box-sizing: border-box; - transition: max-height 200ms ease, color 200ms ease, background-color 100ms ease;; - position: relative; - max-height: 16rem; - margin: 0 1rem; - - .menu-option { - color: $primary-text; - text-decoration: none; - box-sizing: border-box; - display: inline-block; - font-size: 1.5rem; - width: 100%; - text-align: center; - padding: 1rem; - border: none; - border-radius: 8px; - cursor: pointer; - - &:hover { - background-color: $secondary-half-dark; - } - - &.active { - background-color: $secondary-dark; - } - } - - &.hidden { - max-height: 0; - color: rgba(0,0,0,0); - - .menu-option { - color: rgba(0,0,0,0); - background-color: rgba(0,0,0,0) !important; - } - } - } -} - -.container { - @keyframes start { - from {top: 100vh;} - to {top: 0;} - } - - position: relative; - border: none; - border-radius: 16px 16px 0 0; - min-height: 0; - height: 100%; - - box-sizing: border-box; - background-color: white; - margin-top: 8px; - animation-name: start; - animation-duration: 1s; - animation-timing-function: ease; - color: black; - - display: flex; - flex-direction: column; - - .banner { - z-index: 1; - background-color: white; - border: none; - border-radius: 16px 16px 0 0; - display: flex; - margin: 0; - margin-bottom: 1rem; - padding-top: 1rem; - max-height: 10rem; - flex-direction: row; - flex-wrap: wrap; - transform-origin: top; - transition: max-height 200ms ease, transform 200ms ease, visibility 200ms step-start; - min-height: 3.5rem; - justify-items: center; - justify-content: center; - - @media (max-height: 550px) { - position: absolute; - width: 100%; - box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); - } - - &.hidden { - transform: scaleY(0); - visibility: hidden; - max-height: 0; - transition: max-height 200ms ease, transform 200ms ease, visibility 200ms step-end; - min-height: 0; - margin-bottom: 0; - } - - .banner-text { - align-self: left; - margin: 1rem; - flex-grow: 100; - } - - .btn-container{ - display: flex; - flex-grow: 1; - text-align: right; - - - .banner-button { - color: $secondary-dark; - padding: 8px 16px; - margin: 0; - margin-right: 1rem; - letter-spacing: 0.125rem; - } - } - - hr { - width: 100%; - - @media (max-height: 550px) { - margin-bottom: 0; - } - } - } - - .server-listing { - box-sizing: border-box; - background-color: $primary; - color: $primary-text; - min-height: 0; - display: flex; - flex-direction: column; - border-style: none; - border-radius: 8px; - margin: 1rem; - margin-bottom: 2rem; - padding: 0.5rem; - padding-top: 0.25rem; - box-shadow: 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12), 0 5px 5px -3px rgba(0, 0, 0, .2); - h1 { - text-align: center; - @media (max-height: 550px) { - display: none; - } - } - hr { - width: 100%; - @media (max-height: 550px) { - display: none; - } - } - - @media (max-height: 450px) { - padding-bottom: 0.125rem - } - - .server-entries { - overflow-y: auto; - min-height: 0; - - .server { - font-size: 1.25rem; - display: flex; - flex-direction: row; - - @media (max-width: 1000px) { - flex-wrap: wrap; - } - - align-items: center; - background-color: $primary-light; - padding: 0.5rem; - margin-bottom: 0.25rem; - border-style: none; - border-radius: 8px; - - .server-name { - font-weight: bold; - letter-spacing: 0.125rem; - white-space: nowrap; - overflow: hidden; - margin: 0.5rem 0; - } - - .player-count { - font-family: 'Roboto Condensed', sans-serif; - } - - .player-count-static { - @media (max-width: 1000px) { - display: none; - } - - white-space: nowrap; - margin-left: 0.25rem; - letter-spacing: 0; - font-family: 'Roboto Condensed', sans-serif; - } - - .player-count-dot { - background-color: $online-green; - border-radius: 50%; - min-width: 1rem; - min-height: 1rem; - width: 1rem; - height: 1rem; - margin-left: auto; - margin-right: 0.25rem; - } - - .join-btn { - margin-left: 0.5rem; - min-width: 12rem; - } - } - } - - .button-container { - display: flex; - flex-direction: row-reverse; - margin-top: 1rem; - margin-right: 0.25rem; - min-height: 2.5rem; - - @media (max-height: 450px) { - margin-top: 0.125rem; - min-height: 2rem; - } - } - } - - .copyright-container { - box-sizing: border-box; - position: absolute; - width: 100%; - margin: 4px; - bottom: 0; - text-align: center; - } -} - -.modal-container { - position:absolute; - top: 0; - width: 100vw; - height: 100vh; - background-color: #000000AA; - display: flex; - opacity: 1; - transition: opacity 200ms ease; - - &.hidden { - opacity: 0; - } - - .modal { - background-color: #546e7a; - margin: auto; - padding: 1rem; - border-style: none; - border-radius: 8px; - box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22); - } - - .modal-title { - margin: 1rem; - } - - .modal-body { - margin: 0.25rem; - } -} +@import 'partials/base'; +@import 'partials/btn'; +@import 'partials/backdrop/base'; +@import 'partials/backdrop/menu'; +@import 'partials/front-layer/base'; +@import 'partials/front-layer/notifications'; +@import 'partials/front-layer/server-listing'; +@import 'partials/front-layer/copyright'; +@import 'partials/modal/base'; +@import 'partials/modal/login'; diff --git a/WebInterface/NodeJSServer/src/style/partials/_base.scss b/WebInterface/NodeJSServer/src/style/partials/_base.scss new file mode 100644 index 0000000..5f300fd --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/_base.scss @@ -0,0 +1,20 @@ +@import 'colors'; + +html,body { + height: 100vh; + margin: 0; + padding: 0; + font-family: 'Roboto', sans-serif; + font-display: swap; + overflow: hidden; + background-color: $primary; + color: $primary-text; + user-select: none; +} + +body { + display: flex; + flex-direction: column; + background-color: $secondary; + position: relative; +} diff --git a/WebInterface/NodeJSServer/src/style/partials/_btn.scss b/WebInterface/NodeJSServer/src/style/partials/_btn.scss new file mode 100644 index 0000000..cf5ee33 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/_btn.scss @@ -0,0 +1,75 @@ +@import 'colors'; + +.btn { + border: none; + border-radius: 4px; + padding: 8px; + margin: 0; + font-size: 1rem; + font-family: 'Roboto Condensed', sans-serif; + font-weight: bold; + display: inline-block; + background-color: $secondary; + color: $secondary-text; + text-transform: uppercase; + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + cursor: pointer; + letter-spacing: 0.25rem; + + background-position: center; + transition: background 800ms ease, box-shadow 100ms ease, color 200ms ease; + + &:hover { + background: $secondary-dark radial-gradient(circle, transparent 1%, $secondary-dark 1%) center/15000%; + box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); + } + + &:active { + background-color: $secondary-light; + background-size: 100%; + box-shadow: 0 1px 3px rgba(0,0,0,0.12); + transition: background 0s, box-shadow 0s; + } + + &:disabled { + color: $secondary-text-disabled; + background: $secondary-disabled; + box-shadow: none; + transition: background 200ms ease, box-shadow 200ms ease, color 200ms ease; + } +} + +.text-btn { + padding: 8px; + margin: 0; + font-size: 1rem; + font-family: 'Roboto Condensed', sans-serif; + font-weight: bold; + display: inline-block; + color: $secondary-text; + background-color: rgba(0, 0, 0, 0); + text-transform: uppercase; + box-shadow: none; + + background-position: center; + transition: background 800ms ease, box-shadow 100ms ease, color 200ms ease; + + &:hover { + background: $secondary-dark-transparent radial-gradient(circle, transparent 1%, $secondary-dark-transparent 1%) center/15000%; + box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); + } + + &:active { + background-color: $secondary-light; + background-size: 100%; + box-shadow: none; + transition: background 0s, box-shadow 0s; + } + + &:disabled { + background: rgba(0,0,0,0); + color: $secondary-text-disabled; + box-shadow: none; + transition: background 200ms ease, box-shadow 200ms ease, color 200ms ease; + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/backdrop/_base.scss b/WebInterface/NodeJSServer/src/style/partials/backdrop/_base.scss new file mode 100644 index 0000000..1b7a924 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/backdrop/_base.scss @@ -0,0 +1,58 @@ +@import '../colors'; + +.backdrop { + background-color: $secondary; + color: $secondary-text; + font-size: 1rem; + + .header-bar { + display: flex; + align-items: center; + + @media (max-height: 550px) { + margin-top: 0.125rem; + } + + .menu-icon { + background-image: url("../ressources/menu.png"); + background-position: center; + background-repeat: no-repeat; + width: 36px; + height: 36px; + padding: 4px; + margin: 1rem; + display: inline-block; + border: none; + border-radius: 32px; + transition: background-color 100ms ease; + + @media (max-height: 550px) { + padding: 0; + margin: 0.125rem; + } + + &:hover { + background-color: $secondary-dark; + } + + &.open { + background-image: url("../ressources/menu_close.png"); + } + } + + .header { + margin: 0; + padding: 16px; + text-align: center; + flex-grow: 1; + + @media (min-width: 450px) { + margin-right: 56px; + } + + @media (max-height: 550px) { + padding: 0; + } + } + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/backdrop/_menu.scss b/WebInterface/NodeJSServer/src/style/partials/backdrop/_menu.scss new file mode 100644 index 0000000..26833d5 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/backdrop/_menu.scss @@ -0,0 +1,43 @@ +@import '../colors'; + +.backdrop { + .menu-actions { + box-sizing: border-box; + transition: max-height 200ms ease, color 200ms ease, background-color 100ms ease;; + position: relative; + max-height: 16rem; + margin: 0 1rem; + + .menu-option { + color: $primary-text; + text-decoration: none; + box-sizing: border-box; + display: inline-block; + font-size: 1.5rem; + width: 100%; + text-align: center; + padding: 1rem; + border: none; + border-radius: 8px; + cursor: pointer; + + &:hover { + background-color: $secondary-half-dark; + } + + &.active { + background-color: $secondary-dark; + } + } + + &.hidden { + max-height: 0; + color: rgba(0,0,0,0); + + .menu-option { + color: rgba(0,0,0,0); + background-color: rgba(0,0,0,0) !important; + } + } + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/front-layer/_base.scss b/WebInterface/NodeJSServer/src/style/partials/front-layer/_base.scss new file mode 100644 index 0000000..6a2aa9a --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/front-layer/_base.scss @@ -0,0 +1,23 @@ +.front-layer { + @keyframes start { + from {top: 100vh;} + to {top: 0;} + } + + position: relative; + border: none; + border-radius: 16px 16px 0 0; + min-height: 0; + height: 100%; + + box-sizing: border-box; + background-color: white; + margin-top: 8px; + animation-name: start; + animation-duration: 1s; + animation-timing-function: ease; + color: black; + + display: flex; + flex-direction: column; +} diff --git a/WebInterface/NodeJSServer/src/style/partials/front-layer/_copyright.scss b/WebInterface/NodeJSServer/src/style/partials/front-layer/_copyright.scss new file mode 100644 index 0000000..31ac614 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/front-layer/_copyright.scss @@ -0,0 +1,10 @@ +.front-layer{ + .copyright-container { + box-sizing: border-box; + position: absolute; + width: 100%; + margin: 4px; + bottom: 0; + text-align: center; + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/front-layer/_notifications.scss b/WebInterface/NodeJSServer/src/style/partials/front-layer/_notifications.scss new file mode 100644 index 0000000..4dd7361 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/front-layer/_notifications.scss @@ -0,0 +1,66 @@ +@import '../colors'; + +.front-layer { + .banner { + z-index: 1; + background-color: white; + border: none; + border-radius: 16px 16px 0 0; + display: flex; + margin: 0; + margin-bottom: 1rem; + padding-top: 1rem; + max-height: 10rem; + flex-direction: row; + flex-wrap: wrap; + transform-origin: top; + transition: max-height 200ms ease, transform 200ms ease, visibility 200ms step-start; + min-height: 3.5rem; + justify-items: center; + justify-content: center; + + @media (max-height: 550px) { + position: absolute; + width: 100%; + box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); + } + + &.hidden { + transform: scaleY(0); + visibility: hidden; + max-height: 0; + transition: max-height 200ms ease, transform 200ms ease, visibility 200ms step-end; + min-height: 0; + margin-bottom: 0; + } + + .banner-text { + align-self: left; + margin: 1rem; + flex-grow: 100; + } + + .btn-container{ + display: flex; + flex-grow: 1; + text-align: right; + + + .banner-button { + color: $secondary-dark; + padding: 8px 16px; + margin: 0; + margin-right: 1rem; + letter-spacing: 0.125rem; + } + } + + hr { + width: 100%; + + @media (max-height: 550px) { + margin-bottom: 0; + } + } + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/front-layer/_server-listing.scss b/WebInterface/NodeJSServer/src/style/partials/front-layer/_server-listing.scss new file mode 100644 index 0000000..7e67178 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/front-layer/_server-listing.scss @@ -0,0 +1,121 @@ +@import '../colors'; + +.front-layer { + .server-listing { + box-sizing: border-box; + background-color: $primary; + color: $primary-text; + min-height: 0; + display: flex; + flex-direction: column; + border-style: none; + border-radius: 8px; + margin: 1rem; + margin-bottom: 2rem; + padding: 0.5rem; + padding-top: 0.25rem; + box-shadow: 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12), 0 5px 5px -3px rgba(0, 0, 0, .2); + h1 { + text-align: center; + @media (max-height: 550px) { + display: none; + } + } + hr { + width: 100%; + @media (max-height: 550px) { + display: none; + } + } + + @media (max-height: 450px) { + padding-bottom: 0.125rem + } + + .server-entries { + overflow-y: auto; + min-height: 0; + + .server { + font-size: 1.25rem; + display: flex; + flex-direction: row; + + @media (max-width: 1000px) { + flex-wrap: wrap; + } + + align-items: center; + background-color: $primary-light; + padding: 0.5rem; + margin-bottom: 0.25rem; + border-style: none; + border-radius: 8px; + + .server-name { + font-weight: bold; + letter-spacing: 0.125rem; + white-space: nowrap; + overflow: hidden; + margin: 0.5rem 0; + } + + .right-aligned-items { + margin-left: auto; + white-space: nowrap; + display: flex; + align-items: center; + + .player-count-dot { + background-color: $online-green; + border-radius: 50%; + min-width: 1rem; + min-height: 1rem; + width: 1rem; + height: 1rem; + margin-right: 0.25rem; + } + + .player-count { + font-family: 'Roboto Condensed', sans-serif; + } + + .player-count-static { + @media (max-width: 1000px) { + display: none; + } + + white-space: nowrap; + margin-left: 0.25rem; + letter-spacing: 0; + font-family: 'Roboto Condensed', sans-serif; + } + + .join-btn { + margin-left: 0.5rem; + min-width: 12rem; + } + } + } + } + + .button-container { + display: flex; + flex-direction: row-reverse; + margin-top: 1rem; + margin-right: 0.25rem; + min-height: 2.5rem; + + @media (max-height: 450px) { + margin-top: 0.125rem; + min-height: 2rem; + } + + .btn { + @media (max-width: 450px) { + letter-spacing: 0; + } + } + } + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/modal/_base.scss b/WebInterface/NodeJSServer/src/style/partials/modal/_base.scss new file mode 100644 index 0000000..006c241 --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/modal/_base.scss @@ -0,0 +1,35 @@ +@import '../colors'; + +.modal-container { + position:absolute; + top: 0; + width: 100vw; + height: 100vh; + background-color: #000000AA; + display: flex; + opacity: 1; + transition: opacity 200ms ease; + + &.hidden { + opacity: 0; + } + + .modal { + background-color: $primary; + margin: auto; + padding: 1rem; + border-style: none; + border-radius: 8px; + box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22); + } + + .modal-title { + max-width: 85vw; + margin: 1rem; + text-align: center; + } + + .modal-body { + margin: 0.25rem; + } +} diff --git a/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss b/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss new file mode 100644 index 0000000..eed978f --- /dev/null +++ b/WebInterface/NodeJSServer/src/style/partials/modal/_login.scss @@ -0,0 +1,34 @@ +.modal { + .modal-title { + white-space: nowrap; + overflow: hidden; + } + + .modal-body { + display: grid; + grid-template-columns: 10em 1fr; + grid-template-rows: 1fr 1fr 1fr; + grid-row-gap: 0.5rem; + + div { + display: contents; + font-size: 1.25rem; + + label { + flex-basis: 30%; + margin-right: 2rem; + + grid-column: 1 2; + } + + input { + flex-basis: calc(70% - 2rem); + grid-column: 2 3; + } + + button { + grid-column: 1 / 3; + } + } + } +} |