mirror of https://github.com/bra1n/townsquare.git
further cleanup
This commit is contained in:
parent
966c6f0944
commit
23f754a955
74
src/App.vue
74
src/App.vue
|
@ -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;
|
||||||
|
|
|
@ -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>
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue