moved token into own component
fixed a lot of styling issues added button styles updated favicon
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Blood on the Clocktower Virtual Town Square</title>
|
||||
<title>Blood on the Clocktower Town Square</title>
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="static/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="static/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="static/apple-icon-72x72.png">
|
||||
|
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 10 KiB |
37
src/App.vue
|
@ -310,4 +310,41 @@ ul.editions .edition {
|
|||
1px 1px 0 #000, 0 0 5px rgba(0, 0, 0, 0.75);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.button {
|
||||
padding: 0;
|
||||
border: solid 0.125em transparent;
|
||||
border-radius: 15px;
|
||||
box-shadow: inset 0 1px 1px #9c9c9c, 0 0 10px #000;
|
||||
background: radial-gradient(
|
||||
at 0 -15%,
|
||||
rgba(#fff, 0.07) 70%,
|
||||
rgba(#fff, 0) 71%
|
||||
)
|
||||
0 0/ 80% 90% no-repeat content-box,
|
||||
linear-gradient(#4e4e4e, #040404) content-box,
|
||||
linear-gradient(#292929, #010101) border-box;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px rgba(0, 0, 0, 0.5);
|
||||
line-height: 40px;
|
||||
margin: 5px auto;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
transition: all 200ms;
|
||||
&:hover {
|
||||
color: red;
|
||||
}
|
||||
&:disabled {
|
||||
color: gray;
|
||||
}
|
||||
&:before,
|
||||
&:after {
|
||||
content: " ";
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
aria-describedby="modalDescription"
|
||||
@click.stop=""
|
||||
>
|
||||
<font-awesome-icon @click="close" class="close" icon="times-circle" />
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,6 +67,16 @@ export default {
|
|||
font-size: 75%;
|
||||
line-height: 100%;
|
||||
}
|
||||
> .close {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
cursor: pointer;
|
||||
z-index: 5;
|
||||
&:hover {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-fade-enter,
|
||||
|
|
|
@ -10,16 +10,7 @@
|
|||
>
|
||||
<div class="shroud" @click="toggleStatus()"></div>
|
||||
<div class="life" @click="toggleStatus()"></div>
|
||||
<div class="token" @click="changeRole()" :class="[player.role.id]">
|
||||
<span class="leaf-left" v-if="player.role.firstNight"></span>
|
||||
<span class="leaf-right" v-if="player.role.otherNight"></span>
|
||||
<span
|
||||
v-if="player.role.reminders && player.role.reminders.length"
|
||||
v-bind:class="['leaf-top' + player.role.reminders.length]"
|
||||
></span>
|
||||
<span class="leaf-orange" v-if="player.role.setup"></span>
|
||||
<div>{{ player.role.name }}</div>
|
||||
</div>
|
||||
<Token :role="player.role" @set-role="setRole" />
|
||||
<div class="ability" v-if="player.role.ability">
|
||||
{{ player.role.ability }}
|
||||
</div>
|
||||
|
@ -46,7 +37,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Token from "./Token";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Token
|
||||
},
|
||||
props: {
|
||||
player: {
|
||||
type: Object,
|
||||
|
@ -79,7 +75,7 @@ export default {
|
|||
this.$set(this.player, "hasDied", !this.player.hasDied);
|
||||
}
|
||||
},
|
||||
changeRole() {
|
||||
setRole() {
|
||||
this.$emit("set-role", this.player);
|
||||
},
|
||||
changeName() {
|
||||
|
@ -207,76 +203,19 @@ export default {
|
|||
}
|
||||
|
||||
/***** Role token ******/
|
||||
.circle .token {
|
||||
border-radius: 50%;
|
||||
height: $token + 6px;
|
||||
width: $token + 6px;
|
||||
background: url("../assets/token.png") center center;
|
||||
background-size: 100%;
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-weight: 600;
|
||||
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff,
|
||||
1px 1px 0 #fff, 0 0 5px rgba(0, 0, 0, 0.75);
|
||||
padding-top: $token * 0.7;
|
||||
font-family: "Papyrus", serif;
|
||||
border: 3px solid black;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
transition: transform 200ms ease-in-out;
|
||||
transform: perspective(400px) rotateY(0deg);
|
||||
backface-visibility: hidden;
|
||||
.player .token {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
margin-left: ($token + 6) / -2;
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
&.leaf-left {
|
||||
background-image: url("../assets/leaf-left.png");
|
||||
}
|
||||
&.leaf-orange {
|
||||
background-image: url("../assets/leaf-orange.png");
|
||||
}
|
||||
&.leaf-right {
|
||||
background-image: url("../assets/leaf-right.png");
|
||||
}
|
||||
&.leaf-top1 {
|
||||
background-image: url("../assets/leaf-top1.png");
|
||||
}
|
||||
&.leaf-top2 {
|
||||
background-image: url("../assets/leaf-top2.png");
|
||||
}
|
||||
&.leaf-top3 {
|
||||
background-image: url("../assets/leaf-top3.png");
|
||||
}
|
||||
&.leaf-top4 {
|
||||
background-image: url("../assets/leaf-top4.png");
|
||||
}
|
||||
&.leaf-top5 {
|
||||
background-image: url("../assets/leaf-top5.png");
|
||||
}
|
||||
}
|
||||
height: $token + 6px;
|
||||
width: $token + 6px;
|
||||
transition: transform 200ms ease-in-out;
|
||||
transform: perspective(400px) rotateY(0deg);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
#townsquare.public .token {
|
||||
#townsquare.public .circle .token {
|
||||
transform: perspective(400px) rotateY(-180deg);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,31 +12,32 @@
|
|||
</li>
|
||||
<li
|
||||
v-for="role in teamRoles"
|
||||
class="token"
|
||||
v-bind:class="[role.id, role.team, role.selected ? 'selected' : '']"
|
||||
v-bind:class="[role.team, role.selected ? 'selected' : '']"
|
||||
v-bind:key="role.id"
|
||||
@click="role.selected = !role.selected"
|
||||
>
|
||||
{{ role.name }}
|
||||
<Token :role="role" />
|
||||
</li>
|
||||
</ul>
|
||||
<button
|
||||
<div class="button"
|
||||
@click="assignRoles()"
|
||||
v-bind:disabled="selectedRoles > nontravelerPlayers || !selectedRoles"
|
||||
>
|
||||
Assign {{ selectedRoles }} roles randomly
|
||||
</button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from "./Modal";
|
||||
import gameJSON from "./../game";
|
||||
import Token from "./Token";
|
||||
|
||||
const randomElement = arr => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Token,
|
||||
Modal
|
||||
},
|
||||
props: {
|
||||
|
@ -62,7 +63,8 @@ export default {
|
|||
computed: {
|
||||
nontravelerPlayers: function() {
|
||||
return Math.min(
|
||||
this.players.filter(({ role }) => role && role.team !== "traveler").length,
|
||||
this.players.filter(({ role }) => role && role.team !== "traveler")
|
||||
.length,
|
||||
15
|
||||
);
|
||||
},
|
||||
|
@ -129,12 +131,25 @@ export default {
|
|||
@import "../vars.scss";
|
||||
|
||||
.roles .modal ul.tokens {
|
||||
padding-left: 20px;
|
||||
padding-left: 55px;
|
||||
li {
|
||||
opacity: 0.5;
|
||||
transition: all 250ms;
|
||||
&.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.count {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
&.townsfolk {
|
||||
color: $townsfolk;
|
||||
}
|
||||
|
@ -148,11 +163,5 @@ export default {
|
|||
color: $demon;
|
||||
}
|
||||
}
|
||||
.token {
|
||||
opacity: 0.5;
|
||||
&.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div class="token" @click="setRole" :class="[role.id]">
|
||||
<span class="leaf-left" v-if="role.firstNight"></span>
|
||||
<span class="leaf-right" v-if="role.otherNight"></span>
|
||||
<span
|
||||
v-if="role.reminders && role.reminders.length"
|
||||
v-bind:class="['leaf-top' + role.reminders.length]"
|
||||
></span>
|
||||
<span class="leaf-orange" v-if="role.setup"></span>
|
||||
<div>{{ role.name }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Token",
|
||||
props: {
|
||||
role: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
setRole() {
|
||||
this.$emit("set-role");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.token {
|
||||
border-radius: 50%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("../assets/token.png") center center;
|
||||
background-size: 100%;
|
||||
text-align: center;
|
||||
color: black;
|
||||
font-weight: 600;
|
||||
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff,
|
||||
1px 1px 0 #fff, 0 0 5px rgba(0, 0, 0, 0.75);
|
||||
font-family: "Papyrus", serif;
|
||||
border: 3px solid black;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
top: 73%;
|
||||
width: 100%;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
|
||||
&.leaf-left {
|
||||
background-image: url("../assets/leaf-left.png");
|
||||
}
|
||||
|
||||
&.leaf-orange {
|
||||
background-image: url("../assets/leaf-orange.png");
|
||||
}
|
||||
|
||||
&.leaf-right {
|
||||
background-image: url("../assets/leaf-right.png");
|
||||
}
|
||||
|
||||
&.leaf-top1 {
|
||||
background-image: url("../assets/leaf-top1.png");
|
||||
}
|
||||
|
||||
&.leaf-top2 {
|
||||
background-image: url("../assets/leaf-top2.png");
|
||||
}
|
||||
|
||||
&.leaf-top3 {
|
||||
background-image: url("../assets/leaf-top3.png");
|
||||
}
|
||||
|
||||
&.leaf-top4 {
|
||||
background-image: url("../assets/leaf-top4.png");
|
||||
}
|
||||
|
||||
&.leaf-top5 {
|
||||
background-image: url("../assets/leaf-top5.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<div id="townsquare" class="square" v-bind:class="{ public: isPublic }" v-bind:style="{ zoom: zoom }">
|
||||
<div
|
||||
id="townsquare"
|
||||
class="square"
|
||||
v-bind:class="{ public: isPublic }"
|
||||
v-bind:style="{ zoom: zoom }"
|
||||
>
|
||||
<ul class="circle" v-bind:class="['size-' + players.length]">
|
||||
<Player
|
||||
v-for="(player, index) in players"
|
||||
|
@ -12,7 +17,7 @@
|
|||
@remove-player="removePlayer"
|
||||
></Player>
|
||||
</ul>
|
||||
<Modal v-show="availableReminders.length" @close="closeModal">
|
||||
<Modal v-show="availableReminders.length && selectedPlayer" @close="closeModal">
|
||||
<h2>Choose a reminder token:</h2>
|
||||
<ul class="reminders">
|
||||
<li
|
||||
|
@ -26,17 +31,16 @@
|
|||
</li>
|
||||
</ul>
|
||||
</Modal>
|
||||
<Modal v-show="availableRoles.length" @close="closeModal">
|
||||
<Modal v-show="availableRoles.length && selectedPlayer" @close="closeModal">
|
||||
<h2>Choose a new role:</h2>
|
||||
<ul class="tokens">
|
||||
<li
|
||||
v-for="role in availableRoles"
|
||||
class="token"
|
||||
v-bind:class="[role.id, role.team]"
|
||||
v-bind:class="[role.team]"
|
||||
v-bind:key="role.id"
|
||||
@click="setRole(role)"
|
||||
>
|
||||
{{ role.name }}
|
||||
<Token :role="role" />
|
||||
</li>
|
||||
</ul>
|
||||
</Modal>
|
||||
|
@ -46,9 +50,11 @@
|
|||
<script>
|
||||
import Player from "./Player";
|
||||
import Modal from "./Modal";
|
||||
import Token from "./Token";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Token,
|
||||
Modal,
|
||||
Player
|
||||
},
|
||||
|
@ -79,8 +85,9 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
openReminderModal(player) {
|
||||
this.selectedPlayer = player;
|
||||
this.availableRoles = [];
|
||||
this.availableReminders = [];
|
||||
this.selectedPlayer = player;
|
||||
this.roles.forEach(role => {
|
||||
if (this.players.some(p => p.role.id === role.id)) {
|
||||
this.availableReminders = [
|
||||
|
@ -93,10 +100,11 @@ export default {
|
|||
this.availableReminders.push({ role: "evil", name: "Evil" });
|
||||
},
|
||||
openRoleModal(player) {
|
||||
this.selectedPlayer = player;
|
||||
this.availableRoles = [];
|
||||
this.availableReminders = [];
|
||||
this.selectedPlayer = player;
|
||||
this.roles.forEach(role => {
|
||||
if (role.id !== player.role) {
|
||||
if (role.id !== player.role.id) {
|
||||
this.availableRoles.push(role);
|
||||
}
|
||||
});
|
||||
|
@ -112,8 +120,6 @@ export default {
|
|||
},
|
||||
closeModal() {
|
||||
this.selectedPlayer = false;
|
||||
this.availableReminders = [];
|
||||
this.availableRoles = [];
|
||||
},
|
||||
removePlayer(player) {
|
||||
if (confirm(`Do you really want to remove ${player.name}?`)) {
|
||||
|
@ -215,23 +221,11 @@ export default {
|
|||
}
|
||||
|
||||
/***** Role token modal ******/
|
||||
ul.tokens .token {
|
||||
ul.tokens li {
|
||||
border-radius: 50%;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
background: url("../assets/token.png") center center;
|
||||
background-size: 100%;
|
||||
text-align: center;
|
||||
color: black;
|
||||
margin: 5px;
|
||||
font-weight: 600;
|
||||
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff,
|
||||
1px 1px 0 #fff, 0 0 5px rgba(0, 0, 0, 0.75);
|
||||
padding-top: 85px;
|
||||
font-family: "Papyrus", serif;
|
||||
border: 3px solid black;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
transition: transform 500ms ease;
|
||||
|
||||
&.townsfolk {
|
||||
|
@ -249,17 +243,6 @@ ul.tokens .token {
|
|||
&.traveler {
|
||||
box-shadow: 0 0 10px $traveler, 0 0 10px $traveler;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: " ";
|
||||
background-size: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
|