replaced background image again

added session handling with persistence and urls
This commit is contained in:
Steffen 2020-05-12 20:48:00 +02:00
parent c8d71e7454
commit 4fd880961c
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
9 changed files with 111 additions and 44 deletions

View File

@ -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

View File

@ -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() {
if (confirm("Are you sure you want to leave the active live game?")) {
this.$store.commit("setSpectator", false); this.$store.commit("setSpectator", false);
this.$store.commit("setSessionId", ""); 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;

View File

@ -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,

View File

@ -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}?`

View File

@ -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);

View File

@ -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) {

View File

@ -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":

View File

@ -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);
}
}; };