mirror of https://github.com/bra1n/townsquare.git
parent
b37edc8b9e
commit
a8c1c9ea85
121
src/App.vue
121
src/App.vue
|
@ -4,10 +4,12 @@
|
||||||
@keyup="keyup"
|
@keyup="keyup"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
v-bind:class="{ screenshot: isScreenshot }"
|
v-bind:class="{ screenshot: isScreenshot }"
|
||||||
|
v-bind:style="{ backgroundImage: background ? `url('${background}')` : '' }"
|
||||||
>
|
>
|
||||||
<TownInfo :players="players" :edition="edition"></TownInfo>
|
<TownInfo :players="players" :edition="edition"></TownInfo>
|
||||||
<TownSquare
|
<TownSquare
|
||||||
:is-public="isPublic"
|
:is-public="isPublic"
|
||||||
|
:is-night-order="isNightOrder"
|
||||||
:players="players"
|
:players="players"
|
||||||
:roles="roles"
|
:roles="roles"
|
||||||
:zoom="zoom"
|
:zoom="zoom"
|
||||||
|
@ -55,30 +57,65 @@
|
||||||
<div class="menu" v-bind:class="{ open: isControlOpen }">
|
<div class="menu" v-bind:class="{ open: isControlOpen }">
|
||||||
<font-awesome-icon icon="cog" @click="isControlOpen = !isControlOpen" />
|
<font-awesome-icon icon="cog" @click="isControlOpen = !isControlOpen" />
|
||||||
<ul>
|
<ul>
|
||||||
<li @click="togglePublic">Toggle <em>G</em>rimoire</li>
|
<!-- Grimoire -->
|
||||||
|
<li class="headline">
|
||||||
|
<font-awesome-icon icon="book-open" />
|
||||||
|
Grimoire
|
||||||
|
</li>
|
||||||
|
<li @click="togglePublic">
|
||||||
|
<em>[G]</em>
|
||||||
|
<template v-if="!isPublic">Hide</template>
|
||||||
|
<template v-if="isPublic">Show</template>
|
||||||
|
</li>
|
||||||
|
<li @click="toggleNightOrder">
|
||||||
|
<em
|
||||||
|
><font-awesome-icon
|
||||||
|
:icon="['fas', isNightOrder ? 'check-square' : 'square']"
|
||||||
|
/></em>
|
||||||
|
Night order
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Size
|
<em>
|
||||||
<font-awesome-icon @click="zoom -= 0.1" icon="search-minus" />
|
<font-awesome-icon @click="zoom -= 0.1" icon="search-minus" />
|
||||||
{{ Math.round(zoom * 100) }}%
|
{{ Math.round(zoom * 100) }}%
|
||||||
<font-awesome-icon @click="zoom += 0.1" icon="search-plus" />
|
<font-awesome-icon @click="zoom += 0.1" icon="search-plus" />
|
||||||
|
</em>
|
||||||
|
Zoom
|
||||||
|
</li>
|
||||||
|
<li @click="setBackground">
|
||||||
|
Background image
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Users -->
|
||||||
|
<li class="headline">
|
||||||
|
<font-awesome-icon icon="users" />
|
||||||
|
Players
|
||||||
</li>
|
</li>
|
||||||
<li @click="addPlayer" v-if="players.length < 20">
|
<li @click="addPlayer" v-if="players.length < 20">
|
||||||
<em>A</em>dd Player
|
<em>[A]</em> Add
|
||||||
</li>
|
</li>
|
||||||
<li @click="randomizeSeatings" v-if="players.length > 2">
|
<li @click="randomizeSeatings" v-if="players.length > 2">
|
||||||
<em>R</em>andomize Seatings
|
<em>[R]</em> Randomize
|
||||||
</li>
|
</li>
|
||||||
<li @click="clearPlayers" v-if="players.length">
|
<li @click="clearPlayers" v-if="players.length">
|
||||||
Clear Players
|
Remove all
|
||||||
</li>
|
</li>
|
||||||
<li @click="clearRoles" v-if="players.length">
|
|
||||||
Clear Roles
|
<!-- Characters -->
|
||||||
|
<li class="headline">
|
||||||
|
<font-awesome-icon icon="theater-masks" />
|
||||||
|
Characters
|
||||||
</li>
|
</li>
|
||||||
<li @click="showEditionModal" v-if="players.length > 4">
|
<li @click="showEditionModal">
|
||||||
|
<em>[E]</em>
|
||||||
Select Edition
|
Select Edition
|
||||||
</li>
|
</li>
|
||||||
<li @click="showRoleModal" v-if="players.length > 4">
|
<li @click="showRoleModal" v-if="players.length > 4">
|
||||||
Select Roles
|
<em>[C]</em>
|
||||||
|
Choose & Assign
|
||||||
|
</li>
|
||||||
|
<li @click="clearRoles" v-if="players.length">
|
||||||
|
Remove all
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,7 +142,9 @@ export default {
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
|
background: "",
|
||||||
editions: editionJSON,
|
editions: editionJSON,
|
||||||
|
isNightOrder: true,
|
||||||
isPublic: true,
|
isPublic: true,
|
||||||
isControlOpen: false,
|
isControlOpen: false,
|
||||||
isEditionModalOpen: false,
|
isEditionModalOpen: false,
|
||||||
|
@ -132,6 +171,12 @@ export default {
|
||||||
this.isPublic = !this.isPublic;
|
this.isPublic = !this.isPublic;
|
||||||
this.isControlOpen = !this.isPublic;
|
this.isControlOpen = !this.isPublic;
|
||||||
},
|
},
|
||||||
|
toggleNightOrder() {
|
||||||
|
this.isNightOrder = !this.isNightOrder;
|
||||||
|
},
|
||||||
|
setBackground() {
|
||||||
|
this.background = prompt("Enter custom background URL");
|
||||||
|
},
|
||||||
addPlayer() {
|
addPlayer() {
|
||||||
const name = prompt("Player name");
|
const name = prompt("Player name");
|
||||||
if (name) {
|
if (name) {
|
||||||
|
@ -163,6 +208,7 @@ export default {
|
||||||
if (confirm("Are you sure you want to remove all player roles?")) {
|
if (confirm("Are you sure you want to remove all player roles?")) {
|
||||||
this.players.forEach(player => {
|
this.players.forEach(player => {
|
||||||
player.role = {};
|
player.role = {};
|
||||||
|
player.hasDied = false;
|
||||||
player.reminders = [];
|
player.reminders = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -203,10 +249,19 @@ export default {
|
||||||
case "r":
|
case "r":
|
||||||
this.randomizeSeatings();
|
this.randomizeSeatings();
|
||||||
break;
|
break;
|
||||||
|
case "e":
|
||||||
|
this.showEditionModal();
|
||||||
|
break;
|
||||||
|
case "c":
|
||||||
|
this.showRoleModal();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
if (localStorage.background !== undefined) {
|
||||||
|
this.background = JSON.parse(localStorage.background);
|
||||||
|
}
|
||||||
if (localStorage.isPublic !== undefined) {
|
if (localStorage.isPublic !== undefined) {
|
||||||
this.isPublic = JSON.parse(localStorage.isPublic);
|
this.isPublic = JSON.parse(localStorage.isPublic);
|
||||||
}
|
}
|
||||||
|
@ -261,6 +316,13 @@ export default {
|
||||||
},
|
},
|
||||||
isPublic(newIsPublic) {
|
isPublic(newIsPublic) {
|
||||||
localStorage.isPublic = JSON.stringify(newIsPublic);
|
localStorage.isPublic = JSON.stringify(newIsPublic);
|
||||||
|
},
|
||||||
|
background(newBackground) {
|
||||||
|
if (newBackground) {
|
||||||
|
localStorage.background = JSON.stringify(newBackground);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("background");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -318,6 +380,8 @@ ul {
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
background-position: center center;
|
||||||
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
// success animation
|
// success animation
|
||||||
|
@ -343,6 +407,7 @@ ul {
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
filter: drop-shadow(0 0 5px rgba(0, 0, 0, 1));
|
||||||
&.success {
|
&.success {
|
||||||
animation: greenToWhite 1s normal forwards;
|
animation: greenToWhite 1s normal forwards;
|
||||||
animation-iteration-count: 1;
|
animation-iteration-count: 1;
|
||||||
|
@ -357,7 +422,7 @@ ul {
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
transform-origin: 91% 5.5%;
|
transform-origin: 189px 22px;
|
||||||
transition: transform 500ms cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
transition: transform 500ms cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
|
|
||||||
|
@ -388,27 +453,41 @@ ul {
|
||||||
border-radius: 10px 0 10px 10px;
|
border-radius: 10px 0 10px 10px;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
padding: 5px 10px;
|
padding: 2px 10px;
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
margin-bottom: 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:not(.headline):hover {
|
||||||
background-color: red;
|
cursor: pointer;
|
||||||
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
em {
|
em {
|
||||||
text-decoration: underline;
|
float: right;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: bold;
|
margin-left: 10px;
|
||||||
|
font-size: 80%;
|
||||||
|
line-height: 31px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.headline {
|
||||||
|
padding: 5px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
$demon 0%,
|
||||||
|
rgba(0, 0, 0, 0.5) 20%,
|
||||||
|
rgba(0, 0, 0, 0.5) 80%,
|
||||||
|
$townsfolk 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
<div class="shroud" @click="toggleStatus()"></div>
|
<div class="shroud" @click="toggleStatus()"></div>
|
||||||
<div class="life" @click="toggleStatus()"></div>
|
<div class="life" @click="toggleStatus()"></div>
|
||||||
|
|
||||||
<div class="night first" v-if="player.firstNight">
|
<div class="night first" v-if="player.firstNight && isNightOrder">
|
||||||
<em>{{ player.firstNight }}.</em>
|
<em>{{ player.firstNight }}.</em>
|
||||||
<span v-if="player.role.firstNightReminder">{{
|
<span v-if="player.role.firstNightReminder">{{
|
||||||
player.role.firstNightReminder | handleEmojis
|
player.role.firstNightReminder | handleEmojis
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="night other" v-if="player.otherNight">
|
<div class="night other" v-if="player.otherNight && isNightOrder">
|
||||||
<em>{{ player.otherNight }}.</em>
|
<em>{{ player.otherNight }}.</em>
|
||||||
<span v-if="player.role.otherNightReminder">{{
|
<span v-if="player.role.otherNightReminder">{{
|
||||||
player.role.otherNightReminder | handleEmojis
|
player.role.otherNightReminder | handleEmojis
|
||||||
|
@ -83,6 +83,10 @@ export default {
|
||||||
isPublic: {
|
isPublic: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isNightOrder: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -255,13 +259,16 @@ export default {
|
||||||
.player > .name {
|
.player > .name {
|
||||||
font-size: 120%;
|
font-size: 120%;
|
||||||
line-height: 120%;
|
line-height: 120%;
|
||||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 1))
|
|
||||||
drop-shadow(0 0 1px rgba(0, 0, 0, 1)) drop-shadow(0 0 1px rgba(0, 0, 0, 1));
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border: 3px solid black;
|
||||||
|
border-radius: 10px;
|
||||||
|
top: 5px;
|
||||||
|
box-shadow: 0 0 5px black;
|
||||||
|
|
||||||
span.screenshot,
|
span.screenshot,
|
||||||
span.remove {
|
span.remove {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:player="player"
|
:player="player"
|
||||||
:roles="roles"
|
:roles="roles"
|
||||||
:is-public="isPublic"
|
:is-public="isPublic"
|
||||||
|
:is-night-order="isNightOrder"
|
||||||
@add-reminder="openReminderModal"
|
@add-reminder="openReminderModal"
|
||||||
@set-role="openRoleModal"
|
@set-role="openRoleModal"
|
||||||
@remove-player="removePlayer"
|
@remove-player="removePlayer"
|
||||||
|
@ -91,6 +92,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
isNightOrder: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
players: {
|
players: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
|
|
36
src/main.js
36
src/main.js
|
@ -2,30 +2,38 @@ import Vue from "vue";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import {
|
import {
|
||||||
faUsers,
|
faBookOpen,
|
||||||
faHeartbeat,
|
faCamera,
|
||||||
faVoteYea,
|
|
||||||
faUserFriends,
|
|
||||||
faUser,
|
|
||||||
faTimesCircle,
|
|
||||||
faCog,
|
faCog,
|
||||||
|
faHeartbeat,
|
||||||
faSearchMinus,
|
faSearchMinus,
|
||||||
faSearchPlus,
|
faSearchPlus,
|
||||||
faCamera
|
faTheaterMasks,
|
||||||
|
faTimesCircle,
|
||||||
|
faUser,
|
||||||
|
faUserFriends,
|
||||||
|
faUsers,
|
||||||
|
faVoteYea,
|
||||||
|
faCheckSquare,
|
||||||
|
faSquare
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faUsers,
|
faBookOpen,
|
||||||
faHeartbeat,
|
faCamera,
|
||||||
faVoteYea,
|
|
||||||
faUserFriends,
|
|
||||||
faUser,
|
|
||||||
faTimesCircle,
|
|
||||||
faCog,
|
faCog,
|
||||||
|
faHeartbeat,
|
||||||
faSearchMinus,
|
faSearchMinus,
|
||||||
faSearchPlus,
|
faSearchPlus,
|
||||||
faCamera
|
faTheaterMasks,
|
||||||
|
faTimesCircle,
|
||||||
|
faUser,
|
||||||
|
faUserFriends,
|
||||||
|
faUsers,
|
||||||
|
faVoteYea,
|
||||||
|
faCheckSquare,
|
||||||
|
faSquare
|
||||||
);
|
);
|
||||||
|
|
||||||
Vue.component("font-awesome-icon", FontAwesomeIcon);
|
Vue.component("font-awesome-icon", FontAwesomeIcon);
|
||||||
|
|
Loading…
Reference in New Issue