moved token into own component

fixed a lot of styling issues
added button styles
updated favicon
This commit is contained in:
Steffen 2020-04-15 22:40:58 +02:00
parent ed283598d7
commit 3d66b67cbf
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
32 changed files with 214 additions and 125 deletions

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

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

View File

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

View File

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

View File

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

110
src/components/Token.vue Normal file
View File

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

View File

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