mirror of
https://github.com/AlecM33/Werewolf.git
synced 2026-01-01 16:59:29 +01:00
role importing/exporting
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
export const globals = {
|
||||
USER_SIGNATURE_LENGTH: 25,
|
||||
CLOCK_TICK_INTERVAL_MILLIS: 10,
|
||||
MAX_CUSTOM_ROLE_NAME_LENGTH: 30,
|
||||
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 500,
|
||||
TOAST_DURATION_DEFAULT: 6,
|
||||
ACCESS_CODE_LENGTH: 6,
|
||||
PLAYER_ID_COOKIE_KEY: 'play-werewolf-anon-id',
|
||||
|
||||
1
client/src/images/add.svg
Normal file
1
client/src/images/add.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="#00a718" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="384px" height="384px"><path d="M 12 2 C 6.4889971 2 2 6.4889971 2 12 C 2 17.511003 6.4889971 22 12 22 C 17.511003 22 22 17.511003 22 12 C 22 6.4889971 17.511003 2 12 2 z M 12 4 C 16.430123 4 20 7.5698774 20 12 C 20 16.430123 16.430123 20 12 20 C 7.5698774 20 4 16.430123 4 12 C 4 7.5698774 7.5698774 4 12 4 z M 11 7 L 11 11 L 7 11 L 7 13 L 11 13 L 11 17 L 13 17 L 13 13 L 17 13 L 17 11 L 13 11 L 13 7 L 11 7 z"/></svg>
|
||||
|
After Width: | Height: | Size: 502 B |
14
client/src/images/delete.svg
Normal file
14
client/src/images/delete.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="209" height="209" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="172" width="172" y="-1" x="-1"/>
|
||||
<g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid">
|
||||
<rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<path id="svg_1" d="m0.749996,50.93695l50.18695,-50.18695l53.312819,53.312382l53.312819,-53.312382l50.187422,50.18695l-53.312833,53.312819l53.312833,53.312819l-50.187422,50.187422l-53.312819,-53.312833l-53.312819,53.312833l-50.18695,-50.187422l53.312382,-53.312819l-53.312382,-53.312819z" stroke-width="0" stroke="none" fill="#e73333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 842 B |
@@ -1,14 +1 @@
|
||||
<svg width="223" height="223" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="225" width="225" y="-1" x="-1"/>
|
||||
<g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid">
|
||||
<rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<path id="svg_1" d="m111.499982,3.500023c-59.646658,0 -107.999967,48.353386 -107.999967,107.999967c0,59.647903 48.353308,107.999993 107.999967,107.999993c59.647946,0 107.999993,-48.352082 107.999993,-107.999993c0,-59.646581 -48.352047,-107.999967 -107.999993,-107.999967zm-9.236728,48.553238l17.983007,0l0,19.128161l-17.983007,0l0,-19.128161zm29.760957,116.085726l-19.780144,0c-7.684691,0 -10.961591,-3.269729 -10.961591,-11.117474l0,-51.012233c0,-2.452006 -1.306774,-3.597168 -3.595768,-3.597168l-6.539459,0l0,-17.662679l19.781535,0c7.690393,0 10.953072,3.432714 10.953072,11.116049l0,51.176601c0,2.296157 1.306782,3.597237 3.595768,3.597237l6.539537,0l0,17.499659l0.00705,0l0,0.000009z" stroke-width="1.5" stroke="none" fill="#d7d7d7"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0"?><svg fill="#d7d7d7" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="384px" height="384px"> <path d="M 12 2 C 6.4889971 2 2 6.4889971 2 12 C 2 17.511003 6.4889971 22 12 22 C 17.511003 22 22 17.511003 22 12 C 22 6.4889971 17.511003 2 12 2 z M 12 4 C 16.430123 4 20 7.5698774 20 12 C 20 16.430123 16.430123 20 12 20 C 7.5698774 20 4 16.430123 4 12 C 4 7.5698774 7.5698774 4 12 4 z M 11 7 L 11 9 L 13 9 L 13 7 L 11 7 z M 11 11 L 11 17 L 13 17 L 13 11 L 11 11 z"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 505 B |
14
client/src/images/pencil.svg
Normal file
14
client/src/images/pencil.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="132" height="192" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="194" width="134" y="-1" x="-1"/>
|
||||
<g display="none" overflow="visible" y="0" x="0" height="100%" width="100%" id="canvasGrid">
|
||||
<rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<path id="svg_2" d="m124.961908,17.099698l-20.881294,-13.124489c-5.268417,-3.308101 -12.210471,-1.715912 -15.530119,3.553603l-8.230499,13.1l39.946799,25.089697l8.23699,-13.093919c3.307049,-5.275788 1.728716,-12.224161 -3.541878,-15.524891l0,0zm-115.727379,116.707156l39.948976,25.089439l65.110209,-103.65022l-39.967994,-25.095989l-65.091198,103.656764l0.000007,0.000007zm-6.102198,31.877066l-0.88233,23.566079l20.849261,-11.027851l19.374887,-10.229887l-38.540057,-24.219893l-0.801755,21.911559l0,0l-0.000007,-0.000007z" stroke-width="4.5" stroke="none" fill="#d7d7d7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,3 +1,7 @@
|
||||
import { globals } from "../config/globals.js";
|
||||
import {toast} from "./Toast.js";
|
||||
import {ModalManager} from "./ModalManager";
|
||||
|
||||
export class DeckStateManager {
|
||||
constructor() {
|
||||
this.deck = null;
|
||||
@@ -15,6 +19,16 @@ export class DeckStateManager {
|
||||
|
||||
addToCustomRoleOptions(role) {
|
||||
this.customRoleOptions.push(role);
|
||||
localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true))));
|
||||
}
|
||||
|
||||
removeFromCustomRoleOptions(name) {
|
||||
let option = this.customRoleOptions.find((option) => option.role === name);
|
||||
if (option) {
|
||||
this.customRoleOptions.splice(this.customRoleOptions.indexOf(option), 1);
|
||||
localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true))));
|
||||
toast('"' + name + '" deleted.', 'error', true, true, 3);
|
||||
}
|
||||
}
|
||||
|
||||
addCopyOfCard(role) {
|
||||
@@ -54,4 +68,82 @@ export class DeckStateManager {
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
loadCustomRolesFromCookies() {
|
||||
let customRoles = localStorage.getItem('play-werewolf-custom-roles');
|
||||
if (customRoles !== null && validateCustomRoleCookie(customRoles)) {
|
||||
this.customRoleOptions = JSON.parse(customRoles); // we know it is valid JSON from the validate function
|
||||
}
|
||||
}
|
||||
|
||||
loadCustomRolesFromFile(file, updateRoleListFunction, loadDefaultCardsFn, showIncludedCardsFn) {
|
||||
let reader = new FileReader();
|
||||
reader.onerror = (e) => {
|
||||
toast(reader.error.message, "error", true, true, 5);
|
||||
}
|
||||
reader.onload = (e) => {
|
||||
let string;
|
||||
if (typeof e.target.result !== "string") {
|
||||
string = new TextDecoder("utf-8").decode(e.target.result);
|
||||
} else {
|
||||
string = e.target.result;
|
||||
}
|
||||
if (validateCustomRoleCookie(string)) {
|
||||
this.customRoleOptions = JSON.parse(string); // we know it is valid JSON from the validate function
|
||||
ModalManager.dispelModal("upload-custom-roles-modal", "modal-background");
|
||||
toast("Roles imported successfully", "success", true, true, 3);
|
||||
localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions));
|
||||
updateRoleListFunction(this, document.getElementById("deck-select"));
|
||||
// loadDefaultCardsFn(this);
|
||||
// showIncludedCardsFn(this);
|
||||
} else {
|
||||
toast("Invalid formatting. Make sure you import the file as downloaded from this page.", "error", true, true, 5);
|
||||
}
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
// via https://stackoverflow.com/a/18197341
|
||||
downloadCustomRoles(filename, text) {
|
||||
let element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
element.setAttribute('download', filename);
|
||||
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// this is user-supplied, so we should validate it fully
|
||||
function validateCustomRoleCookie(cookie) {
|
||||
let valid = false;
|
||||
if (typeof cookie === "string" && new Blob([cookie]).size <= 1000000) {
|
||||
try {
|
||||
let cookieJSON = JSON.parse(cookie);
|
||||
if (Array.isArray(cookieJSON)) {
|
||||
for (let entry of cookieJSON) {
|
||||
if (typeof entry === "object") {
|
||||
if (typeof entry.role !== "string" || entry.role.length > globals.MAX_CUSTOM_ROLE_NAME_LENGTH
|
||||
|| typeof entry.team !== "string" || (entry.team !== globals.ALIGNMENT.GOOD && entry.team !== globals.ALIGNMENT.EVIL)
|
||||
|| typeof entry.description !== "string" || entry.description.length > globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import { ModalManager } from "./ModalManager.js";
|
||||
import {XHRUtility} from "./XHRUtility.js";
|
||||
import {globals} from "../config/globals.js";
|
||||
import {templates} from "./Templates.js";
|
||||
import {defaultCards} from "../config/defaultCards";
|
||||
|
||||
export class GameCreationStepManager {
|
||||
constructor(deckManager) {
|
||||
loadDefaultCards(deckManager);
|
||||
deckManager.loadCustomRolesFromCookies();
|
||||
this.step = 1;
|
||||
this.currentGame = new Game(null, null, null, null);
|
||||
this.deckManager = deckManager;
|
||||
@@ -197,6 +200,35 @@ function renderRoleSelectionStep(game, containerId, step, deckManager) {
|
||||
stepContainer.innerHTML += templates.CREATE_GAME_DECK;
|
||||
|
||||
document.getElementById(containerId).appendChild(stepContainer);
|
||||
document.querySelector('#custom-roles-export').addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
deckManager.downloadCustomRoles('play-werewolf-custom-roles', JSON.stringify(deckManager.getCurrentCustomRoleOptions()));
|
||||
});
|
||||
|
||||
document.querySelector('#custom-roles-import').addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
ModalManager.displayModal("upload-custom-roles-modal", "modal-background", "close-upload-custom-roles-modal-button");
|
||||
});
|
||||
|
||||
document.getElementById("upload-custom-roles-form").onsubmit = (e) => {
|
||||
e.preventDefault();
|
||||
let fileList = document.getElementById("upload-custom-roles").files;
|
||||
if (fileList.length > 0) {
|
||||
let file = fileList[0];
|
||||
if (file.size > 1000000) {
|
||||
toast("Your file is too large (max 1MB)", "error", true, true, 5);
|
||||
return;
|
||||
}
|
||||
if (file.type !== "text/plain") {
|
||||
toast("Your file must be a text file", "error", true, true, 5);
|
||||
return;
|
||||
}
|
||||
|
||||
deckManager.loadCustomRolesFromFile(file, updateCustomRoleOptionsList, loadDefaultCards, showIncludedCards);
|
||||
} else {
|
||||
toast("You must upload a text file", "error", true, true, 5);
|
||||
}
|
||||
}
|
||||
|
||||
let clickHandler = () => {
|
||||
console.log("fired");
|
||||
@@ -208,9 +240,9 @@ function renderRoleSelectionStep(game, containerId, step, deckManager) {
|
||||
}
|
||||
};
|
||||
|
||||
//document.getElementById("custom-role-hamburger").addEventListener("click", clickHandler);
|
||||
document.getElementById("custom-role-hamburger").addEventListener("click", clickHandler);
|
||||
|
||||
loadIncludedCards(deckManager);
|
||||
showIncludedCards(deckManager);
|
||||
|
||||
loadCustomRoles(deckManager);
|
||||
|
||||
@@ -354,8 +386,9 @@ function showButtons(back, forward, forwardHandler, backHandler, builtGame=null)
|
||||
}
|
||||
|
||||
// Display a widget for each default card that allows copies of it to be added/removed. Set initial deck state.
|
||||
function loadIncludedCards(deckManager) {
|
||||
for (let i = 0; i < deckManager.getCurrentDeck().length; i ++) { // each dropdown should include every
|
||||
function showIncludedCards(deckManager) {
|
||||
document.querySelectorAll('.compact-card').forEach((el) => { el.remove() });
|
||||
for (let i = 0; i < deckManager.getCurrentDeck().length; i ++) {
|
||||
let card = deckManager.getCurrentDeck()[i];
|
||||
let cardEl = constructCompactDeckBuilderElement(card, deckManager);
|
||||
if (card.team === globals.ALIGNMENT.GOOD) {
|
||||
@@ -370,25 +403,23 @@ function loadIncludedCards(deckManager) {
|
||||
create a widget for it */
|
||||
function loadCustomRoles(deckManager) {
|
||||
let select = document.getElementById("deck-select");
|
||||
addOptionsToList(deckManager.getCurrentCustomRoleOptions(), document.getElementById("deck-select"));
|
||||
document.getElementById("include-role").addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (select.value && select.value.length > 0) {
|
||||
if (!deckManager.getCard(select.value)) {
|
||||
deckManager.addToDeck(select.value);
|
||||
let cardEl = constructCompactDeckBuilderElement(deckManager.getCard(select.value), deckManager);
|
||||
toast('"' + select.value + '" included.', 'success', true, true, 3);
|
||||
if (deckManager.getCard(select.value).team === globals.ALIGNMENT.GOOD) {
|
||||
document.getElementById("deck-good").appendChild(cardEl);
|
||||
} else {
|
||||
document.getElementById("deck-evil").appendChild(cardEl);
|
||||
}
|
||||
updateCustomRoleOptionsList(deckManager, select);
|
||||
} else {
|
||||
toast('"' + select.value + '" already included.', 'error', true, true, 3);
|
||||
}
|
||||
addOptionsToList(deckManager, document.getElementById("deck-select"));
|
||||
}
|
||||
|
||||
function loadDefaultCards(deckManager) {
|
||||
defaultCards.sort((a, b) => {
|
||||
if (a.team !== b.team) {
|
||||
return a.team === globals.ALIGNMENT.GOOD ? 1 : -1;
|
||||
}
|
||||
})
|
||||
return a.role.localeCompare(b.role);
|
||||
});
|
||||
let deck = [];
|
||||
for (let i = 0; i < defaultCards.length; i ++) {
|
||||
let card = defaultCards[i];
|
||||
card.quantity = 0;
|
||||
deck.push(card);
|
||||
}
|
||||
deckManager.deck = deck;
|
||||
}
|
||||
|
||||
function constructCompactDeckBuilderElement(card, deckManager) {
|
||||
@@ -453,9 +484,9 @@ function initializeRemainingEventListeners(deckManager) {
|
||||
toast('Your description is too long (max 500 characters).', "error", true);
|
||||
return;
|
||||
}
|
||||
deckManager.addToCustomRoleOptions({role: name, description: description, team: team});
|
||||
deckManager.addToCustomRoleOptions({role: name, description: description, team: team, custom: true});
|
||||
updateCustomRoleOptionsList(deckManager, document.getElementById("deck-select"))
|
||||
ModalManager.dispelModal("add-role-modal", "add-role-modal-background");
|
||||
ModalManager.dispelModal("add-role-modal", "modal-background");
|
||||
toast("Role Created", "success", true);
|
||||
} else {
|
||||
toast("There is already a role with this name", "error", true, true, 3);
|
||||
@@ -465,7 +496,7 @@ function initializeRemainingEventListeners(deckManager) {
|
||||
"click", () => {
|
||||
ModalManager.displayModal(
|
||||
"add-role-modal",
|
||||
"add-role-modal-background",
|
||||
"modal-background",
|
||||
"close-modal-button"
|
||||
)
|
||||
}
|
||||
@@ -473,11 +504,12 @@ function initializeRemainingEventListeners(deckManager) {
|
||||
}
|
||||
|
||||
function updateCustomRoleOptionsList(deckManager, selectEl) {
|
||||
document.querySelectorAll('#deck-select option').forEach(e => e.remove());
|
||||
addOptionsToList(deckManager.customRoleOptions, selectEl);
|
||||
document.querySelectorAll('#deck-select .deck-select-role').forEach(e => e.remove());
|
||||
addOptionsToList(deckManager, selectEl);
|
||||
}
|
||||
|
||||
function addOptionsToList(options, selectEl) {
|
||||
function addOptionsToList(deckManager, selectEl) {
|
||||
let options = deckManager.getCurrentCustomRoleOptions();
|
||||
options.sort((a, b) => {
|
||||
if (a.team !== b.team) {
|
||||
return a.team === globals.ALIGNMENT.GOOD ? 1 : -1;
|
||||
@@ -485,29 +517,72 @@ function addOptionsToList(options, selectEl) {
|
||||
return a.role.localeCompare(b.role);
|
||||
});
|
||||
for (let i = 0; i < options.length; i ++) {
|
||||
let optionEl = document.createElement("option");
|
||||
let optionEl = document.createElement("div");
|
||||
optionEl.innerHTML = templates.DECK_SELECT_ROLE;
|
||||
optionEl.classList.add('deck-select-role');
|
||||
let alignmentClass = options[i].team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL
|
||||
optionEl.classList.add(alignmentClass);
|
||||
optionEl.setAttribute("value", options[i].role);
|
||||
optionEl.innerText = options[i].role;
|
||||
optionEl.querySelector('.deck-select-role-name').innerText = options[i].role;
|
||||
selectEl.appendChild(optionEl);
|
||||
}
|
||||
|
||||
addCustomRoleEventListeners(deckManager, selectEl);
|
||||
}
|
||||
|
||||
function addCustomRoleEventListeners(deckManager, select) {
|
||||
document.querySelectorAll('.deck-select-role').forEach((role) => {
|
||||
let name = role.querySelector('.deck-select-role-name').innerText;
|
||||
role.querySelector('.deck-select-include').addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (!deckManager.getCard(name)) {
|
||||
deckManager.addToDeck(name);
|
||||
let cardEl = constructCompactDeckBuilderElement(deckManager.getCard(name), deckManager);
|
||||
toast('"' + name + '" included.', 'success', true, true, 3);
|
||||
if (deckManager.getCard(name).team === globals.ALIGNMENT.GOOD) {
|
||||
document.getElementById("deck-good").appendChild(cardEl);
|
||||
} else {
|
||||
document.getElementById("deck-evil").appendChild(cardEl);
|
||||
}
|
||||
updateCustomRoleOptionsList(deckManager, select);
|
||||
} else {
|
||||
toast('"' + select.value + '" already included.', 'error', true, true, 3);
|
||||
}
|
||||
});
|
||||
|
||||
role.querySelector('.deck-select-remove').addEventListener('click', (e) => {
|
||||
if (confirm("Delete the role '" + name + "'?")) {
|
||||
e.preventDefault();
|
||||
deckManager.removeFromCustomRoleOptions(name);
|
||||
updateCustomRoleOptionsList(deckManager, select);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function updateDeckStatus(deckManager) {
|
||||
document.querySelectorAll('.deck-role').forEach((el) => el.remove());
|
||||
document.getElementById("deck-count").innerText = deckManager.getDeckSize() + " Players";
|
||||
for (let card of deckManager.getCurrentDeck()) {
|
||||
if (card.quantity > 0) {
|
||||
let roleEl = document.createElement("div");
|
||||
roleEl.classList.add('deck-role');
|
||||
if (card.team === globals.ALIGNMENT.GOOD) {
|
||||
roleEl.classList.add(globals.ALIGNMENT.GOOD);
|
||||
} else {
|
||||
roleEl.classList.add(globals.ALIGNMENT.EVIL);
|
||||
if (deckManager.getDeckSize() === 0) {
|
||||
let placeholder = document.createElement("div");
|
||||
placeholder.setAttribute("id", "deck-list-placeholder");
|
||||
placeholder.innerText = "Add a card from the included roles below.";
|
||||
document.getElementById("deck-list").appendChild(placeholder);
|
||||
} else {
|
||||
if (document.getElementById("deck-list-placeholder")) {
|
||||
document.getElementById("deck-list-placeholder").remove();
|
||||
}
|
||||
for (let card of deckManager.getCurrentDeck()) {
|
||||
if (card.quantity > 0) {
|
||||
let roleEl = document.createElement("div");
|
||||
roleEl.classList.add('deck-role');
|
||||
if (card.team === globals.ALIGNMENT.GOOD) {
|
||||
roleEl.classList.add(globals.ALIGNMENT.GOOD);
|
||||
} else {
|
||||
roleEl.classList.add(globals.ALIGNMENT.EVIL);
|
||||
}
|
||||
roleEl.innerText = card.quantity + 'x ' + card.role;
|
||||
document.getElementById("deck-list").appendChild(roleEl);
|
||||
}
|
||||
roleEl.innerText = card.quantity + 'x ' + card.role;
|
||||
document.getElementById("deck-list").appendChild(roleEl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,38 +227,40 @@ export const templates = {
|
||||
CREATE_GAME_DECK:
|
||||
"<div id='deck-container'>" +
|
||||
"<div>" +
|
||||
"<label for='deck-good'>Good Roles</label>" +
|
||||
"<label for='deck-good'>Included Good Roles</label>" +
|
||||
"<div id='deck-good'></div>" +
|
||||
"</div>" +
|
||||
"<div>" +
|
||||
"<label for='deck-evil'>Evil Roles</label>" +
|
||||
"<label for='deck-evil'>Included Evil Roles</label>" +
|
||||
"<div id='deck-evil'></div>" +
|
||||
"</div>" +
|
||||
"</div>",
|
||||
CREATE_GAME_CUSTOM_ROLES:
|
||||
'<div id=\"custom-roles-container\">' +
|
||||
// '<button id="custom-role-hamburger" class="hamburger hamburger--collapse" type="button">' +
|
||||
// '<span class="hamburger-box">' +
|
||||
// '<span class="hamburger-inner"></span>' +
|
||||
// '</span>' +
|
||||
// '</button>' +
|
||||
// '<div id="custom-role-actions" style="display:none">' +
|
||||
// '<div class="custom-role-action">Export</div>' +
|
||||
// '<div class="custom-role-action">Import</div>' +
|
||||
// '<div class="custom-role-action">Edit</div>' +
|
||||
// '</div>' +
|
||||
'<button id="custom-role-hamburger" class="hamburger hamburger--collapse" type="button">' +
|
||||
'<span class="hamburger-box">' +
|
||||
'<span class="hamburger-inner"></span>' +
|
||||
'</span>' +
|
||||
'</button>' +
|
||||
'<div id="custom-role-actions" style="display:none">' +
|
||||
'<div class="custom-role-action" id="custom-roles-export">Export</div>' +
|
||||
'<div class="custom-role-action" id="custom-roles-import">Import</div>' +
|
||||
'</div>' +
|
||||
'<label for=\"add-card-to-deck-form\">Custom Roles</label>' +
|
||||
'<form id=\"add-card-to-deck-form\">' +
|
||||
'<select id=\"deck-select\"></select>' +
|
||||
'<input id="include-role" type=\"submit\" value=\"Include Role\">' +
|
||||
'</form>' +
|
||||
'<div id=\"deck-select\"></div>' +
|
||||
'<button id=\"custom-role-btn\" class=\"app-button\">+ Create Custom Role</button>' +
|
||||
'</div>',
|
||||
CREATE_GAME_DECK_STATUS:
|
||||
'<div id="deck-status-container">' +
|
||||
'<div id="deck-count">0 Players</div>' +
|
||||
'<div id="deck-list">' +
|
||||
'</div>' +
|
||||
'<div id="deck-list"></div>' +
|
||||
'</div>',
|
||||
DECK_SELECT_ROLE:
|
||||
'<div class="deck-select-role-name"></div>' +
|
||||
'<div class="deck-select-role-options">' +
|
||||
'<img class="deck-select-include" src="images/add.svg" title="include" alt="include"/>' +
|
||||
'<img class="deck-select-info" src="images/info.svg" title="info" alt="info"/>' +
|
||||
'<img class="deck-select-edit" src="images/pencil.svg" title="edit" alt="edit"/>' +
|
||||
'<img class="deck-select-remove" src="images/delete.svg" title="remove" alt="remove"/>' +
|
||||
'</div>'
|
||||
|
||||
}
|
||||
|
||||
@@ -1,41 +1,14 @@
|
||||
import { defaultCards } from "../config/defaultCards.js";
|
||||
import { customCards } from "../config/customCards.js";
|
||||
import { DeckStateManager } from "../modules/DeckStateManager.js";
|
||||
import { GameCreationStepManager } from "../modules/GameCreationStepManager.js";
|
||||
import { injectNavbar } from "../modules/Navbar.js";
|
||||
import {globals} from "../config/globals";
|
||||
|
||||
const create = () => {
|
||||
injectNavbar();
|
||||
let deckManager = new DeckStateManager();
|
||||
let gameCreationStepManager = new GameCreationStepManager(deckManager);
|
||||
loadDefaultCards(deckManager);
|
||||
gameCreationStepManager.renderStep("creation-step-container", 1);
|
||||
}
|
||||
|
||||
function loadDefaultCards(deckManager) {
|
||||
defaultCards.sort((a, b) => {
|
||||
if (a.team !== b.team) {
|
||||
return a.team === globals.ALIGNMENT.GOOD ? 1 : -1;
|
||||
}
|
||||
return a.role.localeCompare(b.role);
|
||||
});
|
||||
let deck = [];
|
||||
for (let i = 0; i < defaultCards.length; i ++) {
|
||||
let card = defaultCards[i];
|
||||
card.quantity = 0;
|
||||
deck.push(card);
|
||||
}
|
||||
deckManager.deck = deck;
|
||||
}
|
||||
|
||||
function loadCustomRoles(deckManager) {
|
||||
customCards.sort((a, b) => {
|
||||
return a.role.localeCompare(b.role);
|
||||
});
|
||||
deckManager.customRoleOptions = customCards;
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
||||
module.exports = create;
|
||||
} else {
|
||||
|
||||
@@ -121,7 +121,7 @@ input, textarea {
|
||||
background-color: transparent;
|
||||
border: 1px solid white;
|
||||
border-radius: 3px;
|
||||
color: #f7f7f7;
|
||||
color: #d7d7d7;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
|
||||
border-radius: 3px;
|
||||
user-select: none;
|
||||
max-width: 15em;
|
||||
min-width: 130px;
|
||||
display: flex;
|
||||
height: 55px;
|
||||
}
|
||||
@@ -28,8 +26,6 @@
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 9em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.selected-card {
|
||||
@@ -83,11 +79,19 @@
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#custom-roles-container {
|
||||
width: 95%;
|
||||
max-width: 25em;
|
||||
}
|
||||
|
||||
.deck-role {
|
||||
border-radius: 3px;
|
||||
margin: 0.25em 0;
|
||||
padding: 0 5px;
|
||||
font-size: 18px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#custom-roles-container, #deck-status-container {
|
||||
@@ -101,7 +105,8 @@
|
||||
}
|
||||
|
||||
#deck-status-container {
|
||||
min-width: 15em;
|
||||
width: 20em;
|
||||
max-width: 95%;
|
||||
height: 13em;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
@@ -122,6 +127,17 @@
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
#deck-list-placeholder {
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 290px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#custom-role-hamburger .hamburger-inner, #custom-role-hamburger .hamburger-inner::before, #custom-role-hamburger .hamburger-inner::after {
|
||||
background-color: whitesmoke;
|
||||
width: 28px;
|
||||
@@ -189,6 +205,8 @@
|
||||
margin: 0 auto;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 95%;
|
||||
max-width: 38em;
|
||||
}
|
||||
|
||||
#deck-container label {
|
||||
@@ -322,6 +340,53 @@ input[type="number"] {
|
||||
|
||||
#deck-select {
|
||||
margin: 0.5em 1em 1.5em 0;
|
||||
overflow-y: auto;
|
||||
height: 15em;
|
||||
}
|
||||
|
||||
.deck-select-role {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: black;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
margin: 0.25em 0;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.deck-select-role-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.deck-select-role:hover {
|
||||
border: 1px solid #d7d7d7;
|
||||
}
|
||||
|
||||
.deck-select-role-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#deck-select img {
|
||||
height: 20px;
|
||||
margin: 0 8px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#deck-select img:nth-child(4) {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#deck-select img:hover {
|
||||
filter: brightness(1.5);
|
||||
background-color: #8080804d;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
@@ -367,7 +432,7 @@ input[type="number"] {
|
||||
#game-creation-container {
|
||||
width: 95%;
|
||||
position: relative;
|
||||
margin-bottom: 2em;
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
#tracker-container {
|
||||
@@ -378,6 +443,10 @@ input[type="number"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#upload-custom-roles-modal input[type='file'] {
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
#creation-step-tracker {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -466,6 +535,20 @@ input[type="number"] {
|
||||
padding: 10px 15px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.deck-select-role-name {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.compact-card .card-role {
|
||||
max-width: 9em;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.compact-card {
|
||||
min-width: 130px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 551px) {
|
||||
@@ -476,4 +559,13 @@ input[type="number"] {
|
||||
#step-1 div {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.compact-card .card-role {
|
||||
max-width: 10em;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.compact-card {
|
||||
min-width: 155px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div id="mobile-menu-background-overlay"></div>
|
||||
<div id="navbar"></div>
|
||||
<div id="game-creation-container" class="container">
|
||||
<div id="add-role-modal-background" class="modal-background" style="display: none"></div>
|
||||
<div id="modal-background" class="modal-background" style="display: none"></div>
|
||||
<div id="add-role-modal" class="modal" style="display: none">
|
||||
<form id="add-role-form">
|
||||
<div>
|
||||
@@ -46,15 +46,16 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- <div id="upload-custom-roles-modal">-->
|
||||
<!-- <form id="upload-custom-roles-form">-->
|
||||
<!-- <input type="file" id="upload-custom-roles" name="Upload Custom Roles" accept="application/json"/>-->
|
||||
<!-- </form>-->
|
||||
<!-- <div class="modal-button-container">-->
|
||||
<!-- <button id="close-upload-custom-roles-modal-button" class="cancel app-button">Close</button>-->
|
||||
<!-- <input type="submit" id="upload-custom-roles-button" value="Upload"/>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div id="upload-custom-roles-modal" class="modal" style="display:none">
|
||||
<h3>Import Custom Roles</h3>
|
||||
<form id="upload-custom-roles-form">
|
||||
<input type="file" id="upload-custom-roles" name="Upload Custom Roles" accept="text/plain"/>
|
||||
<div class="modal-button-container">
|
||||
<button id="close-upload-custom-roles-modal-button" class="cancel app-button">Close</button>
|
||||
<input type="submit" id="upload-custom-roles-button" value="Upload"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<h1>Create A Game</h1>
|
||||
<div id="tracker-container">
|
||||
<div id="creation-step-tracker">
|
||||
|
||||
Reference in New Issue
Block a user