added vote locking and styling

This commit is contained in:
Steffen 2020-06-04 18:23:33 +02:00
parent 6a37d17aec
commit 3b36c47f8e
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
5 changed files with 114 additions and 39 deletions

View File

@ -18,6 +18,7 @@
<EditionModal /> <EditionModal />
<RolesModal /> <RolesModal />
<ReferenceModal /> <ReferenceModal />
<Gradients />
</div> </div>
</template> </template>
@ -31,6 +32,7 @@ import EditionModal from "./components/modals/EditionModal";
import Intro from "./components/Intro"; import Intro from "./components/Intro";
import ReferenceModal from "./components/modals/ReferenceModal"; import ReferenceModal from "./components/modals/ReferenceModal";
import Vote from "./components/Vote"; import Vote from "./components/Vote";
import Gradients from "./components/Gradients";
export default { export default {
components: { components: {
@ -41,7 +43,8 @@ export default {
TownSquare, TownSquare,
Menu, Menu,
EditionModal, EditionModal,
RolesModal RolesModal,
Gradients
}, },
computed: { computed: {
...mapState(["grimoire", "session"]), ...mapState(["grimoire", "session"]),

View File

@ -0,0 +1,43 @@
<template>
<!-- SVG Gradients -->
<div id="gradients">
<svg
width="0"
height="0"
v-for="(gradient, index) in gradients"
:key="index"
>
<linearGradient :id="gradient[0]" x1="50%" y1="100%" x2="50%" y2="0%">
<stop
offset="0%"
:style="{ 'stop-color': gradient[2], 'stop-opacity': 1 }"
></stop>
<stop
offset="100%"
:style="{ 'stop-color': gradient[1], 'stop-opacity': 1 }"
></stop>
</linearGradient>
</svg>
</div>
</template>
<script>
export default {
data() {
return {
gradients: [
["demon", "#ce0100", "#000"],
["townsfolk", "#1f65ff", "#000"],
["default", "#4E4E4E", "#000"]
]
};
}
};
</script>
<style lang="scss" scoped>
svg {
position: absolute;
z-index: -1;
}
</style>

View File

@ -8,7 +8,8 @@
dead: player.isDead, dead: player.isDead,
'no-vote': player.isVoteless, 'no-vote': player.isVoteless,
you: player.id === session.playerId, you: player.id === session.playerId,
'voted-yes': session.votes[index] 'vote-yes': session.votes[index],
'vote-lock': voteLocked
}, },
player.role.team player.role.team
]" ]"
@ -44,7 +45,13 @@
<font-awesome-icon <font-awesome-icon
icon="skull" icon="skull"
class="vote" class="vote"
title="Vote" title="Voted YES"
@click="vote()"
/>
<font-awesome-icon
icon="times"
class="vote"
title="Voted NO"
@click="vote()" @click="vote()"
/> />
<font-awesome-icon <font-awesome-icon
@ -170,11 +177,20 @@ export default {
} }
}, },
computed: { computed: {
index: function() { ...mapState("players", ["players"]),
return this.$store.state.players.players.indexOf(this.player);
},
...mapState(["grimoire", "session"]), ...mapState(["grimoire", "session"]),
...mapGetters({ nightOrder: "players/nightOrder" }) ...mapGetters({ nightOrder: "players/nightOrder" }),
index: function() {
return this.players.indexOf(this.player);
},
voteLocked: function() {
const session = this.session;
const players = this.players.length;
if (!session.nomination) return false;
const indexAdjusted =
(this.index - 1 + players - session.nomination[1]) % players;
return indexAdjusted < session.lockedVote - 1;
}
}, },
data() { data() {
return { return {
@ -419,26 +435,36 @@ export default {
&.vote, &.vote,
&.cancel { &.cancel {
top: 9%; top: 9%;
left: 20%; left: 25%;
width: 60%; width: 50%;
height: 60%; height: 60%;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
transition: all 250ms; transition: all 250ms;
transform: scale(0.2); transform: scale(0.2);
&:hover { * {
color: red; stroke-width: 10px;
stroke: white;
fill: url(#default);
}
&:hover *,
&.fa-skull * {
fill: url(#demon);
}
&.fa-times * {
fill: url(#townsfolk);
} }
} }
} }
#townsquare.vote .player.voted-yes > svg.vote { #townsquare.vote .player.vote-yes > svg.vote.fa-skull {
color: $demon;
opacity: 0.5; opacity: 0.5;
transform: scale(1); transform: scale(1);
} }
#townsquare.vote .player.you.voted-yes > svg.vote { #townsquare.vote .player.you.vote-yes > svg.vote.fa-skull,
#townsquare.vote .player.vote-lock.vote-yes > svg.vote.fa-skull,
#townsquare.vote .player.vote-lock:not(.vote-yes) > svg.vote.fa-times {
opacity: 1; opacity: 1;
transform: scale(1); transform: scale(1);
} }

View File

@ -26,12 +26,7 @@
</div> </div>
<div class="button" @click="finish">Finish</div> <div class="button" @click="finish">Finish</div>
</div> </div>
<div <div class="button-group" v-else-if="canVote">
class="button-group"
v-else-if="
player && (!player.isVoteless || nominee.role.team === 'traveler')
"
>
<div class="button vote-no" @click="vote(false)">Vote NO</div> <div class="button vote-no" @click="vote(false)">Vote NO</div>
<div class="button vote-yes" @click="vote(true)">Vote YES</div> <div class="button vote-yes" @click="vote(true)">Vote YES</div>
</div> </div>
@ -47,39 +42,45 @@ import { mapGetters, mapState } from "vuex";
export default { export default {
computed: { computed: {
...mapState("players", ["players"]),
...mapState(["session"]),
...mapGetters({ alive: "players/alive" }),
nominator: function() { nominator: function() {
return this.$store.state.players.players[ return this.players[this.session.nomination[0]];
this.$store.state.session.nomination[0]
];
}, },
nominatorStyle: function() { nominatorStyle: function() {
const players = this.$store.state.players.players.length; const players = this.players.length;
const nomination = this.$store.state.session.nomination[0]; const nomination = this.session.nomination[0];
return { return {
transform: `rotate(${Math.round((nomination / players) * 360)}deg)` transform: `rotate(${Math.round((nomination / players) * 360)}deg)`
}; };
}, },
nominee: function() { nominee: function() {
return this.$store.state.players.players[ return this.players[this.session.nomination[1]];
this.$store.state.session.nomination[1]
];
}, },
nomineeStyle: function() { nomineeStyle: function() {
const players = this.$store.state.players.players.length; const players = this.players.length;
const nomination = this.$store.state.session.nomination[1]; const nomination = this.session.nomination[1];
const lock = this.$store.state.session.lockedVote; const lock = this.session.lockedVote;
const rotation = (360 * (nomination + Math.min(lock, players))) / players; const rotation = (360 * (nomination + Math.min(lock, players))) / players;
return { return {
transform: `rotate(${Math.round(rotation)}deg)` transform: `rotate(${Math.round(rotation)}deg)`
}; };
}, },
player: function() { player: function() {
const id = this.$store.state.session.playerId; return this.players.find(p => p.id === this.session.playerId);
return this.$store.state.players.players.find(p => p.id === id);
}, },
...mapState("players", ["players"]), canVote: function() {
...mapState(["session"]), if (!this.player) return false;
...mapGetters({ alive: "players/alive" }) if (this.player.isVoteless && this.nominee.role.team !== "traveler")
return false;
const session = this.session;
const players = this.players.length;
const index = this.players.indexOf(this.player);
const indexAdjusted =
(index - 1 + players - session.nomination[1]) % players;
return indexAdjusted >= session.lockedVote - 1;
}
}, },
methods: { methods: {
start() { start() {
@ -99,6 +100,7 @@ export default {
this.$store.commit("session/nomination", false); this.$store.commit("session/nomination", false);
}, },
vote(vote) { vote(vote) {
if (!this.canVote) return false;
const index = this.players.findIndex(p => p.id === this.session.playerId); const index = this.players.findIndex(p => p.id === this.session.playerId);
if (index >= 0 && !!this.session.votes[index] !== vote) { if (index >= 0 && !!this.session.votes[index] !== vote) {
this.$store.commit("session/vote", [index, vote]); this.$store.commit("session/vote", [index, vote]);

View File

@ -9,8 +9,8 @@ const faIcons = [
"BookOpen", "BookOpen",
"BroadcastTower", "BroadcastTower",
"Camera", "Camera",
"Chair",
"CheckSquare", "CheckSquare",
"Skull",
"Cog", "Cog",
"Copy", "Copy",
"ExchangeAlt", "ExchangeAlt",
@ -23,16 +23,17 @@ const faIcons = [
"RedoAlt", "RedoAlt",
"SearchMinus", "SearchMinus",
"SearchPlus", "SearchPlus",
"Skull",
"Square", "Square",
"TheaterMasks", "TheaterMasks",
"Times",
"TimesCircle", "TimesCircle",
"Undo", "Undo",
"User", "User",
"UserEdit", "UserEdit",
"UserFriends", "UserFriends",
"Users", "Users",
"VoteYea", "VoteYea"
"Chair"
]; ];
library.add(...faIcons.map(i => fas["fa" + i])); library.add(...faIcons.map(i => fas["fa" + i]));
Vue.component("font-awesome-icon", FontAwesomeIcon); Vue.component("font-awesome-icon", FontAwesomeIcon);