role importing/exporting

This commit is contained in:
AlecM33
2022-01-07 00:39:37 -05:00
parent c0a18a6921
commit 82e86f4fb6
13 changed files with 378 additions and 122 deletions

View File

@@ -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',

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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>'
}

View File

@@ -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 {

View File

@@ -121,7 +121,7 @@ input, textarea {
background-color: transparent;
border: 1px solid white;
border-radius: 3px;
color: #f7f7f7;
color: #d7d7d7;
}
a {

View File

@@ -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;
}
}

View File

@@ -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">