24 Commits

Author SHA1 Message Date
AlecM33
fbf8a9a1ae minor performance improvements per the lighthouse report 2024-11-12 20:20:21 -05:00
AlecM33
befbeaa228 formatting 2024-11-11 15:01:56 -05:00
AlecM33
467a0a17de update role descriptions 2024-11-11 15:00:18 -05:00
AlecM33
0bbd696fba remove footer, update link to buymeacoffee 2024-11-11 14:32:39 -05:00
AlecM33
7c97001363 fix webpack compression exception 2024-11-10 13:10:04 -05:00
AlecM33
35d280d5ee update node version in dockerfile 2024-11-10 12:48:22 -05:00
AlecM33
0fe9432528 bump node version in package json 2024-11-10 12:35:36 -05:00
AlecM33
b5c610f9ab update node ci version 2024-11-08 13:37:24 -05:00
AlecM33
7cc87d9a48 reset package-lock 2024-11-08 13:32:11 -05:00
dependabot[bot]
ee4aa21a1d Bump ws and socket.io-adapter (#204)
Bumps [ws](https://github.com/websockets/ws) and [socket.io-adapter](https://github.com/socketio/socket.io-adapter). These dependencies needed to be updated together.

Updates `ws` from 8.11.0 to 8.17.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.11.0...8.17.1)

Updates `socket.io-adapter` from 2.5.2 to 2.5.5
- [Release notes](https://github.com/socketio/socket.io-adapter/releases)
- [Changelog](https://github.com/socketio/socket.io-adapter/blob/2.5.5/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-adapter/compare/2.5.2...2.5.5)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 13:29:14 -05:00
dependabot[bot]
4d18ca0d42 Bump cookie, express and socket.io (#203)
Bumps [cookie](https://github.com/jshttp/cookie) to 0.7.1 and updates ancestor dependencies [cookie](https://github.com/jshttp/cookie), [express](https://github.com/expressjs/express) and [socket.io](https://github.com/socketio/socket.io). These dependencies need to be updated together.


Updates `cookie` from 0.4.2 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.4.2...v0.7.1)

Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)

Updates `socket.io` from 4.7.5 to 4.8.1
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io@4.7.5...socket.io@4.8.1)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
- dependency-name: socket.io
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 13:24:07 -05:00
dependabot[bot]
47263c65a8 Bump body-parser and express (#202)
Bumps [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `body-parser` from 1.20.2 to 1.20.3
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-type: direct:production
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alec <leohfx@gmail.com>
2024-11-08 13:19:41 -05:00
dependabot[bot]
a7fb2afde1 Bump send and express (#201)
Bumps [send](https://github.com/pillarjs/send) to 0.19.0 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alec <leohfx@gmail.com>
2024-11-08 13:16:02 -05:00
dependabot[bot]
d31999e06e Bump serve-static and express (#200)
* Bump serve-static and express

Bumps [serve-static](https://github.com/expressjs/serve-static) to 1.16.2 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `serve-static` from 1.15.0 to 1.16.2
- [Release notes](https://github.com/expressjs/serve-static/releases)
- [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md)
- [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2)

Updates `express` from 4.19.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0)

---
updated-dependencies:
- dependency-name: serve-static
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update package-lock.json

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alec <leohfx@gmail.com>
2024-11-08 13:02:13 -05:00
dependabot[bot]
7b4a96a8fa Bump path-to-regexp and express (#199)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.10 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.7 to 0.1.10
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.10)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 12:35:35 -05:00
dependabot[bot]
c180897862 Bump webpack from 5.76.0 to 5.94.0 (#198)
Bumps [webpack](https://github.com/webpack/webpack) from 5.76.0 to 5.94.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.76.0...v5.94.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 12:35:26 -05:00
dependabot[bot]
088e65c728 Bump ws, socket.io and socket.io-client (#197)
Bumps [ws](https://github.com/websockets/ws) to 8.18.0 and updates ancestor dependencies [ws](https://github.com/websockets/ws), [socket.io](https://github.com/socketio/socket.io) and [socket.io-client](https://github.com/socketio/socket.io-client). These dependencies need to be updated together.


Updates `ws` from 8.2.3 to 8.18.0
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.2.3...8.18.0)

Updates `socket.io` from 4.6.2 to 4.7.5
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/4.6.2...4.7.5)

Updates `socket.io-client` from 4.5.4 to 4.7.5
- [Release notes](https://github.com/socketio/socket.io-client/releases)
- [Changelog](https://github.com/socketio/socket.io-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-client/compare/4.5.4...4.7.5)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
- dependency-name: socket.io
  dependency-type: direct:production
- dependency-name: socket.io-client
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 12:35:16 -05:00
dependabot[bot]
718ad1b58e Bump braces from 3.0.2 to 3.0.3 (#195)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-04 11:05:09 -04:00
dependabot[bot]
69a2a88d74 Bump socket.io from 4.6.1 to 4.6.2 (#196)
Bumps [socket.io](https://github.com/socketio/socket.io) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/4.6.1...4.6.2)

---
updated-dependencies:
- dependency-name: socket.io
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-04 11:05:01 -04:00
dependabot[bot]
5f819f8f17 Bump ejs from 3.1.8 to 3.1.10 (#194)
Bumps [ejs](https://github.com/mde/ejs) from 3.1.8 to 3.1.10.
- [Release notes](https://github.com/mde/ejs/releases)
- [Commits](https://github.com/mde/ejs/compare/v3.1.8...v3.1.10)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-10 09:09:13 -04:00
dependabot[bot]
4ad2d6c663 Bump express from 4.18.2 to 4.19.2 (#193)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 16:19:16 -04:00
Alec
01ed3c6842 Remove unload event (#192)
* use page hide event, manually reconnect

* comment

* lint
2024-03-26 22:01:39 -04:00
dependabot[bot]
1833bde903 Bump follow-redirects from 1.15.4 to 1.15.6 (#190)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-17 16:13:01 -04:00
Alec
915819bb15 Fix bug where we incorrectly added a user as a player instead of a spectator (#189)
* fix bug with failing to add as spectator for in-progress game

* refactor fix

* revert to previous fix
2024-03-12 22:59:05 -04:00
24 changed files with 1382 additions and 5998 deletions

View File

@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
node-version: [14.x]
node-version: [20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:

View File

@@ -1,6 +1,6 @@
# Use the official lightweight Node.js 14 image.
# https://hub.docker.com/_/node
FROM node:14-slim
FROM node:20-slim
# Create and change to the app directory.
WORKDIR /usr/src/app

View File

@@ -1,4 +1,4 @@
FROM node:14-slim
FROM node:20-slim
WORKDIR /usr/src/app

View File

@@ -2,17 +2,17 @@ export const defaultRoles = [
{
role: 'Villager',
team: 'good',
description: 'During the day, find the wolves and kill them.'
description: 'During the day, find the Werewolves and kill them.'
},
{
role: 'Werewolf',
team: 'evil',
description: "During the night, choose a villager to kill. Don't get killed."
description: 'During the night, choose a player to eliminate.'
},
{
role: 'Dream Wolf',
team: 'evil',
description: "You are a Werewolf, but you don't wake up with the other Werewolves until one of them dies."
description: 'You are a Werewolf, but you don\'t wake up with the other Werewolves until one of them dies.'
},
{
role: 'Sorceress',
@@ -22,12 +22,12 @@ export const defaultRoles = [
{
role: 'Knowing Minion',
team: 'evil',
description: 'You are an evil Villager, and you know who the Werewolves are.'
description: 'You are an evil Villager, and you know who the Werewolves are. You win if the Werewolves win.'
},
{
role: 'Blind Minion',
team: 'evil',
description: "You are an evil villager, but you don't know who the Werewolves are."
description: 'You are an evil villager, but you do NOT know who the Werewolves are. You win if the Werewolves win.'
},
{
role: 'Seer',
@@ -48,11 +48,11 @@ export const defaultRoles = [
{
role: 'Parity Hunter',
team: 'good',
description: 'You beat a werewolf in a 1v1 situation, winning the game for the village.'
description: 'If you and a Werewolf are the only two players remaining, the Village wins.'
},
{
role: 'Brutal Hunter',
team: 'good',
description: 'When you are eliminated, choose another player to go with you.'
description: 'When you are eliminated, choose another player to be eliminated with you.'
}
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -44,6 +44,7 @@ function getNavbarLinks (page = null, device) {
'<a class="' + linkClass + '" href="/create">Create</a>' +
'<a class="' + linkClass + '" href="/how-to-use">How to Use</a>' +
'<a class="' + linkClass + ' "href="mailto:play.werewolf.contact@gmail.com?Subject=Werewolf App" target="_top">Feedback</a>' +
'<a class="' + linkClass + ' "href="https://buymeacoffee.com/alecm33" target="_top">Support Me</a>' +
'<a class="' + linkClass + ' "href="https://github.com/alecm33/Werewolf" target="_top">Github</a>';
}

View File

@@ -500,7 +500,7 @@ function showButtons (back, forward, forwardHandler, backHandler, builtGame = nu
document.querySelector('#create-game')?.remove();
if (back) {
const backButton = document.createElement('button');
backButton.innerHTML = '<img alt="back" src="../../images/caret-back.svg"/>';
backButton.innerHTML = '<img alt="back" width="40" height="40" src="../../images/caret-back.svg"/>';
backButton.addEventListener('click', backHandler);
backButton.setAttribute('id', 'step-back-button');
backButton.classList.add('app-button');
@@ -509,7 +509,7 @@ function showButtons (back, forward, forwardHandler, backHandler, builtGame = nu
if (forward && builtGame === null) {
const fwdButton = document.createElement('button');
fwdButton.innerHTML = '<img alt="next" src="../../images/caret-forward.svg"/>';
fwdButton.innerHTML = '<img alt="next" width="40" height="40" src="../../images/caret-forward.svg"/>';
fwdButton.addEventListener('click', forwardHandler);
fwdButton.setAttribute('id', 'step-forward-button');
fwdButton.classList.add('app-button');

View File

@@ -18,7 +18,7 @@ import { InProgress } from '../game_state/states/InProgress.js';
import { Ended } from '../game_state/states/Ended.js';
export const gameHandler = (socket, window, gameDOM) => {
window.onunload = () => {
window.onpagehide = () => {
socket.close();
};
document.body.innerHTML = gameDOM + document.body.innerHTML;
@@ -60,8 +60,11 @@ export const gameHandler = (socket, window, gameDOM) => {
toast(err, 'error', true, false);
});
socket.on('disconnect', () => {
socket.on('disconnect', (reason) => {
toast('Disconnected. Attempting reconnect...', 'error', true, false);
if (reason === 'io client disconnect') { // see https://socket.io/docs/v4/client-api/#event-disconnect
socket.connect();
}
});
setClientSocketHandlers(stateBucket, socket);
resolve();

View File

@@ -46,9 +46,7 @@ function attemptToJoinGame (event) {
} else {
res.json().then(json => {
window.location = window.location.protocol + '//' + window.location.host +
'/join/' + encodeURIComponent(json.accessCode) +
'?playerCount=' + encodeURIComponent(json.playerCount) +
'&timer=' + encodeURIComponent(getTimeString(json.timerParams));
'/join/' + encodeURIComponent(json.accessCode);
});
}
}).catch(() => {
@@ -62,29 +60,6 @@ function attemptToJoinGame (event) {
}
}
function getTimeString (timerParams) {
let timeString = '';
if (timerParams) {
const hours = timerParams.hours;
const minutes = timerParams.minutes;
if (hours) {
timeString += hours > 1
? hours + ' hours '
: hours + ' hour ';
}
if (minutes) {
timeString += minutes > 1
? minutes + ' minutes '
: minutes + ' minute ';
}
return timeString;
} else {
timeString = 'untimed';
return timeString;
}
}
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = home;
} else {

View File

@@ -15,6 +15,7 @@ th, thead, tr, tt, u, ul, var {
@font-face {
font-family: 'signika-negative';
src: url("../webfonts/SignikaNegative-Light.woff2") format("woff2");
font-display: swap;
}
html {
@@ -68,131 +69,12 @@ textarea {
resize: none;
}
.toast-top {
top: 2rem;
}
.toast-bottom {
bottom: 140px;
}
.toast-success {
background-color: #bef5cb;
border: 3px solid #8ac78a;
}
.toast-warning {
background-color: #fff5b1;
border: 3px solid #c7c28a;
}
.toast-error {
background-color: #f98e9a;
border: 3px solid #c57272;
}
.toast-neutral {
background-color: #e9e9e9;
border: 3px solid #b7b7b7;
}
.toast-dispel-automatically {
animation: fade-in-slide-down-then-exit ease normal forwards;
}
.toast-not-dispelled-automatically {
animation: fade-in-slide-down ease normal forwards;
}
.toast-short {
animation-duration: 3s;
}
.toast-medium {
animation-duration: 5s;
}
.toast-long {
animation-duration: 8s;
}
.toast-plus-one {
color: #1c8a36;
font-weight: bold;
font-size: 20px;
margin-right: 5px;
}
.toast-minus-one {
font-size: 20px;
margin-right: 5px;
color: #e73333;
font-weight: bold;
}
.toast-plus-role-quantity {
color: #1c8a36;
font-weight: bold;
margin-left: 10px;
}
.toast-minus-role-quantity {
color: #e73333;
font-weight: bold;
margin-left: 10px;
}
#footer {
bottom: 0;
width: 100%;
text-align: center;
align-items: center;
display: flex;
justify-content: center;
flex-wrap: wrap;
color: #d7d7d7;
font-size: 14px;
margin-top: 4em;
margin-bottom: 0.5em;
}
#footer a:not([href='https://www.buymeacoffee.com/alecm33']) img {
width: 32px;
}
#footer a[href='https://www.buymeacoffee.com/alecm33'] img {
width: 200px;
}
#footer a {
color: #f7f7f7;
text-decoration: none;
cursor: pointer;
font-family: 'signika-negative', sans-serif;
margin: 0 0.25em;
}
#footer a:hover {
color: gray;
}
#footer div {
display: flex;
}
.teaser {
text-align:center;
color:gray;
margin-bottom:3em;
}
#footer > div, #footer > a {
margin: 0.5em;
}
#footer div:nth-child(2) > a, #footer div:nth-child(2) > p {
margin: 0 5px;
}
label {
color: #d7d7d7;
font-family: 'signika-negative', sans-serif;

View File

@@ -54,6 +54,10 @@ button#home-create-button {
margin: 0 15px;
}
#about-container div:nth-child(2) h2 {
margin-bottom: 2em;
}
#homepage-logos {
display: flex;
align-items: center;

111
client/src/styles/toast.css Normal file
View File

@@ -0,0 +1,111 @@
.toast-top {
top: 2rem;
}
.toast-bottom {
bottom: 140px;
}
.toast-success {
background-color: #bef5cb;
border: 3px solid #8ac78a;
}
.toast-warning {
background-color: #fff5b1;
border: 3px solid #c7c28a;
}
.toast-error {
background-color: #f98e9a;
border: 3px solid #c57272;
}
.toast-neutral {
background-color: #e9e9e9;
border: 3px solid #b7b7b7;
}
.toast-dispel-automatically {
animation: fade-in-slide-down-then-exit ease normal forwards;
}
.toast-not-dispelled-automatically {
animation: fade-in-slide-down ease normal forwards;
}
.toast-short {
animation-duration: 3s;
}
.toast-medium {
animation-duration: 5s;
}
.toast-long {
animation-duration: 8s;
}
.toast-plus-one {
color: #1c8a36;
font-weight: bold;
font-size: 20px;
margin-right: 5px;
}
.toast-minus-one {
font-size: 20px;
margin-right: 5px;
color: #e73333;
font-weight: bold;
}
.toast-plus-role-quantity {
color: #1c8a36;
font-weight: bold;
margin-left: 10px;
}
.toast-minus-role-quantity {
color: #e73333;
font-weight: bold;
margin-left: 10px;
}
@keyframes fade-in-slide-down-then-exit {
0% {
opacity: 0;
transform: translateY(-20px);
}
5% {
opacity: 1;
transform: translateY(0px);
}
95% {
opacity: 1;
transform: translateY(0px);
}
100% {
opacity: 0;
transform: translateY(-20px);
}
}
@keyframes fade-in-slide-down {
0% {
opacity: 0;
transform: translateY(-20px);
}
5% {
opacity: 1;
transform: translateY(0px);
}
95% {
opacity: 1;
transform: translateY(0px);
}
100% {
opacity: 1;
transform: translateY(0px);
}
}

View File

@@ -36,9 +36,9 @@ export const hiddenMenus =
<div tabindex="-1" id="custom-role-info-modal" class="modal">
<h3 id="custom-role-info-modal-name"></h3>
<div id="custom-role-info-modal-image-placeholder"></div>
<label for="custom-role-info-modal-alignment">alignment:</label>
<label>alignment:</label>
<div id="custom-role-info-modal-alignment"></div>
<label for="custom-role-info-modal-alignment">description:</label>
<label>description:</label>
<div id="custom-role-info-modal-description"></div>
<div class="modal-button-container single-button">
<button id="close-custom-role-info-modal-button" class="cancel app-button">Close</button>

View File

@@ -18,6 +18,8 @@
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="stylesheet" href="/styles/404.css">
<link rel="preload" href="./styles/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/toast.css"></noscript>
</head>
<body>
<div id="mobile-menu-background-overlay"></div>

View File

@@ -15,9 +15,13 @@
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="./styles/GLOBAL.css">
<link rel="stylesheet" href="./styles/create.css">
<link rel="stylesheet" href="./styles/modal.css">
<link rel="stylesheet" href="./styles/confirmation.css">
<link rel="preload" href="./styles/confirmation.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/confirmation.css"></noscript>
<link rel="preload" href="./styles/modal.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/modal.css"></noscript>
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="preload" href="./styles/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/toast.css"></noscript>
</head>
<body>
<div id="mobile-menu-background-overlay"></div>

View File

@@ -14,11 +14,14 @@
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/game.css">
<link rel="stylesheet" href="/styles/create.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/confirmation.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="preload" href="/webfonts/SignikaNegative-Light.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/styles/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/toast.css"></noscript>
<link rel="preload" href="/styles/create.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/create.css"></noscript>
</head>
<body>
<script src="/dist/game-bundle.js.gz"></script>

View File

@@ -11,15 +11,464 @@
<meta property="og:url" content="https://play-werewolf.app">
<meta property="og:description" content="An app to create and run games of Werewolf (Mafia) with your friends. No sign-up, installation, or payment required.">
<meta property="og:image" content="image.png">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="./styles/GLOBAL.css">
<link rel="stylesheet" href="./styles/home.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="stylesheet" href="./styles/confirmation.css">
<link rel="preload" href="./styles/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/toast.css"></noscript>
<style>
canvas, caption, center, cite, code,
dd, del, dfn, div, dl, dt, em, embed,
fieldset, font, form, h1, h2, h3, h4,
h5, h6, hr, i, iframe, img, ins, kbd,
label, legend, li, menu, object, ol, p,
pre, q, s, samp, small, span, strike,
strong, sub, sup, table, tbody, td, tfoot,
th, thead, tr, tt, u, ul, var {
margin: 0;
padding: 0;
border: 0;
background: transparent;
}
@font-face {
font-family: 'signika-negative';
src: url("../webfonts/SignikaNegative-Light.woff2") format("woff2");
font-display: swap;
}
html {
font-family: 'signika-negative', sans-serif !important;
background-color: #0f0f10;
overflow: auto;
}
body {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 0 auto;
background-color: #0f0f10;
}
h2 {
color: #e7e7e7;
font-size: 25px;
font-weight: bold;
}
label {
color: #d7d7d7;
font-family: 'signika-negative', sans-serif;
font-size: 20px;
font-weight: normal;
}
input, textarea {
background-color: transparent;
border: 1px solid white;
border-radius: 5px;
color: #d7d7d7;
}
a {
text-decoration: none;
}
textarea, input {
font-family: 'signika-negative', sans-serif;
font-size: 16px;
}
button {
display: flex;
align-items: center;
justify-content: center;
}
.app-button, input[type="submit"] {
font-family: 'signika-negative', sans-serif !important;
padding: 10px;
background-color: #1a7a31;
border-radius: 5px;
color: #e7e7e7;
font-size: 18px;
cursor: pointer;
border: 3px solid transparent;
text-shadow: 0 3px 4px rgb(0 0 0 / 55%);
}
.app-button:active, input[type=submit]:active {
border: 3px solid #21ba45;
}
.submitted {
filter: opacity(0.5);
pointer-events: none;
}
.app-button:hover, input[type="submit"]:hover, #game-link:hover {
background-color: #326243;
border: 3px solid #1a7a31;
}
input {
padding: 10px;
}
.info-message {
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
z-index: 1000000;
padding: 10px;
border-radius: 5px;
font-family: 'signika-negative', sans-serif;
font-weight: 100;
box-shadow:
0 1px 1px rgba(0,0,0,0.11),
0 2px 2px rgba(0,0,0,0.11),
0 4px 4px rgba(0,0,0,0.11),
0 8px 8px rgba(0,0,0,0.11),
0 16px 16px rgba(0,0,0,0.11),
0 32px 32px rgba(0,0,0,0.11);
left: 0;
right: 0;
width: fit-content;
max-width: 80%;
min-width: 15em;
font-size: 20px;
margin: 0 auto;
}
#navbar {
display: flex;
align-items: center;
padding: 10px 0;
width: 100%;
background-color: #0f0f10;
height: 45px;
z-index: 53000;
}
#desktop-links > a:nth-child(1) {
margin: 0 0.5em;
width: 50px;
}
#mobile-links a:nth-child(1) {
width: 80px;
margin: 0 auto 3em auto !important;
display: flex;
}
.logo {
display: flex;
align-items: center;
}
#navbar img {
width: 100%;
}
#navbar a:not(.logo) {
color: #f7f7f7;
text-decoration: none;
cursor: pointer;
font-family: 'signika-negative', sans-serif;
border-radius: 5px;
padding: 2px 5px;
font-size: 20px;
margin: 1em;
width: fit-content;
}
#navbar a:hover {
color: gray;
}
.overlay {
position: fixed;
background-size: cover;
height: 100%;
opacity: 75%;
background-color: black;
width: 100%;
z-index: 50000;
}
.hidden {
display: none !important;
}
#mobile-links {
display: flex;
flex-direction: column;
margin-top: 3em;
}
.mobile-link {
margin-top: 1em !important;
margin-left: 2em !important;
}
@media(max-width: 1000px) {
#navbar {
display: flex;
padding: 0;
}
#navbar-hamburger {
z-index: 52000;
position: relative;
}
#desktop-menu {
display: none;
}
#mobile-menu {
position: absolute;
top: 0;
left: 0;
height: auto;
padding-bottom: 2em;
width: 100%;
z-index: 51000;
background-color: #1e1e1e;
}
}
@media(min-width: 1001px) {
#navbar-hamburger, #mobile-menu, #mobile-menu-background-overlay {
display: none;
}
.desktop-link {
display: flex;
}
#desktop-links {
display: flex;
align-items: center;
}
}
@media(max-width: 550px) {
h1 {
font-size: 30px;
}
#step-1 div {
font-size: 20px;
}
.info-message {
padding: 5px;
font-size: 16px;
}
}
body {
align-items: center;
}
button#home-create-button {
padding: 20px;
}
#framed-phone-screenshot, #framed-phone-screenshot-2, .framed-phone-screenshot-container {
max-width: 250px;
width: 40vw;
min-width: 175px;
border-radius: 21px;
aspect-ratio: 1522 / 3290;
}
.framed-phone-screenshot-container {
margin: 0 0 20px 0;
border: 1px solid #464552;
}
#about-container {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
width: 100%;
}
#about-container > div {
display: flex;
align-items: center;
justify-content: center;
width: fit-content;
flex-wrap: wrap;
padding: 25px 0;
}
#join-container form {
margin: 0;
}
#about-container h2 {
max-width: 17em;
font-size: 22px;
border-left: 1px solid #bababa;
padding: 15px;
margin: 0 15px;
}
#about-container div:nth-child(2) h2 {
margin-bottom: 2em;
}
#homepage-logos {
display: flex;
align-items: center;
}
#home-page-top-section {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
background-color: #0f0f10;
}
form {
display: flex;
flex-wrap: wrap;
margin: 10px 0;
border-radius: 5px;
justify-content: center;
align-items: center;
}
a button {
text-shadow: 0 3px 4px rgb(0 0 0 / 85%);
}
#join-button {
min-width: 6em;
max-height: 3em;
background-color: #1c8a36;
color: #e7e7e7;
font-size: 16px;
}
#join-button:hover {
background-color: #326243;
border: 2px solid #1c8a36;
}
#join-form div:nth-child(1) {
margin-right: 0.5em;
}
h3 {
color: #d7d7d7;
font-weight: normal;
font-size: 20px;
margin-bottom: 1em;
padding: 1em;
max-width: 23em;
font-family: 'signika-negative', sans-serif;
}
img[src='../images/new-logo.png'], #new-logo-container {
max-width: 250px;
width: 25vw;
min-width: 150px;
margin: 1em 0 1em 0;
aspect-ratio: 500 / 641;
}
h3 a {
color: #768df0;
text-decoration: underline;
cursor: pointer;
font-family: 'signika-negative', sans-serif;
width: fit-content;
}
h3 a:hover {
color: gray;
}
form > div {
margin: 15px 0;
}
#create-join {
width: 100%;
max-width: 900px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-evenly;
margin-bottom: 1em;
}
#join-container {
max-width: 90%;
border: 1px solid #55555599;
background: #5555555c;
padding: 0.5em;
border-radius: 5px;
margin: 20px
}
#join-container > label {
font-size: 35px;
font-family: 'signika-negative', sans-serif;
color: #e7e7e7;
filter: drop-shadow(2px 2px 4px black);
}
#room-code {
background-color: #1e1e1e;
}
label[for="room-code"], label[for="player-name"] {
margin-right: 0.5em;
}
@media (min-width: 700px) {
button#home-create-button {
font-size: 30px;
}
}
@media (max-width: 701px) {
button#home-create-button {
font-size: 5vw;
padding: 15px;
}
img[src='../images/new-logo.png'], #new-logo-container {
margin: 1em 0 0 0;
}
#join-container > label {
font-size: 26px;
}
#room-code {
max-width: 9em;
}
#about-container h2 {
font-size: 18px;
}
}
</style>
</head>
<body>
<div id="mobile-menu-background-overlay"></div>
@@ -34,7 +483,7 @@
<button id="home-create-button" class="app-button">Create A Room</button>
</a>
<div id="join-container">
<label for="join-form">Join A Room</label>
<label>Join A Room</label>
<form id="join-form">
<div>
<label for="room-code">Room Code</label>
@@ -48,24 +497,17 @@
<div id="about-container">
<div>
<div class="framed-phone-screenshot-container">
<img id="framed-phone-screenshot" alt="framed phone screenshot" src="../images/framed-phone-screenshot.webp"/>
<img id="framed-phone-screenshot" alt="framed phone screenshot" src="../images/framed-phone-screenshot_resized.webp"/>
</div>
<h2>Join a game and have a role dealt to your device.</h2>
</div>
<div>
<div class="framed-phone-screenshot-container">
<img id="framed-phone-screenshot-2" alt="framed phone screenshot" src="../images/framed-phone-screenshot-2.webp"/>
<img id="framed-phone-screenshot-2" alt="framed phone screenshot" src="../images/framed-phone-screenshot-2_resized.webp"/>
</div>
<h2>Create your own game with default or custom roles.</h2>
</div>
</div>
<footer id="footer">
<a href="https://www.buymeacoffee.com/alecm33"><img alt="Buy Me a Coffee" src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=alecm33&button_colour=252525&font_colour=d7d7d7&font_family=Lato&outline_colour=d7d7d7&coffee_colour=d7d7d7" /></a>
<div>
<a aria-label="view the project on Github" href="https://github.com/AlecM33/Werewolf"><img alt="Github" src='/images/GitHub-Mark-Light-120px-plus.png'/></a>
<a aria-label="email the creator with questions" href="mailto:play.werewolf.contact@gmail.com?Subject=Werewolf App" target="_top"><img alt="email" src='/images/email.svg'/></a>
</div>
</footer>
<script src="/dist/home-bundle.js.gz"></script>
</body>
</html>

View File

@@ -14,8 +14,6 @@
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/create.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
</head>
<body>

View File

@@ -12,11 +12,274 @@
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/styles/GLOBAL.css">
<link rel="stylesheet" href="/styles/join.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="stylesheet" href="/styles/hamburgers.css">
<link rel="stylesheet" href="/styles/modal.css">
<link rel="preload" href="/styles/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./styles/toast.css"></noscript>
<link rel="preload" href="/webfonts/SignikaNegative-Light.woff2" as="font" type="font/woff2" crossorigin>
<style>
canvas, caption, center, cite, code,
dd, del, dfn, div, dl, dt, em, embed,
fieldset, font, form, h1, h2, h3, h4,
h5, h6, hr, i, iframe, img, ins, kbd,
label, legend, li, menu, object, ol, p,
pre, q, s, samp, small, span, strike,
strong, sub, sup, table, tbody, td, tfoot,
th, thead, tr, tt, u, ul, var {
margin: 0;
padding: 0;
border: 0;
background: transparent;
}
@font-face {
font-family: 'signika-negative';
src: url("../webfonts/SignikaNegative-Light.woff2") format("woff2");
font-display: swap;
}
html {
font-family: 'signika-negative', sans-serif !important;
background-color: #0f0f10;
overflow: auto;
}
body {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 0 auto;
background-color: #0f0f10;
}
label {
color: #d7d7d7;
font-family: 'signika-negative', sans-serif;
font-size: 20px;
font-weight: normal;
}
input, textarea {
background-color: transparent;
border: 1px solid white;
border-radius: 5px;
color: #d7d7d7;
}
a {
text-decoration: none;
}
textarea, input {
font-family: 'signika-negative', sans-serif;
font-size: 16px;
}
button {
display: flex;
align-items: center;
justify-content: center;
}
.app-button, input[type="submit"] {
font-family: 'signika-negative', sans-serif !important;
padding: 10px;
background-color: #1a7a31;
border-radius: 5px;
color: #e7e7e7;
font-size: 18px;
cursor: pointer;
border: 3px solid transparent;
text-shadow: 0 3px 4px rgb(0 0 0 / 55%);
}
.app-button:active, input[type=submit]:active {
border: 3px solid #21ba45;
}
.submitted {
filter: opacity(0.5);
pointer-events: none;
}
.app-button:hover, input[type="submit"]:hover, #game-link:hover {
background-color: #326243;
border: 3px solid #1a7a31;
}
#game-parameters {
font-family: signika-negative, sans-serif;
color: #d7d7d7;
font-size: 20px;
}
#game-parameters > div {
display: flex;
align-items: center;
font-size: 25px;
}
input {
padding: 10px;
}
.info-message {
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
z-index: 1000000;
padding: 10px;
border-radius: 5px;
font-family: 'signika-negative', sans-serif;
font-weight: 100;
box-shadow:
0 1px 1px rgba(0,0,0,0.11),
0 2px 2px rgba(0,0,0,0.11),
0 4px 4px rgba(0,0,0,0.11),
0 8px 8px rgba(0,0,0,0.11),
0 16px 16px rgba(0,0,0,0.11),
0 32px 32px rgba(0,0,0,0.11);
left: 0;
right: 0;
width: fit-content;
max-width: 80%;
min-width: 15em;
font-size: 20px;
margin: 0 auto;
}
#navbar {
display: flex;
align-items: center;
padding: 10px 0;
width: 100%;
background-color: #0f0f10;
height: 45px;
z-index: 53000;
}
#desktop-links > a:nth-child(1) {
margin: 0 0.5em;
width: 50px;
}
#mobile-links a:nth-child(1) {
width: 80px;
margin: 0 auto 3em auto !important;
display: flex;
}
.logo {
display: flex;
align-items: center;
}
#navbar img {
width: 100%;
}
#navbar a:not(.logo) {
color: #f7f7f7;
text-decoration: none;
cursor: pointer;
font-family: 'signika-negative', sans-serif;
border-radius: 5px;
padding: 2px 5px;
font-size: 20px;
margin: 1em;
width: fit-content;
}
#navbar a:hover {
color: gray;
}
.overlay {
position: fixed;
background-size: cover;
height: 100%;
opacity: 75%;
background-color: black;
width: 100%;
z-index: 50000;
}
.hidden {
display: none !important;
}
#mobile-links {
display: flex;
flex-direction: column;
margin-top: 3em;
}
.mobile-link {
margin-top: 1em !important;
margin-left: 2em !important;
}
@media(max-width: 1000px) {
#navbar {
display: flex;
padding: 0;
}
#navbar-hamburger {
z-index: 52000;
position: relative;
}
#desktop-menu {
display: none;
}
#mobile-menu {
position: absolute;
top: 0;
left: 0;
height: auto;
padding-bottom: 2em;
width: 100%;
z-index: 51000;
background-color: #1e1e1e;
}
}
@media(min-width: 1001px) {
#navbar-hamburger, #mobile-menu, #mobile-menu-background-overlay {
display: none;
}
.desktop-link {
display: flex;
}
#desktop-links {
display: flex;
align-items: center;
}
}
@media(max-width: 550px) {
h1 {
font-size: 30px;
}
#step-1 div {
font-size: 20px;
}
.info-message {
padding: 5px;
font-size: 16px;
}
}
</style>
</head>
<body>
<div id="mobile-menu-background-overlay"></div>

View File

@@ -15,7 +15,7 @@ module.exports = {
path: path.resolve(__dirname, '../dist'),
filename: "[name]-bundle.js"
},
plugins: [new CompressionPlugin({ deleteOriginalAssets: true, exclude: [/521-bundle.js$/]})],
plugins: [new CompressionPlugin({ deleteOriginalAssets: true, exclude: [/\d+-bundle.js$/]})],
mode: "production",
node: false,
module: {

6312
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,24 +21,24 @@
},
"main": "index.js",
"engines": {
"node": ">= 14.0.0"
"node": ">= 20.0.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-loader": "^8.2.3",
"body-parser": "^1.20.1",
"body-parser": "^1.20.3",
"compression-webpack-plugin": "^10.0.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"express": "^4.21.1",
"express-force-https": "^1.0.0",
"express-rate-limit": "^6.0.1",
"open": "^7.0.3",
"rate-limiter-flexible": "^2.3.6",
"redis": "^4.5.1",
"regenerator-runtime": "^0.13.9",
"socket.io": "^4.6.1",
"socket.io-client": "^4.5.4"
"socket.io": "^4.8.1",
"socket.io-client": "^4.7.5"
},
"devDependencies": {
"@babel/core": "^7.18.13",
@@ -59,7 +59,7 @@
"karma": "^6.3.16",
"karma-chrome-launcher": "^3.1.0",
"karma-jasmine": "^4.0.1",
"webpack": "^5.76.0",
"webpack": "^5.94.0",
"webpack-cli": "^4.9.1",
"webpack-remove-debug": "^0.1.0"
},

View File

@@ -191,7 +191,7 @@ class GameManager {
&& game.people.filter(person => person.userType === USER_TYPES.SPECTATOR).length === PRIMITIVES.MAX_SPECTATORS
) {
return Promise.reject({ status: 400, reason: 'There are too many people already spectating.' });
} else if (joinAsSpectator || this.isGameStartable(game)) {
} else if (joinAsSpectator || this.isGameStartable(game) || game.status === STATUS.IN_PROGRESS) {
return await addSpectator(game, name, this.logger, this.namespace, this.eventManager, this.instanceId, this.refreshGame);
}
let moderator, newPlayer;