mirror of https://github.com/bra1n/townsquare.git
added vote buttons
This commit is contained in:
parent
952cb1f0a5
commit
31b4cd5183
|
@ -7,7 +7,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]
|
||||||
},
|
},
|
||||||
player.role.team
|
player.role.team
|
||||||
]"
|
]"
|
||||||
|
@ -40,6 +41,12 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Overlay icons -->
|
<!-- Overlay icons -->
|
||||||
|
<font-awesome-icon
|
||||||
|
icon="skull"
|
||||||
|
class="vote"
|
||||||
|
title="Vote"
|
||||||
|
@click="vote()"
|
||||||
|
/>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
icon="times-circle"
|
icon="times-circle"
|
||||||
class="cancel"
|
class="cancel"
|
||||||
|
@ -71,7 +78,7 @@
|
||||||
<!-- Ghost vote icon -->
|
<!-- Ghost vote icon -->
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
icon="vote-yea"
|
icon="vote-yea"
|
||||||
class="vote"
|
class="has-vote"
|
||||||
v-if="player.isDead && !player.isVoteless"
|
v-if="player.isDead && !player.isVoteless"
|
||||||
@click="updatePlayer('isVoteless', true)"
|
@click="updatePlayer('isVoteless', true)"
|
||||||
title="Ghost vote"
|
title="Ghost vote"
|
||||||
|
@ -163,6 +170,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
index: function() {
|
||||||
|
return this.$store.state.players.players.indexOf(this.player);
|
||||||
|
},
|
||||||
...mapState(["grimoire", "session"]),
|
...mapState(["grimoire", "session"]),
|
||||||
...mapGetters({ nightOrder: "players/nightOrder" })
|
...mapGetters({ nightOrder: "players/nightOrder" })
|
||||||
},
|
},
|
||||||
|
@ -235,6 +245,10 @@ export default {
|
||||||
claimSeat() {
|
claimSeat() {
|
||||||
this.isMenuOpen = false;
|
this.isMenuOpen = false;
|
||||||
this.$emit("trigger", ["claimSeat"]);
|
this.$emit("trigger", ["claimSeat"]);
|
||||||
|
},
|
||||||
|
vote() {
|
||||||
|
if (this.player.id !== this.session.playerId) return;
|
||||||
|
this.$store.commit("session/vote", [this.index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -402,6 +416,7 @@ export default {
|
||||||
&.swap,
|
&.swap,
|
||||||
&.move,
|
&.move,
|
||||||
&.nominate,
|
&.nominate,
|
||||||
|
&.vote,
|
||||||
&.cancel {
|
&.cancel {
|
||||||
top: 9%;
|
top: 9%;
|
||||||
left: 20%;
|
left: 20%;
|
||||||
|
@ -417,6 +432,17 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#townsquare.vote .player.voted-yes > svg.vote {
|
||||||
|
color: $demon;
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#townsquare.vote .player.you.voted-yes > svg.vote {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
li.from:not(.nominate) .player > svg.cancel {
|
li.from:not(.nominate) .player > svg.cancel {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
|
@ -432,7 +458,7 @@ li.move:not(.from) .player > svg.move {
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** Vote icon ********/
|
/****** Vote icon ********/
|
||||||
.player .vote {
|
.player .has-vote {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
bottom: 45px;
|
bottom: 45px;
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
class="square"
|
class="square"
|
||||||
v-bind:class="{
|
v-bind:class="{
|
||||||
public: grimoire.isPublic,
|
public: grimoire.isPublic,
|
||||||
spectator: session.isSpectator
|
spectator: session.isSpectator,
|
||||||
|
vote: session.nomination
|
||||||
}"
|
}"
|
||||||
v-bind:style="{ zoom: grimoire.zoom }"
|
v-bind:style="{ zoom: grimoire.zoom }"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="vote">
|
<div id="vote">
|
||||||
<div class="arrows">
|
<div class="arrows">
|
||||||
<span class="nominee" :style="nomineeStyle"></span>
|
<span class="nominee" :style="nomineeStyle"></span>
|
||||||
<span class="nominator" :style="nominatorStyle"></span>
|
<span class="nominator" :style="nominatorStyle"></span>
|
||||||
|
@ -10,17 +10,29 @@
|
||||||
>!
|
>!
|
||||||
<br />
|
<br />
|
||||||
<template v-if="nominee.role.team !== 'traveler'">
|
<template v-if="nominee.role.team !== 'traveler'">
|
||||||
<em class="blue">{{ Math.ceil(alive / 2) }} votes</em> required for an
|
<em class="blue">{{ Math.ceil(alive / 2) }} votes</em> required to
|
||||||
<em>execution</em>
|
<em>execute</em>.
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<em>{{ Math.ceil(players.length / 2) }} votes</em> required for an
|
<em>{{ Math.ceil(players.length / 2) }} votes</em> required to
|
||||||
<em>exile</em>
|
<em>exile</em>.
|
||||||
</template>
|
</template>
|
||||||
<div class="button-group">
|
<div class="button-group" v-if="!session.isSpectator">
|
||||||
<div class="button">Start Vote</div>
|
<div class="button">Start Vote</div>
|
||||||
<div class="button" @click="finish">Finish Vote</div>
|
<div class="button" @click="finish">Finish Vote</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
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-yes" @click="vote(true)">Vote YES</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="!player">
|
||||||
|
Please claim a seat to vote.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,6 +66,10 @@ export default {
|
||||||
transform: `rotate(${Math.round((nomination / players) * 360)}deg)`
|
transform: `rotate(${Math.round((nomination / players) * 360)}deg)`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
player: function() {
|
||||||
|
const id = this.$store.state.session.playerId;
|
||||||
|
return this.$store.state.players.players.find(p => p.id === id);
|
||||||
|
},
|
||||||
...mapState("players", ["players"]),
|
...mapState("players", ["players"]),
|
||||||
...mapState(["session"]),
|
...mapState(["session"]),
|
||||||
...mapGetters({ alive: "players/alive" })
|
...mapGetters({ alive: "players/alive" })
|
||||||
|
@ -61,6 +77,12 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
finish() {
|
finish() {
|
||||||
this.$store.commit("session/nomination", false);
|
this.$store.commit("session/nomination", false);
|
||||||
|
},
|
||||||
|
vote(vote) {
|
||||||
|
const index = this.players.findIndex(p => p.id === this.session.playerId);
|
||||||
|
if (index >= 0 && !!this.session.votes[index] !== vote) {
|
||||||
|
this.$store.commit("session/vote", [index, vote]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -69,7 +91,7 @@ export default {
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "../vars.scss";
|
@import "../vars.scss";
|
||||||
|
|
||||||
.vote {
|
#vote {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 20%;
|
width: 20%;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
@ -151,4 +173,30 @@ export default {
|
||||||
animation: arrow-cw 1s ease-out;
|
animation: arrow-cw 1s ease-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button.vote-no {
|
||||||
|
background: radial-gradient(
|
||||||
|
at 0 -15%,
|
||||||
|
rgba(255, 255, 255, 0.07) 70%,
|
||||||
|
rgba(255, 255, 255, 0) 71%
|
||||||
|
)
|
||||||
|
0 0/80% 90% no-repeat content-box,
|
||||||
|
linear-gradient(#0031ad, rgba(5, 0, 0, 0.22)) content-box,
|
||||||
|
linear-gradient(#292929, #001142) border-box;
|
||||||
|
box-shadow: inset 0 1px 1px #002c9c, 0 0 10px #000;
|
||||||
|
&:hover {
|
||||||
|
color: #008cf7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button.vote-yes {
|
||||||
|
background: radial-gradient(
|
||||||
|
at 0 -15%,
|
||||||
|
rgba(255, 255, 255, 0.07) 70%,
|
||||||
|
rgba(255, 255, 255, 0) 71%
|
||||||
|
)
|
||||||
|
0 0/80% 90% no-repeat content-box,
|
||||||
|
linear-gradient(#ad0000, rgba(5, 0, 0, 0.22)) content-box,
|
||||||
|
linear-gradient(#292929, #420000) border-box;
|
||||||
|
box-shadow: inset 0 1px 1px #9c0000, 0 0 10px #000;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,6 +10,7 @@ const faIcons = [
|
||||||
"BroadcastTower",
|
"BroadcastTower",
|
||||||
"Camera",
|
"Camera",
|
||||||
"CheckSquare",
|
"CheckSquare",
|
||||||
|
"Skull",
|
||||||
"Cog",
|
"Cog",
|
||||||
"Copy",
|
"Copy",
|
||||||
"ExchangeAlt",
|
"ExchangeAlt",
|
||||||
|
|
|
@ -4,7 +4,9 @@ const state = () => ({
|
||||||
playerCount: 0,
|
playerCount: 0,
|
||||||
playerId: "",
|
playerId: "",
|
||||||
claimedSeat: -1,
|
claimedSeat: -1,
|
||||||
nomination: false
|
nomination: false,
|
||||||
|
votes: [],
|
||||||
|
lockedVote: -1
|
||||||
});
|
});
|
||||||
|
|
||||||
const getters = {};
|
const getters = {};
|
||||||
|
@ -29,6 +31,11 @@ const mutations = {
|
||||||
},
|
},
|
||||||
nomination(state, nomination) {
|
nomination(state, nomination) {
|
||||||
state.nomination = nomination;
|
state.nomination = nomination;
|
||||||
|
state.votes = [];
|
||||||
|
},
|
||||||
|
vote(state, [index, vote]) {
|
||||||
|
state.votes = [...state.votes];
|
||||||
|
state.votes[index] = vote === undefined ? !state.votes[index] : vote;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,12 @@ class LiveSession {
|
||||||
case "ping":
|
case "ping":
|
||||||
this._handlePing(params);
|
this._handlePing(params);
|
||||||
break;
|
break;
|
||||||
|
case "nomination":
|
||||||
|
this._store.commit("session/nomination", params);
|
||||||
|
break;
|
||||||
|
case "vote":
|
||||||
|
this._store.commit("session/vote", params);
|
||||||
|
break;
|
||||||
case "bye":
|
case "bye":
|
||||||
this._handleBye(params);
|
this._handleBye(params);
|
||||||
break;
|
break;
|
||||||
|
@ -291,7 +297,7 @@ class LiveSession {
|
||||||
}
|
}
|
||||||
// remove claimed seats from players that are no longer connected
|
// remove claimed seats from players that are no longer connected
|
||||||
this._store.state.players.players.forEach(player => {
|
this._store.state.players.players.forEach(player => {
|
||||||
if (player.id && !this._players[player.id]) {
|
if (!this._isSpectator && player.id && !this._players[player.id]) {
|
||||||
this._store.commit("players/update", {
|
this._store.commit("players/update", {
|
||||||
player,
|
player,
|
||||||
property: "id",
|
property: "id",
|
||||||
|
@ -336,20 +342,50 @@ class LiveSession {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_updateSeat([index, value]) {
|
_updateSeat([index, value]) {
|
||||||
|
if (this._isSpectator) return;
|
||||||
const property = "id";
|
const property = "id";
|
||||||
|
const players = this._store.state.players.players;
|
||||||
// remove previous seat
|
// remove previous seat
|
||||||
const player = this._store.state.players.players.find(
|
const oldIndex = players.findIndex(({ id }) => id === value);
|
||||||
({ id }) => id === value
|
if (oldIndex >= 0 && oldIndex !== index) {
|
||||||
);
|
this._store.commit("players/update", {
|
||||||
if (player) {
|
player: players[oldIndex],
|
||||||
this._store.commit("players/update", { player, property, value: "" });
|
property,
|
||||||
|
value: ""
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// add playerId to new seat
|
// add playerId to new seat
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
const player = this._store.state.players.players[index];
|
const player = players[index];
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
this._store.commit("players/update", { player, property, value });
|
this._store.commit("players/update", { player, property, value });
|
||||||
}
|
}
|
||||||
|
// update player session list as if this was a ping
|
||||||
|
this._handlePing([true, value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A player nomination.
|
||||||
|
* @param nomination [nominator, nominee]
|
||||||
|
*/
|
||||||
|
nomination(nomination) {
|
||||||
|
if (this._isSpectator) return;
|
||||||
|
const players = this._store.state.players.players;
|
||||||
|
if (
|
||||||
|
!nomination ||
|
||||||
|
(players.length > nomination[0] && players.length > nomination[1])
|
||||||
|
) {
|
||||||
|
this._send("nomination", nomination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a vote.
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
vote([index]) {
|
||||||
|
if (!this._isSpectator) return;
|
||||||
|
this._send("vote", [index, this._store.state.session.votes[index]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,6 +407,12 @@ module.exports = store => {
|
||||||
case "session/claimSeat":
|
case "session/claimSeat":
|
||||||
session.claimSeat(payload);
|
session.claimSeat(payload);
|
||||||
break;
|
break;
|
||||||
|
case "session/nomination":
|
||||||
|
session.nomination(payload);
|
||||||
|
break;
|
||||||
|
case "session/vote":
|
||||||
|
session.vote(payload);
|
||||||
|
break;
|
||||||
case "players/set":
|
case "players/set":
|
||||||
case "players/swap":
|
case "players/swap":
|
||||||
case "players/move":
|
case "players/move":
|
||||||
|
|
Loading…
Reference in New Issue