mirror of https://github.com/bra1n/townsquare.git
replaced background image again
added session handling with persistence and urls
This commit is contained in:
parent
c8d71e7454
commit
4fd880961c
12
src/App.vue
12
src/App.vue
|
@ -37,10 +37,10 @@ export default {
|
||||||
EditionModal,
|
EditionModal,
|
||||||
RolesModal
|
RolesModal
|
||||||
},
|
},
|
||||||
computed: mapState({
|
computed: {
|
||||||
grimoire: state => state.grimoire,
|
...mapState(["grimoire", "session"]),
|
||||||
players: state => state.players.players
|
...mapState("players", ["players"])
|
||||||
}),
|
},
|
||||||
methods: {
|
methods: {
|
||||||
takeScreenshot(dimensions) {
|
takeScreenshot(dimensions) {
|
||||||
this.$refs.menu.takeScreenshot(dimensions);
|
this.$refs.menu.takeScreenshot(dimensions);
|
||||||
|
@ -57,11 +57,11 @@ export default {
|
||||||
this.$refs.menu.randomizeSeatings();
|
this.$refs.menu.randomizeSeatings();
|
||||||
break;
|
break;
|
||||||
case "e":
|
case "e":
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
this.$store.commit("toggleModal", "edition");
|
this.$store.commit("toggleModal", "edition");
|
||||||
break;
|
break;
|
||||||
case "c":
|
case "c":
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
this.$store.commit("toggleModal", "roles");
|
this.$store.commit("toggleModal", "roles");
|
||||||
break;
|
break;
|
||||||
case "Escape":
|
case "Escape":
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
|
@ -1,9 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<Screenshot ref="screenshot"></Screenshot>
|
<Screenshot ref="screenshot"></Screenshot>
|
||||||
|
<font-awesome-icon
|
||||||
|
@click="leaveSession"
|
||||||
|
icon="broadcast-tower"
|
||||||
|
v-if="session.sessionId"
|
||||||
|
v-bind:class="{ spectator: session.isSpectator }"
|
||||||
|
title="You're currently in a live game!"
|
||||||
|
/>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
icon="camera"
|
icon="camera"
|
||||||
@click="takeScreenshot()"
|
@click="takeScreenshot()"
|
||||||
|
title="Take a screenshot"
|
||||||
v-bind:class="{ success: grimoire.isScreenshotSuccess }"
|
v-bind:class="{ success: grimoire.isScreenshotSuccess }"
|
||||||
/>
|
/>
|
||||||
<div class="menu" v-bind:class="{ open: grimoire.isMenuOpen }">
|
<div class="menu" v-bind:class="{ open: grimoire.isMenuOpen }">
|
||||||
|
@ -37,22 +45,26 @@
|
||||||
<li @click="setBackground">
|
<li @click="setBackground">
|
||||||
Background image
|
Background image
|
||||||
</li>
|
</li>
|
||||||
<li @click="hostSession" v-if="!grimoire.sessionId">
|
<li @click="hostSession" v-if="!session.sessionId">
|
||||||
Host Live Session
|
Host Live Session
|
||||||
</li>
|
</li>
|
||||||
<li @click="joinSession" v-if="!grimoire.sessionId">
|
<li @click="joinSession" v-if="!session.sessionId">
|
||||||
Join Live Session
|
Join Live Session
|
||||||
</li>
|
</li>
|
||||||
<li class="headline" v-if="grimoire.sessionId">
|
<li class="headline" v-if="session.sessionId">
|
||||||
<font-awesome-icon icon="broadcast-tower" />
|
<font-awesome-icon icon="broadcast-tower" />
|
||||||
{{ grimoire.isSpectator ? "Playing" : "Hosting" }}
|
{{ session.isSpectator ? "Playing" : "Hosting" }}
|
||||||
</li>
|
</li>
|
||||||
<li @click="leaveSession" v-if="grimoire.sessionId">
|
<li v-if="session.sessionId" @click="copySessionUrl">
|
||||||
<em>{{ grimoire.sessionId }}</em>
|
<em><font-awesome-icon icon="copy"/></em>
|
||||||
|
Copy player link
|
||||||
|
</li>
|
||||||
|
<li @click="leaveSession" v-if="session.sessionId">
|
||||||
|
<em>{{ session.sessionId }}</em>
|
||||||
Leave Session
|
Leave Session
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<template v-if="!grimoire.isSpectator">
|
<template v-if="!session.isSpectator">
|
||||||
<!-- Users -->
|
<!-- Users -->
|
||||||
<li class="headline">
|
<li class="headline">
|
||||||
<font-awesome-icon icon="users" />
|
<font-awesome-icon icon="users" />
|
||||||
|
@ -99,7 +111,7 @@ export default {
|
||||||
Screenshot
|
Screenshot
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["grimoire"]),
|
...mapState(["grimoire", "session"]),
|
||||||
...mapState("players", ["players"])
|
...mapState("players", ["players"])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -115,49 +127,70 @@ export default {
|
||||||
},
|
},
|
||||||
hostSession() {
|
hostSession() {
|
||||||
const sessionId = prompt(
|
const sessionId = prompt(
|
||||||
"Enter a code for your session",
|
"Enter a channel number for your session",
|
||||||
Math.round(Math.random() * 10000)
|
Math.round(Math.random() * 10000)
|
||||||
);
|
);
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
this.$store.commit("setSpectator", false);
|
this.$store.commit("setSpectator", false);
|
||||||
this.$store.commit("setSessionId", sessionId.substr(0, 5));
|
this.$store.commit(
|
||||||
|
"setSessionId",
|
||||||
|
sessionId.replace(/[^0-9]/g, "").substr(0, 5)
|
||||||
|
);
|
||||||
|
this.copySessionUrl();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
copySessionUrl() {
|
||||||
|
// check for clipboard permissions
|
||||||
|
navigator.permissions
|
||||||
|
.query({ name: "clipboard-write" })
|
||||||
|
.then(({ state }) => {
|
||||||
|
if (state === "granted" || state === "prompt") {
|
||||||
|
const url = window.location.href.split("#")[0];
|
||||||
|
const link = url + "#play/" + this.session.sessionId;
|
||||||
|
navigator.clipboard.writeText(link);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
joinSession() {
|
joinSession() {
|
||||||
const sessionId = prompt(
|
const sessionId = prompt(
|
||||||
"Enter the code of the session you want to join"
|
"Enter the channel number of the session you want to join"
|
||||||
);
|
);
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
this.$store.commit("setSpectator", true);
|
this.$store.commit("setSpectator", true);
|
||||||
this.$store.commit("setSessionId", sessionId.substr(0, 5));
|
this.$store.commit(
|
||||||
|
"setSessionId",
|
||||||
|
sessionId.replace(/[^0-9]/g, "").substr(0, 5)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leaveSession() {
|
leaveSession() {
|
||||||
this.$store.commit("setSpectator", false);
|
if (confirm("Are you sure you want to leave the active live game?")) {
|
||||||
this.$store.commit("setSessionId", "");
|
this.$store.commit("setSpectator", false);
|
||||||
|
this.$store.commit("setSessionId", "");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
addPlayer() {
|
addPlayer() {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
const name = prompt("Player name");
|
const name = prompt("Player name");
|
||||||
if (name) {
|
if (name) {
|
||||||
this.$store.commit("players/add", name);
|
this.$store.commit("players/add", name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
randomizeSeatings() {
|
randomizeSeatings() {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (confirm("Are you sure you want to randomize seatings?")) {
|
if (confirm("Are you sure you want to randomize seatings?")) {
|
||||||
this.$store.dispatch("players/randomize");
|
this.$store.dispatch("players/randomize");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearPlayers() {
|
clearPlayers() {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (confirm("Are you sure you want to remove all players?")) {
|
if (confirm("Are you sure you want to remove all players?")) {
|
||||||
this.$store.commit("players/clear");
|
this.$store.commit("players/clear");
|
||||||
this.$store.commit("setBluff");
|
this.$store.commit("setBluff");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearRoles() {
|
clearRoles() {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (confirm("Are you sure you want to remove all player roles?")) {
|
if (confirm("Are you sure you want to remove all player roles?")) {
|
||||||
this.$store.dispatch("players/clearRoles");
|
this.$store.dispatch("players/clearRoles");
|
||||||
this.$store.commit("setBluff");
|
this.$store.commit("setBluff");
|
||||||
|
@ -194,13 +227,13 @@ export default {
|
||||||
right: 3px;
|
right: 3px;
|
||||||
top: 3px;
|
top: 3px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
padding-right: 50px;
|
||||||
|
|
||||||
#app.screenshot & {
|
#app.screenshot & {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
cursor: pointer;
|
|
||||||
filter: drop-shadow(0 0 5px rgba(0, 0, 0, 1));
|
filter: drop-shadow(0 0 5px rgba(0, 0, 0, 1));
|
||||||
&.success {
|
&.success {
|
||||||
animation: greenToWhite 1s normal forwards;
|
animation: greenToWhite 1s normal forwards;
|
||||||
|
@ -208,12 +241,17 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-camera {
|
> svg {
|
||||||
position: absolute;
|
cursor: pointer;
|
||||||
right: 50px;
|
|
||||||
top: 10px;
|
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .fa-broadcast-tower {
|
||||||
|
color: $demon;
|
||||||
|
&.spectator {
|
||||||
|
color: $townsfolk;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
|
@ -221,12 +259,16 @@ export default {
|
||||||
transform-origin: 190px 22px;
|
transform-origin: 190px 22px;
|
||||||
transition: transform 500ms cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
transition: transform 500ms cubic-bezier(0.68, -0.55, 0.27, 1.55);
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
&.open {
|
&.open {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> svg {
|
> svg {
|
||||||
|
cursor: pointer;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
border: 3px solid black;
|
border: 3px solid black;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
|
|
|
@ -93,7 +93,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["grimoire"]),
|
...mapState(["grimoire", "session"]),
|
||||||
...mapGetters({ nightOrder: "players/nightOrder" })
|
...mapGetters({ nightOrder: "players/nightOrder" })
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -125,7 +125,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeName() {
|
changeName() {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
const name = prompt("Player name", this.player.name) || this.player.name;
|
const name = prompt("Player name", this.player.name) || this.player.name;
|
||||||
this.updatePlayer("name", name);
|
this.updatePlayer("name", name);
|
||||||
},
|
},
|
||||||
|
@ -135,7 +135,7 @@ export default {
|
||||||
this.updatePlayer("reminders", reminders);
|
this.updatePlayer("reminders", reminders);
|
||||||
},
|
},
|
||||||
updatePlayer(property, value) {
|
updatePlayer(property, value) {
|
||||||
if (this.grimoire.isSpectator && property !== "reminders") return;
|
if (this.session.isSpectator && property !== "reminders") return;
|
||||||
this.$store.commit("players/update", {
|
this.$store.commit("players/update", {
|
||||||
player: this.player,
|
player: this.player,
|
||||||
property,
|
property,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
class="square"
|
class="square"
|
||||||
v-bind:class="{
|
v-bind:class="{
|
||||||
public: grimoire.isPublic,
|
public: grimoire.isPublic,
|
||||||
spectator: grimoire.isSpectator
|
spectator: session.isSpectator
|
||||||
}"
|
}"
|
||||||
v-bind:style="{ zoom: grimoire.zoom }"
|
v-bind:style="{ zoom: grimoire.zoom }"
|
||||||
>
|
>
|
||||||
|
@ -54,7 +54,7 @@ export default {
|
||||||
ReminderModal
|
ReminderModal
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["grimoire", "roles"]),
|
...mapState(["grimoire", "roles", "session"]),
|
||||||
...mapState("players", ["players"])
|
...mapState("players", ["players"])
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -74,12 +74,12 @@ export default {
|
||||||
},
|
},
|
||||||
openRoleModal(playerIndex) {
|
openRoleModal(playerIndex) {
|
||||||
const player = this.players[playerIndex];
|
const player = this.players[playerIndex];
|
||||||
if (this.grimoire.isSpectator && player.role.team === "traveler") return;
|
if (this.session.isSpectator && player.role.team === "traveler") return;
|
||||||
this.selectedPlayer = playerIndex;
|
this.selectedPlayer = playerIndex;
|
||||||
this.$store.commit("toggleModal", "role");
|
this.$store.commit("toggleModal", "role");
|
||||||
},
|
},
|
||||||
removePlayer(playerIndex) {
|
removePlayer(playerIndex) {
|
||||||
if (this.grimoire.isSpectator) return;
|
if (this.session.isSpectator) return;
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
`Do you really want to remove ${this.players[playerIndex].name}?`
|
`Do you really want to remove ${this.players[playerIndex].name}?`
|
||||||
|
|
|
@ -19,7 +19,8 @@ import {
|
||||||
faSquare,
|
faSquare,
|
||||||
faRandom,
|
faRandom,
|
||||||
faPeopleArrows,
|
faPeopleArrows,
|
||||||
faBroadcastTower
|
faBroadcastTower,
|
||||||
|
faCopy
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ library.add(
|
||||||
faSquare,
|
faSquare,
|
||||||
faRandom,
|
faRandom,
|
||||||
faPeopleArrows,
|
faPeopleArrows,
|
||||||
faBroadcastTower
|
faBroadcastTower,
|
||||||
|
faCopy
|
||||||
);
|
);
|
||||||
|
|
||||||
Vue.component("font-awesome-icon", FontAwesomeIcon);
|
Vue.component("font-awesome-icon", FontAwesomeIcon);
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default new Vuex.Store({
|
||||||
isScreenshotSuccess: false,
|
isScreenshotSuccess: false,
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
background: "",
|
background: "",
|
||||||
bluffs: [],
|
bluffs: []
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
sessionId: "",
|
sessionId: "",
|
||||||
|
@ -72,11 +72,11 @@ export default new Vuex.Store({
|
||||||
setBackground({ grimoire }, background) {
|
setBackground({ grimoire }, background) {
|
||||||
grimoire.background = background;
|
grimoire.background = background;
|
||||||
},
|
},
|
||||||
setSessionId({ grimoire }, sessionId) {
|
setSessionId({ session }, sessionId) {
|
||||||
grimoire.sessionId = sessionId;
|
session.sessionId = sessionId;
|
||||||
},
|
},
|
||||||
setSpectator({ grimoire }, spectator) {
|
setSpectator({ session }, spectator) {
|
||||||
grimoire.isSpectator = spectator;
|
session.isSpectator = spectator;
|
||||||
},
|
},
|
||||||
setBluff({ grimoire }, { index, role } = {}) {
|
setBluff({ grimoire }, { index, role } = {}) {
|
||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
|
|
|
@ -27,6 +27,11 @@ module.exports = store => {
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (localStorage.getItem("session")) {
|
||||||
|
const [spectator, sessionId] = JSON.parse(localStorage.getItem("session"));
|
||||||
|
store.commit("setSpectator", spectator);
|
||||||
|
store.commit("setSessionId", sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
// listen to mutations
|
// listen to mutations
|
||||||
store.subscribe(({ type, payload }, state) => {
|
store.subscribe(({ type, payload }, state) => {
|
||||||
|
@ -53,6 +58,16 @@ module.exports = store => {
|
||||||
JSON.stringify(state.grimoire.bluffs.map(({ id }) => id))
|
JSON.stringify(state.grimoire.bluffs.map(({ id }) => id))
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case "setSessionId":
|
||||||
|
if (payload) {
|
||||||
|
localStorage.setItem(
|
||||||
|
"session",
|
||||||
|
JSON.stringify([state.session.isSpectator, payload])
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("session");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "players/add":
|
case "players/add":
|
||||||
case "players/update":
|
case "players/update":
|
||||||
case "players/remove":
|
case "players/remove":
|
||||||
|
|
|
@ -79,7 +79,7 @@ class LiveSession {
|
||||||
* @param channel
|
* @param channel
|
||||||
*/
|
*/
|
||||||
connect(channel) {
|
connect(channel) {
|
||||||
this.isSpectator = this.store.state.grimoire.isSpectator;
|
this.isSpectator = this.store.state.session.isSpectator;
|
||||||
this._open(channel);
|
this._open(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ module.exports = store => {
|
||||||
if (payload) {
|
if (payload) {
|
||||||
session.connect(payload);
|
session.connect(payload);
|
||||||
} else {
|
} else {
|
||||||
|
window.location.hash = "";
|
||||||
session.disconnect();
|
session.disconnect();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -264,4 +265,11 @@ module.exports = store => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// check for session Id in hash
|
||||||
|
const [command, param] = window.location.hash.substr(1).split("/");
|
||||||
|
if (command === "play") {
|
||||||
|
store.commit("setSpectator", true);
|
||||||
|
store.commit("setSessionId", param);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue