diff --git a/client/images/Werewolf_Small.png b/client/images/Werewolf_Small.png
index d81ac12..0f6256a 100644
Binary files a/client/images/Werewolf_Small.png and b/client/images/Werewolf_Small.png differ
diff --git a/client/images/logo_cropped.gif b/client/images/logo_cropped.gif
new file mode 100644
index 0000000..7ebb7fb
Binary files /dev/null and b/client/images/logo_cropped.gif differ
diff --git a/client/modules/GameCreationStepManager.js b/client/modules/GameCreationStepManager.js
index f10ada1..a284ea5 100644
--- a/client/modules/GameCreationStepManager.js
+++ b/client/modules/GameCreationStepManager.js
@@ -247,12 +247,19 @@ function renderReviewAndCreateStep(containerId, stepNumber, game) {
div.setAttribute("id", "step-" + stepNumber);
div.innerHTML =
- "Moderation " +
- "
" +
- "Timer " +
- "
" +
- "Game Deck " +
- "
";
+ "" +
+ "
Moderation " +
+ "
" +
+ "
" +
+ "" +
+ "
Timer " +
+ "
" +
+ "
" +
+ "" +
+ "
Game Deck " +
+ "
" +
+ "
";
+
div.querySelector('#mod-option').innerText = game.hasDedicatedModerator
? "I will be the dedicated mod. Don't deal me a card."
diff --git a/client/modules/GameStateRenderer.js b/client/modules/GameStateRenderer.js
index fb2af5d..3c22239 100644
--- a/client/modules/GameStateRenderer.js
+++ b/client/modules/GameStateRenderer.js
@@ -1,4 +1,5 @@
-import {globals} from "../config/globals.js";
+import { globals } from "../config/globals.js";
+import { toast } from "./Toast.js";
export class GameStateRenderer {
constructor(gameState) {
@@ -30,9 +31,14 @@ export class GameStateRenderer {
renderLobbyHeader() {
let title = document.createElement("h1");
title.innerText = "Lobby";
- document.body.prepend(title);
+ document.getElementById("game-title").appendChild(title);
let gameLinkContainer = document.getElementById("game-link");
gameLinkContainer.innerText = window.location;
+ gameLinkContainer.addEventListener('click', () => {
+ navigator.clipboard.writeText(gameLinkContainer.innerText).then(() => {
+ toast('Link copied!', 'success', true);
+ });
+ });
let copyImg = document.createElement("img");
copyImg.setAttribute("src", "../images/copy.svg");
gameLinkContainer.appendChild(copyImg);
diff --git a/client/modules/Templates.js b/client/modules/Templates.js
index f7c2b0d..ca547d6 100644
--- a/client/modules/Templates.js
+++ b/client/modules/Templates.js
@@ -20,5 +20,9 @@ export const templates = {
"" +
+ "",
+ START_GAME_PROMPT:
+ "" +
+ "Start Game " +
"
"
}
diff --git a/client/modules/Toast.js b/client/modules/Toast.js
index 7b14cf5..93a9b72 100644
--- a/client/modules/Toast.js
+++ b/client/modules/Toast.js
@@ -7,7 +7,7 @@ export const toast = (message, type, positionAtTop = true) => {
function buildAndInsertMessageElement (message, type, positionAtTop) {
cancelCurrentToast();
let backgroundColor;
- const position = positionAtTop ? 'top:4rem;' : 'bottom: 35px;';
+ const position = positionAtTop ? 'top:3rem;' : 'bottom: 35px;';
switch (type) {
case 'warning':
backgroundColor = '#fff5b1';
diff --git a/client/modules/UserUtility.js b/client/modules/UserUtility.js
index 208f08a..ce1912c 100644
--- a/client/modules/UserUtility.js
+++ b/client/modules/UserUtility.js
@@ -1,9 +1,14 @@
import { globals } from '../config/globals.js';
+/*
+ we will use sessionStorage during local development to aid in testing, vs. localStorage for production.
+ sessionStorage does not persist across tabs, allowing developers to join a game as different players from different windows.
+ */
export const UserUtility = {
createNewAnonymousUserId (force = true, environment) {
let newId, currentId;
+
if (environment === globals.ENVIRONMENT.LOCAL) {
currentId = sessionStorage.getItem(globals.PLAYER_ID_COOKIE_KEY);
} else {
@@ -23,7 +28,7 @@ export const UserUtility = {
},
setAnonymousUserId (id, environment) {
- if (environment === globals.ENVIRONMENT.LOCAL) { // use sessionStorage for cookie during local development to aid in testing.
+ if (environment === globals.ENVIRONMENT.LOCAL) {
sessionStorage.setItem(globals.PLAYER_ID_COOKIE_KEY, id);
} else {
localStorage.setItem(globals.PLAYER_ID_COOKIE_KEY, id);
@@ -32,7 +37,7 @@ export const UserUtility = {
validateAnonUserSignature (environment) {
let userSig;
- if (environment === globals.ENVIRONMENT.LOCAL) { // use sessionStorage for cookie during local development to aid in testing.
+ if (environment === globals.ENVIRONMENT.LOCAL) {
userSig = sessionStorage.getItem(globals.PLAYER_ID_COOKIE_KEY);
} else {
userSig = localStorage.getItem(globals.PLAYER_ID_COOKIE_KEY);
diff --git a/client/scripts/game.js b/client/scripts/game.js
index 32cafad..f4426ad 100644
--- a/client/scripts/game.js
+++ b/client/scripts/game.js
@@ -32,8 +32,17 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
switch (gameState.status) {
case globals.GAME_STATE.LOBBY:
document.getElementById("game-state-container").innerHTML = templates.LOBBY;
- gameStateRenderer.renderLobbyPlayers();
gameStateRenderer.renderLobbyHeader();
+ gameStateRenderer.renderLobbyPlayers();
+ if (
+ gameState.isFull
+ && (
+ gameState.userType === globals.USER_TYPES.MODERATOR
+ || gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
+ )
+ ) {
+ displayStartGamePromptForModerators();
+ }
break;
default:
break;
@@ -41,9 +50,25 @@ function processGameState (gameState, userId, socket, gameStateRenderer) {
}
function setClientSocketHandlers(gameStateRenderer, socket) {
- socket.on(globals.EVENTS.PLAYER_JOINED, (player) => {
+ socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => {
toast(player.name + " joined!", "success", false);
gameStateRenderer.gameState.people.push(player);
gameStateRenderer.renderLobbyPlayers();
+ if (
+ gameIsFull
+ && (
+ gameStateRenderer.gameState.userType === globals.USER_TYPES.MODERATOR
+ || gameStateRenderer.gameState.userType === globals.USER_TYPES.TEMPORARY_MODERATOR
+ )
+ ) {
+ displayStartGamePromptForModerators();
+ }
})
}
+
+function displayStartGamePromptForModerators() {
+ document.getElementById("lobby-players").setAttribute("style", 'margin-bottom: 130px');
+ let div = document.createElement("div");
+ div.innerHTML = templates.START_GAME_PROMPT;
+ document.body.appendChild(div);
+}
diff --git a/client/styles/GLOBAL.css b/client/styles/GLOBAL.css
index fc363cc..7b99623 100644
--- a/client/styles/GLOBAL.css
+++ b/client/styles/GLOBAL.css
@@ -23,23 +23,20 @@ th, thead, tr, tt, u, ul, var {
html {
font-family: 'signika-negative', sans-serif !important;
- background-color: #23282b !important;
+ background-color: #121314 !important;
}
body {
display: flex;
flex-direction: column;
align-items: flex-start;
- width: 95%;
margin: 0 auto;
- max-width: 68em;
}
h1 {
font-family: 'diavlo', sans-serif;
color: #ab2626;
filter: drop-shadow(2px 2px 4px black);
- font-size: 50px;
margin: 0.5em 0;
}
@@ -79,12 +76,13 @@ textarea, input {
button, input[type="submit"] {
font-family: 'signika-negative', sans-serif !important;
padding: 10px;
- background-color: black;
+ background-color: #722c2c;
border-radius: 3px;
color: whitesmoke;
font-size: 18px;
cursor: pointer;
border: 2px solid transparent;
+ transition: background-color 0.3s ease-out;
}
button:active, input[type=submit]:active {
@@ -97,11 +95,13 @@ button:active, input[type=submit]:active {
display: flex;
flex-direction: column;
justify-content: center;
- width: 100%;
+ width: 95%;
+ max-width: 68em;
+ margin: 0 auto;
}
-button:hover, input[type="submit"]:hover {
- background-color: #4f4f4f;
+button:hover, input[type="submit"]:hover, #game-link:hover {
+ background-color: #333243;
}
input {
@@ -122,7 +122,7 @@ input {
left: 0;
right: 0;
width: fit-content;
- max-width: 30em;
+ max-width: 80%;
min-width: 15em;
font-size: 20px;
margin: 0 auto;
@@ -134,8 +134,14 @@ input {
#navbar {
display: flex;
align-items: center;
- padding: 5px;
+ padding: 5px 0;
width: 100%;
+ background-color: #333243;
+}
+
+#navbar img {
+ margin: 0 1em;
+ width: 50px;
}
#navbar a {
@@ -143,6 +149,7 @@ input {
text-decoration: none;
cursor: pointer;
font-size: 25px;
+ font-family: 'diavlo', sans-serif;
}
#navbar a:hover {
@@ -253,3 +260,23 @@ input {
transform: translateY(-20px);
}
}
+
+@media(max-width: 550px) {
+ h1 {
+ font-size: 35px;
+ }
+
+ #step-1 div {
+ font-size: 20px;
+ }
+}
+
+@media(min-width: 551px) {
+ h1 {
+ font-size: 50px;
+ }
+
+ #step-1 div {
+ font-size: 25px;
+ }
+}
diff --git a/client/styles/create.css b/client/styles/create.css
index 9eb7037..5976516 100644
--- a/client/styles/create.css
+++ b/client/styles/create.css
@@ -86,7 +86,7 @@
width: fit-content;
}
-#deck-container, #custom-roles-container, #step-3 {
+#deck-container, #custom-roles-container {
margin: 1em 0;
background-color: #1f1f1f;
padding: 10px;
@@ -95,12 +95,29 @@
#step-3 {
display: flex;
+ padding: 10px;
justify-content: center;
align-items: center;
width: fit-content;
+ border-radius: 3px;
margin: 0 auto;
}
+#step-4 > div {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: left;
+ justify-content: center;
+ margin: 0 auto;
+ width: 25em;
+ max-width: 95%;
+}
+
+#step-4 > div label {
+ width: 100%;
+}
+
#deck {
display: flex;
flex-wrap: wrap;
@@ -235,7 +252,6 @@ input[type="number"] {
cursor: pointer;
border: 2px solid transparent;
border-radius: 3px;
- font-size: 25px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.6);
}
@@ -259,6 +275,7 @@ input[type="number"] {
width: fit-content;
border-radius: 3px;
margin: 0.5em 0;
+ align-self: flex-start;
}
@keyframes fade-in {
@@ -268,3 +285,23 @@ input[type="number"] {
opacity: 1;
}
}
+
+@media(max-width: 550px) {
+ h1 {
+ font-size: 35px;
+ }
+
+ #step-1 div {
+ font-size: 20px;
+ }
+}
+
+@media(min-width: 551px) {
+ h1 {
+ font-size: 50px;
+ }
+
+ #step-1 div {
+ font-size: 25px;
+ }
+}
diff --git a/client/styles/game.css b/client/styles/game.css
index b285bc7..f6950b3 100644
--- a/client/styles/game.css
+++ b/client/styles/game.css
@@ -41,15 +41,15 @@ h1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- border: 2px solid transparent;
cursor: pointer;
margin-top: 10px;
- padding: 5px;
+ padding: 7px;
border-radius: 3px;
- background-color: #1f1f1f;
+ background-color: #722c2c;
color: whitesmoke;
align-items: center;
display: flex;
+ transition: background-color 0.2s;
}
#game-player-count {
@@ -63,8 +63,8 @@ h1 {
margin-left: 0.5em;
}
-#game-link:hover {
- border: 2px solid #0075F2;
+#game-title {
+ margin: 0 auto;
}
label[for='moderator'] {
@@ -80,3 +80,60 @@ label[for='lobby-players'] {
filter: drop-shadow(2px 2px 4px black);
font-size: 30px;
}
+
+#start-game-prompt {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: fixed;
+ z-index: 1000;
+ border-radius: 3px;
+ font-family: 'signika-negative', sans-serif;
+ font-weight: 100;
+ box-shadow: 0 2px 4px 0 rgb(0 0 0 / 25%);
+ left: 0;
+ right: 0;
+ bottom: 0;
+ /* width: fit-content; */
+ font-size: 20px;
+ height: 120px;
+ margin: 0 auto;
+ animation: fade-in-slide-up 10s ease;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ width: 100%;
+ background-color: #333243;
+}
+
+#start-game-button {
+ font-family: 'signika-negative', sans-serif !important;
+ padding: 10px;
+ background-color: #1c8a36;
+ border-radius: 3px;
+ color: whitesmoke;
+ font-size: 30px;
+ cursor: pointer;
+ border: 2px solid transparent;
+ transition: background-color, border 0.3s ease-out;
+ text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
+}
+
+#start-game-button:hover {
+ background-color: #326243;
+ border: 2px solid #1c8a36;
+}
+
+@keyframes fade-in-slide-up {
+ 0% {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ 5% {
+ opacity: 1;
+ transform: translateY(0px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0px);
+ }
+}
diff --git a/client/styles/home.css b/client/styles/home.css
index 2b9761a..f84aee8 100644
--- a/client/styles/home.css
+++ b/client/styles/home.css
@@ -1,10 +1,15 @@
+html {
+ height: 100%;
+}
+
body {
align-items: center;
+ justify-content: center;
+ height: 100%;
}
button {
padding: 20px;
- font-size: 25px;
margin-bottom: 1em;
}
@@ -19,6 +24,10 @@ form {
align-items: center;
}
+a button {
+ text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
+}
+
#join-button {
min-width: 6em;
max-height: 3em;
@@ -26,19 +35,26 @@ form {
}
h3 {
- max-width: 30em;
- font-size: 16px;
+ font-size: 20px;
margin-bottom: 2em;
+ padding: 1em;
+ max-width: 23em;
+ font-family: 'diavlo', sans-serif;
}
img {
- max-width: 650px;
+ max-width: 400px;
width: 63vw;
- min-width: 430px;
+ min-width: 250px;
+ margin: 1em 0;
}
form > div {
- margin: 1em;
+ margin: 1em 0;
+}
+
+#join-container {
+ max-width: 90%;
}
#join-container > label {
@@ -51,3 +67,15 @@ form > div {
label[for="room-code"], label[for="player-name"] {
margin-right: 0.5em;
}
+
+@media (min-width: 700px) {
+ button {
+ font-size: 35px;
+ }
+}
+
+@media (max-width: 701px) {
+ button {
+ font-size: 5vw;
+ }
+}
diff --git a/client/views/404.html b/client/views/404.html
index 07ab078..4a212d6 100644
--- a/client/views/404.html
+++ b/client/views/404.html
@@ -3,22 +3,77 @@
-
- Werewolf Utility
-
-
+ Create A Game
+
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
-404
+
+
+ 404
+ The game or other resource that you are looking for could not be found, or you don't have permission to access it.
+ If this error is unexpected, the application may have restarted.
+
+