further cleanup

This commit is contained in:
Steffen 2020-05-02 21:33:44 +02:00
parent 966c6f0944
commit 23f754a955
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
7 changed files with 120 additions and 113 deletions

View File

@ -10,32 +10,9 @@
: '' : ''
}" }"
> >
<div class="intro" v-if="!players.length"> <Intro v-if="!players.length"></Intro>
<img src="static/apple-icon.png" alt="" /> <TownInfo :players="players" v-if="players.length"></TownInfo>
Welcome to the (unofficial) <TownSquare :players="players" @screenshot="takeScreenshot"></TownSquare>
<b> Virtual Blood on the Clocktower Town Square</b>!<br />
Please add more players through the
<span class="button">
<font-awesome-icon icon="cog" /> Menu
</span>
on the top right or by pressing <b>[A]</b>.<br />
This project is free and open source and can be found on
<a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a>.
</div>
<TownInfo
:players="players"
:edition="edition"
v-if="players.length"
></TownInfo>
<TownSquare
:is-public="grimoire.isPublic"
:is-night-order="grimoire.isNightOrder"
:players="players"
:roles="roles"
:zoom="grimoire.zoom"
@screenshot="takeScreenshot"
></TownSquare>
<Menu ref="menu" :players="players"></Menu> <Menu ref="menu" :players="players"></Menu>
<EditionSelectionModal :players="players"></EditionSelectionModal> <EditionSelectionModal :players="players"></EditionSelectionModal>
<RoleSelectionModal :players="players"></RoleSelectionModal> <RoleSelectionModal :players="players"></RoleSelectionModal>
@ -49,16 +26,18 @@ import TownInfo from "./components/TownInfo";
import Menu from "./components/Menu"; import Menu from "./components/Menu";
import RoleSelectionModal from "./components/RoleSelectionModal"; import RoleSelectionModal from "./components/RoleSelectionModal";
import EditionSelectionModal from "./components/EditionSelectionModal"; import EditionSelectionModal from "./components/EditionSelectionModal";
import Intro from "./components/Intro";
export default { export default {
components: { components: {
Intro,
EditionSelectionModal, EditionSelectionModal,
Menu, Menu,
TownSquare, TownSquare,
TownInfo, TownInfo,
RoleSelectionModal RoleSelectionModal
}, },
computed: mapState(["grimoire", "edition", "roles"]), computed: mapState(["grimoire"]),
data: function() { data: function() {
return { return {
players: [] players: []
@ -85,15 +64,17 @@ export default {
case "c": case "c":
this.$store.commit("toggleModal", "roles"); this.$store.commit("toggleModal", "roles");
break; break;
case "Escape":
this.$store.commit("toggleMenu");
} }
} }
}, },
mounted() { mounted() {
if (localStorage.background !== undefined) { if (localStorage.background !== undefined) {
this.background = JSON.parse(localStorage.background); this.$store.commit("setBackground", JSON.parse(localStorage.background));
} }
if (localStorage.isPublic !== undefined) { if (localStorage.isPublic !== undefined) {
this.isPublic = JSON.parse(localStorage.isPublic); this.$store.commit("showGrimoire", JSON.parse(localStorage.isPublic));
} }
if (localStorage.edition) { if (localStorage.edition) {
this.$store.commit("setEdition", localStorage.edition); this.$store.commit("setEdition", localStorage.edition);
@ -101,7 +82,7 @@ export default {
if (localStorage.players) { if (localStorage.players) {
this.players = JSON.parse(localStorage.players).map(player => ({ this.players = JSON.parse(localStorage.players).map(player => ({
...player, ...player,
role: this.roles.get(player.role) || {} role: this.$store.state.roles.get(player.role) || {}
})); }));
} }
}, },
@ -223,39 +204,6 @@ ul {
justify-content: center; justify-content: center;
} }
// success animation
@keyframes greenToWhite {
from {
color: green;
}
to {
color: white;
}
}
// Intro
.intro {
text-align: center;
width: 50%;
font-size: 120%;
position: absolute;
padding: 10px;
background: rgba(0, 0, 0, 0.5);
border: 3px solid black;
border-radius: 10px;
z-index: 3;
img {
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -96px;
margin-bottom: 20px;
border-radius: 50%;
box-shadow: 0 0 10px black;
border: 3px solid black;
}
}
// Buttons // Buttons
.button-group { .button-group {
display: flex; display: flex;

47
src/components/Intro.vue Normal file
View File

@ -0,0 +1,47 @@
<template>
<div class="intro" >
<img src="static/apple-icon.png" alt="" />
Welcome to the (unofficial)
<b> Virtual Blood on the Clocktower Town Square</b>!<br />
Please add more players through the
<span class="button">
<font-awesome-icon icon="cog" @click="toggleMenu" /> Menu
</span>
on the top right or by pressing <b>[A]</b>.<br />
This project is free and open source and can be found on
<a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a>.
</div>
</template>
<script>
import { mapMutations } from "vuex";
export default {
methods: mapMutations(["toggleMenu"])
};
</script>
<style scoped lang="scss">
// Intro
.intro {
text-align: center;
width: 50%;
font-size: 120%;
position: absolute;
padding: 10px;
background: rgba(0, 0, 0, 0.5);
border: 3px solid black;
border-radius: 10px;
z-index: 3;
img {
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -96px;
margin-bottom: 20px;
border-radius: 50%;
box-shadow: 0 0 10px black;
border: 3px solid black;
}
}
</style>

View File

@ -6,8 +6,8 @@
@click="takeScreenshot()" @click="takeScreenshot()"
v-bind:class="{ success: grimoire.isScreenshotSuccess }" v-bind:class="{ success: grimoire.isScreenshotSuccess }"
/> />
<div class="menu" v-bind:class="{ open: isMenuOpen }"> <div class="menu" v-bind:class="{ open: grimoire.isMenuOpen }">
<font-awesome-icon icon="cog" @click="isMenuOpen = !isMenuOpen" /> <font-awesome-icon icon="cog" @click="toggleMenu" />
<ul> <ul>
<!-- Grimoire --> <!-- Grimoire -->
<li class="headline"> <li class="headline">
@ -82,9 +82,7 @@ export default {
}, },
props: ["players"], props: ["players"],
data: function() { data: function() {
return { return {};
isMenuOpen: false
};
}, },
computed: mapState(["grimoire"]), computed: mapState(["grimoire"]),
methods: { methods: {
@ -133,6 +131,7 @@ export default {
}, },
...mapMutations([ ...mapMutations([
"toggleGrimoire", "toggleGrimoire",
"toggleMenu",
"toggleNightOrder", "toggleNightOrder",
"updateScreenshot", "updateScreenshot",
"updateZoom", "updateZoom",
@ -145,6 +144,16 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
@import "../vars.scss"; @import "../vars.scss";
// success animation
@keyframes greenToWhite {
from {
color: green;
}
to {
color: white;
}
}
// Controls // Controls
#controls { #controls {
position: absolute; position: absolute;

View File

@ -12,13 +12,19 @@
<div class="shroud" @click="toggleStatus()"></div> <div class="shroud" @click="toggleStatus()"></div>
<div class="life" @click="toggleStatus()"></div> <div class="life" @click="toggleStatus()"></div>
<div class="night first" v-if="player.firstNight && isNightOrder"> <div
class="night first"
v-if="player.firstNight && grimoire.isNightOrder"
>
<em>{{ player.firstNight }}.</em> <em>{{ player.firstNight }}.</em>
<span v-if="player.role.firstNightReminder">{{ <span v-if="player.role.firstNightReminder">{{
player.role.firstNightReminder | handleEmojis player.role.firstNightReminder | handleEmojis
}}</span> }}</span>
</div> </div>
<div class="night other" v-if="player.otherNight && isNightOrder"> <div
class="night other"
v-if="player.otherNight && grimoire.isNightOrder"
>
<em>{{ player.otherNight }}.</em> <em>{{ player.otherNight }}.</em>
<span v-if="player.role.otherNightReminder">{{ <span v-if="player.role.otherNightReminder">{{
player.role.otherNightReminder | handleEmojis player.role.otherNightReminder | handleEmojis
@ -66,6 +72,7 @@
<script> <script>
import Token from "./Token"; import Token from "./Token";
import { mapState } from "vuex";
export default { export default {
components: { components: {
@ -75,20 +82,9 @@ export default {
player: { player: {
type: Object, type: Object,
required: true required: true
},
roles: {
type: Map,
required: true
},
isPublic: {
type: Boolean,
required: true
},
isNightOrder: {
type: Boolean,
required: true
} }
}, },
computed: mapState(["grimoire"]),
data() { data() {
return {}; return {};
}, },
@ -101,7 +97,7 @@ export default {
this.$emit("screenshot", { width, height, x, y }); this.$emit("screenshot", { width, height, x, y });
}, },
toggleStatus() { toggleStatus() {
if (this.isPublic) { if (this.$store.state.grimoire.isPublic) {
if (!this.player.hasDied) { if (!this.player.hasDied) {
this.$set(this.player, "hasDied", true); this.$set(this.player, "hasDied", true);
} else if (this.player.hasVoted) { } else if (this.player.hasVoted) {

View File

@ -40,16 +40,13 @@
<script> <script>
import gameJSON from "./../game"; import gameJSON from "./../game";
import { mapState } from "vuex";
export default { export default {
props: { props: {
players: { players: {
type: Array, type: Array,
required: true required: true
},
edition: {
type: String,
required: true
} }
}, },
computed: { computed: {
@ -70,7 +67,8 @@ export default {
player => player.hasDied === true && player.hasVoted !== true player => player.hasDied === true && player.hasVoted !== true
).length ).length
}; };
} },
...mapState(["edition"])
} }
}; };
</script> </script>
@ -78,6 +76,27 @@ export default {
<style lang="scss"> <style lang="scss">
@import "../vars.scss"; @import "../vars.scss";
// Editions
@each $img, $skipIcons in $editions {
.edition-#{$img} {
background-image: url("../assets/editions/#{$img}.png");
}
@if $skipIcons != true {
.edition-#{$img}.townsfolk {
background-image: url("../assets/editions/#{$img}-townsfolk.png");
}
.edition-#{$img}.outsider {
background-image: url("../assets/editions/#{$img}-outsider.png");
}
.edition-#{$img}.minion {
background-image: url("../assets/editions/#{$img}-minion.png");
}
.edition-#{$img}.demon {
background-image: url("../assets/editions/#{$img}-demon.png");
}
}
}
.info { .info {
position: absolute; position: absolute;
display: flex; display: flex;

View File

@ -2,17 +2,14 @@
<div <div
id="townsquare" id="townsquare"
class="square" class="square"
v-bind:class="{ public: isPublic }" v-bind:class="{ public: grimoire.isPublic }"
v-bind:style="{ zoom: zoom }" v-bind:style="{ zoom: grimoire.zoom }"
> >
<ul class="circle" v-bind:class="['size-' + players.length]"> <ul class="circle" v-bind:class="['size-' + players.length]">
<Player <Player
v-for="(player, index) in players" v-for="(player, index) in players"
:key="index" :key="index"
:player="player" :player="player"
:roles="roles"
:is-public="isPublic"
:is-night-order="isNightOrder"
@add-reminder="openReminderModal" @add-reminder="openReminderModal"
@set-role="openRoleModal" @set-role="openRoleModal"
@remove-player="removePlayer" @remove-player="removePlayer"
@ -60,6 +57,7 @@
</li> </li>
</ul> </ul>
</Modal> </Modal>
<Modal v-show="availableRoles.length && selectedPlayer" @close="closeModal"> <Modal v-show="availableRoles.length && selectedPlayer" @close="closeModal">
<h3>Choose a new character:</h3> <h3>Choose a new character:</h3>
<ul class="tokens"> <ul class="tokens">
@ -80,6 +78,7 @@
import Player from "./Player"; import Player from "./Player";
import Modal from "./Modal"; import Modal from "./Modal";
import Token from "./Token"; import Token from "./Token";
import { mapState } from "vuex";
export default { export default {
components: { components: {
@ -88,27 +87,12 @@ export default {
Player Player
}, },
props: { props: {
isPublic: {
type: Boolean,
required: true
},
isNightOrder: {
type: Boolean,
required: true
},
players: { players: {
type: Array, type: Array,
required: true required: true
},
roles: {
type: Map,
required: true
},
zoom: {
type: Number,
required: true
} }
}, },
computed: mapState(["grimoire"]),
data() { data() {
return { return {
selectedPlayer: false, selectedPlayer: false,
@ -128,7 +112,7 @@ export default {
this.availableRoles = []; this.availableRoles = [];
this.availableReminders = []; this.availableReminders = [];
this.selectedPlayer = player; this.selectedPlayer = player;
this.roles.forEach(role => { this.$store.state.roles.forEach(role => {
if (this.players.some(p => p.role.id === role.id)) { if (this.players.some(p => p.role.id === role.id)) {
this.availableReminders = [ this.availableReminders = [
...this.availableReminders, ...this.availableReminders,
@ -143,7 +127,7 @@ export default {
this.availableRoles = []; this.availableRoles = [];
this.availableReminders = []; this.availableReminders = [];
this.selectedPlayer = player; this.selectedPlayer = player;
this.roles.forEach(role => { this.$store.state.roles.forEach(role => {
if (player.role && role.id !== player.role.id) { if (player.role && role.id !== player.role.id) {
this.availableRoles.push(role); this.availableRoles.push(role);
} }

View File

@ -22,6 +22,7 @@ export default new Vuex.Store({
grimoire: { grimoire: {
isNightOrder: true, isNightOrder: true,
isPublic: true, isPublic: true,
isMenuOpen: false,
isScreenshot: false, isScreenshot: false,
isScreenshotSuccess: false, isScreenshotSuccess: false,
zoom: 1, zoom: 1,
@ -36,12 +37,15 @@ export default new Vuex.Store({
players: [] players: []
}, },
mutations: { mutations: {
toggleMenu({ grimoire }) {
grimoire.isMenuOpen = !grimoire.isMenuOpen;
},
toggleGrimoire({ grimoire }) { toggleGrimoire({ grimoire }) {
grimoire.isPublic = !grimoire.isPublic; grimoire.isPublic = !grimoire.isPublic;
grimoire.isControlOpen = !grimoire.isPublic; grimoire.isControlOpen = !grimoire.isPublic;
}, },
showGrimoire({ grimoire }) { showGrimoire({ grimoire }, isPublic = false) {
grimoire.isPublic = false; grimoire.isPublic = isPublic;
}, },
toggleNightOrder({ grimoire }) { toggleNightOrder({ grimoire }) {
grimoire.isNightOrder = !grimoire.isNightOrder; grimoire.isNightOrder = !grimoire.isNightOrder;