added vote component

This commit is contained in:
Steffen 2020-05-31 23:42:08 +02:00
parent f42d7dd2be
commit c2d142f169
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
10 changed files with 136 additions and 14 deletions

View File

@ -11,8 +11,9 @@
}" }"
> >
<Intro v-if="!players.length"></Intro> <Intro v-if="!players.length"></Intro>
<TownInfo v-if="players.length"></TownInfo> <TownInfo v-if="players.length && !session.nomination"></TownInfo>
<TownSquare @screenshot="takeScreenshot"></TownSquare> <TownSquare @screenshot="takeScreenshot"></TownSquare>
<Vote v-if="session.nomination"></Vote>
<Menu ref="menu"></Menu> <Menu ref="menu"></Menu>
<EditionModal /> <EditionModal />
<RolesModal /> <RolesModal />
@ -29,9 +30,11 @@ import RolesModal from "./components/modals/RolesModal";
import EditionModal from "./components/modals/EditionModal"; 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";
export default { export default {
components: { components: {
Vote,
ReferenceModal, ReferenceModal,
Intro, Intro,
TownInfo, TownInfo,

BIN
src/assets/clock-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/assets/clock-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -58,6 +58,12 @@
@click="movePlayer(player)" @click="movePlayer(player)"
title="Move player to this seat" title="Move player to this seat"
/> />
<font-awesome-icon
icon="hand-point-right"
class="nominate"
@click="nominatePlayer(player)"
title="Nominate this player"
/>
<!-- Claimed seat icon --> <!-- Claimed seat icon -->
<font-awesome-icon icon="chair" v-if="player.id" class="seat" /> <font-awesome-icon icon="chair" v-if="player.id" class="seat" />
@ -85,10 +91,10 @@
<li @click="changeName"> <li @click="changeName">
<font-awesome-icon icon="user-edit" />Rename <font-awesome-icon icon="user-edit" />Rename
</li> </li>
<!--<li @click="nomination"> <li v-if="!session.nomination" @click="nominatePlayer()">
<font-awesome-icon icon="hand-point-right" /> <font-awesome-icon icon="hand-point-right" />
Nomination Nomination
</li>--> </li>
<li @click="movePlayer()"> <li @click="movePlayer()">
<font-awesome-icon icon="redo-alt" /> <font-awesome-icon icon="redo-alt" />
Move player Move player
@ -219,6 +225,10 @@ export default {
this.isMenuOpen = false; this.isMenuOpen = false;
this.$emit("trigger", ["movePlayer", player]); this.$emit("trigger", ["movePlayer", player]);
}, },
nominatePlayer(player) {
this.isMenuOpen = false;
this.$emit("trigger", ["nominatePlayer", player]);
},
cancel() { cancel() {
this.$emit("trigger", ["cancel"]); this.$emit("trigger", ["cancel"]);
}, },
@ -391,6 +401,7 @@ export default {
cursor: pointer; cursor: pointer;
&.swap, &.swap,
&.move, &.move,
&.nominate,
&.cancel { &.cancel {
top: 9%; top: 9%;
left: 20%; left: 20%;
@ -406,13 +417,14 @@ export default {
} }
} }
li.from .player > svg.cancel { li.from:not(.nominate) .player > svg.cancel {
opacity: 1; opacity: 1;
transform: scale(1); transform: scale(1);
pointer-events: all; pointer-events: all;
} }
li.swap:not(.from) .player > svg.swap, li.swap:not(.from) .player > svg.swap,
li.nominate .player > svg.nominate,
li.move:not(.from) .player > svg.move { li.move:not(.from) .player > svg.move {
opacity: 1; opacity: 1;
transform: scale(1); transform: scale(1);

View File

@ -59,15 +59,13 @@ export default {
).length ).length
}; };
}, },
...mapState({ ...mapState(["edition"]),
edition: state => state.edition, ...mapState("players", ["players"])
players: state => state.players.players
})
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
@import "../vars.scss"; @import "../vars.scss";
// Editions // Editions
@ -94,12 +92,8 @@ export default {
.info { .info {
position: absolute; position: absolute;
display: flex; display: flex;
left: 50%;
top: 50%;
width: 20%; width: 20%;
height: 20%; height: 20%;
margin-left: -10%;
margin-top: -5%;
padding: 50px 0 0; padding: 50px 0 0;
align-items: center; align-items: center;
align-content: center; align-content: center;

View File

@ -133,6 +133,20 @@ export default {
this.cancel(); this.cancel();
} }
}, },
nominatePlayer(from, to) {
if (to === undefined && from !== this.nominate) {
this.cancel();
if (from !== this.nominate) {
this.nominate = from;
}
} else {
this.$store.commit("session/nomination", [
this.nominate,
this.players.indexOf(to)
]);
this.cancel();
}
},
cancel() { cancel() {
this.move = -1; this.move = -1;
this.swap = -1; this.swap = -1;
@ -229,6 +243,10 @@ export default {
height: 100%; height: 100%;
border-radius: 50%; border-radius: 50%;
padding: 20px; padding: 20px;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
} }
/***** Demon bluffs *******/ /***** Demon bluffs *******/

78
src/components/Vote.vue Normal file
View File

@ -0,0 +1,78 @@
<template>
<div class="vote">
<div class="arrows">
<span class="nominator"></span>
<span class="nominee"></span>
</div>
<div class="overlay">
<em>{{ nominator.name }}</em> nominated <em>{{ nominee.name }}</em
>!
<br />
<template v-if="nominee.role.team !== 'traveler'">
<em>{{ Math.ceil(alive / 2) }} votes</em> required for an
<em>execution</em>
</template>
<template v-else>
<em>{{ Math.ceil(players.length / 2) }} votes</em> required for an
<em>exile</em>
</template>
<div class="button-group">
<div class="button">Start Vote</div>
<div class="button" @click="finish">Finish Vote</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapState } from "vuex";
export default {
computed: {
nominator: function() {
return this.$store.state.players.players[
this.$store.state.session.nomination[0]
];
},
nominee: function() {
return this.$store.state.players.players[
this.$store.state.session.nomination[1]
];
},
...mapState("players", ["players"]),
...mapState(["session"]),
...mapGetters({ alive: "players/alive" })
},
methods: {
finish() {
this.$store.commit("session/nomination", false);
}
}
};
</script>
<style lang="scss" scoped>
@import "../vars.scss";
.vote {
position: absolute;
height: 300px;
width: 300px;
z-index: 20;
display: flex;
align-items: center;
align-content: center;
justify-content: center;
background: url("../assets/demon-head.png") center center no-repeat;
background-size: auto 100%;
text-align: center;
text-shadow: 0 1px 2px #000000, 0 -1px 2px #000000, 1px 0 2px #000000,
-1px 0 2px #000000;
em {
color: red;
font-style: normal;
font-weight: bold;
}
}
</style>

View File

@ -12,6 +12,9 @@ const state = () => ({
}); });
const getters = { const getters = {
alive({ players }) {
return players.filter(player => !player.isDead).length;
},
nonTravelers({ players }) { nonTravelers({ players }) {
const nonTravelers = players.filter( const nonTravelers = players.filter(
player => player.role.team !== "traveler" player => player.role.team !== "traveler"

View File

@ -3,7 +3,8 @@ const state = () => ({
isSpectator: false, isSpectator: false,
playerCount: 0, playerCount: 0,
playerId: "", playerId: "",
claimedSeat: -1 claimedSeat: -1,
nomination: false
}); });
const getters = {}; const getters = {};
@ -25,6 +26,9 @@ const mutations = {
}, },
claimSeat(state, claimedSeat) { claimSeat(state, claimedSeat) {
state.claimedSeat = claimedSeat; state.claimedSeat = claimedSeat;
},
nomination(state, nomination) {
state.nomination = nomination;
} }
}; };

View File

@ -289,6 +289,16 @@ class LiveSession {
delete this._players[player]; delete this._players[player];
} }
} }
// remove claimed seats from players that are no longer connected
this._store.state.players.players.forEach(player => {
if (player.id && !this._players[player.id]) {
this._store.commit("players/update", {
player,
property: "id",
value: ""
});
}
});
this._store.commit( this._store.commit(
"session/setPlayerCount", "session/setPlayerCount",
Object.keys(this._players).length Object.keys(this._players).length