Skip to content

Commit

Permalink
Merge pull request #212 from zusorio/confetti-champions
Browse files Browse the repository at this point in the history
feat: Add confetti and champions overlays 🎉
  • Loading branch information
slmnio authored Sep 3, 2023
2 parents 7cd8d56 + a9b7432 commit 41b0ca1
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 5 deletions.
1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"spacetime-informal": "^0.6.1",
"timesync": "^1.0.11",
"vue": "^2.7",
"vue-confetti": "^2.3.0",
"vue-cookies": "^1.8.1",
"vue-meta": "^2.4.0",
"vue-router": "^3.2.0",
Expand Down
7 changes: 5 additions & 2 deletions website/src/apps/BroadcastApp.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<StingerWrap :theme="broadcast.event && broadcast.event.theme" :active="active" :should-use="useBuiltInStingers" :text="stingerText">
<StingerWrap :theme="stingerThemeOverride && overrideTheme || broadcast.event && broadcast.event.theme" :active="active" :should-use="useBuiltInStingers" :text="stingerText">
<div class="broadcast-app" :class="broadcastClass">
<!-- <div style="font-size: 5em; color: black">{{ $root.activeScene }}</div>-->
<router-view id="overlay" :class="bodyClass" :broadcast="broadcast" :client="client" :title="title" :top="top" :active="active"
Expand Down Expand Up @@ -36,7 +36,7 @@ function getComponentName(route) {
export default {
name: "BroadcastApp",
props: ["id", "title", "top", "code", "client", "noAnimation", "noStinger", "bodyClass", "full", "clientName", "backgroundIndex", "stingerText"],
props: ["id", "title", "top", "code", "client", "noAnimation", "noStinger", "bodyClass", "full", "clientName", "backgroundIndex", "stingerText", "stingerThemeOverride"],
components: {
BroadcastBackground,
StingerWrap
Expand Down Expand Up @@ -81,6 +81,9 @@ export default {
}
return broadcast;
},
overrideTheme() {
return ReactiveRoot(this.stingerThemeOverride);
},
haltAnimations() {
return this.noAnimation || (this.broadcast?.broadcast_settings || []).includes("No animations");
},
Expand Down
4 changes: 2 additions & 2 deletions website/src/apps/ClientApp.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<BroadcastApp v-if="broadcastID" :id="broadcastID" :title="title" :client="_client" :no-animation="noAnimation"
:no-stinger="noStinger" :body-class="bodyClass" :full="full" :clientName="client" :background-index="backgroundIndex" :stinger-text="stingerText" />
:no-stinger="noStinger" :body-class="bodyClass" :full="full" :clientName="client" :background-index="backgroundIndex" :stinger-text="stingerText" :stingerThemeOverride="stingerThemeOverride" />
</template>

<script>
Expand All @@ -9,7 +9,7 @@ import { ReactiveRoot, ReactiveThing } from "@/utils/reactive";
export default {
name: "ClientApp",
components: { BroadcastApp },
props: ["client", "title", "noAnimation", "noStinger", "bodyClass", "full", "backgroundIndex", "stingerText"],
props: ["client", "title", "noAnimation", "noStinger", "bodyClass", "full", "backgroundIndex", "stingerText", "stingerThemeOverride"],
computed: {
_client() {
return ReactiveRoot(`client-${this.client}`, {
Expand Down
11 changes: 10 additions & 1 deletion website/src/components/broadcast/StingerWrap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export default {
data: () => ({
showStinger: null,
customTheme: null,
customText: null
customText: null,
hideText: false
}),
watch: {
active(isActive) {
Expand All @@ -45,13 +46,21 @@ export default {
return logoBackground(this.useTheme);
},
stingerText() {
if (this.hideText) return;
return this.customText || this.text;
}
},
methods: {
updateTheme(theme) {
this.customTheme = theme;
console.log("custom stinger theme", theme);
},
updateText(text) {
this.customText = text;
console.log("custom stinger text", text);
},
setTextVisibility(visibility) {
this.hideText = !visibility;
}
}
};
Expand Down
60 changes: 60 additions & 0 deletions website/src/components/broadcast/roots/ChampionsOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<ConfettiOverlay v-if="winner" :theme="winner?.theme" :active="active" :animation-active="animationActive"/>
</template>

<script>
import ConfettiOverlay from "@/components/broadcast/roots/ConfettiOverlay.vue";
import { ReactiveArray, ReactiveRoot, ReactiveThing } from "@/utils/reactive";
export default {
components: { ConfettiOverlay },
props: ["broadcast", "stingerText", "active", "animationActive"],
name: "ChampionsOverlay",
data: () => ({
confettiStarted: false,
prodData: {
minor: true
}
}),
mounted() {
console.log(this.stingerText);
this.$parent.updateText();
this.$parent.setTextVisibility(this.stingerTextVal);
},
computed: {
stingerTextVal() {
return this.winner ? (this.stingerText || "Winners") : null;
},
match() {
if (!this.broadcast?.live_match?.length) return null;
return ReactiveRoot(this.broadcast?.live_match?.[0], {
teams: ReactiveArray("teams", {
theme: ReactiveThing("theme")
})
});
},
winner() {
if (!this.match) return null;
if (!(this.match.first_to && [this.match.score_1, this.match.score_2].some(s => s === this.match.first_to))) return null;
return this.match.teams[this.match.score_1 === this.match.first_to ? 0 : 1];
}
},
watch: {
winner: {
deep: true,
handler(winner) {
console.log("winner change", this.$parent);
this.$parent.updateTheme(winner?.theme);
this.$parent.updateText(this.winner ? (this.stingerText || "Winners") : null);
this.$parent.setTextVisibility(this.stingerTextVal);
}
}
},
metaInfo() {
return {
title: `Champions | ${this.broadcast?.code || this.broadcast?.name || ""}`
};
}
};
</script>
104 changes: 104 additions & 0 deletions website/src/components/broadcast/roots/ConfettiOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<div></div>
</template>
<script>
import VueConfetti from "vue-confetti";
import { ReactiveRoot } from "@/utils/reactive";
import Vue from "vue";
Vue.use(VueConfetti);
export default {
props: ["themeId", "theme", "active", "animationActive"],
name: "ConfettiOverlay",
data: () => ({
confettiStarted: false,
confettiDisabled: false,
noStinger: true,
prodData: {
minor: true
}
}),
methods: {
startOrUpdateConfetti() {
if (this.confettiDisabled) return;
console.log("start confetti");
if (!this.confettiStarted) {
this.$confetti.start({
particles: [
{
type: "circle"
}
],
defaultColors: this.confettiColors
});
this.confettiStarted = true;
} else {
this.$confetti.update({
particles: [
{
type: "circle"
}
],
defaultColors: this.confettiColors
});
}
}
},
watch: {
confettiColors: {
handler() {
if (this.confettiColors.length === 0) return;
this.startOrUpdateConfetti();
},
immediate: true
},
animationActive: {
handler(isActive) {
console.log("active", isActive);
if (!isActive) return;
if (this.confettiColors.length === 0) return;
this.startOrUpdateConfetti();
},
immediate: true
}
},
computed: {
themeData() {
return this.theme || ReactiveRoot(this.themeId);
},
confettiColors() {
return Array.from(new Set(
[
this.themeData?.color_theme,
this.themeData?.color_logo_background,
this.themeData?.color_logo_accent,
this.themeData?.color_accent,
this.themeData?.color_alt
].filter(Boolean))
);
}
},
metaInfo() {
return {
title: `Confetti | ${this.broadcast?.code || this.broadcast?.name || ""}`
};
},
sockets: {
stop_confetti() {
console.log("confetti stop");
this.confettiStarted = false;
this.$confetti.stop();
},
disable_confetti() {
this.confettiDisabled = true;
},
enable_confetti() {
this.confettiDisabled = false;
}
}
};
</script>
<style scoped>
</style>
14 changes: 14 additions & 0 deletions website/src/router/broadcast.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,20 @@ export default [
index: parseInt(route.params.index) || parseInt(route.query.index ?? route.query.number) || 1
})
},
{
path: "confetti",
component: () => import("@/components/broadcast/roots/ConfettiOverlay.vue"),
props: route => ({
themeId: route.query.theme || route.query.themeId || route.query.themeid || route.query.themeID
})
},
{
path: "champions",
component: () => import("@/components/broadcast/roots/ChampionsOverlay.vue"),
props: route => ({
stingerText: route.query.stingerText
})
},

/* Production staff stuff */
{ path: "clock", component: () => import("@/components/broadcast/roots/MediaClock.vue") },
Expand Down
2 changes: 2 additions & 0 deletions website/src/router/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default [
code: route.params.broadcastCode,
title: route.query.title,
stingerText: route.query.stingerText,
stingerThemeOverride: route.query.stingerThemeOverride || route.query.stingerTheme,
top: route.query.top,
noAnimation: (route.query.noAnimate || route.query.dontAnimate || route.query.noAnimation),
noStinger: (route.query.noStinger || route.query.stinger === "false"),
Expand All @@ -88,6 +89,7 @@ export default [
client: route.params.clientID,
title: route.query.title,
stingerText: route.query.stingerText,
stingerThemeOverride: route.query.stingerThemeOverride || route.query.stingerTheme,
noAnimation: (route.query.noAnimate || route.query.dontAnimate || route.query.noAnimation),
noStinger: (route.query.noStinger || route.query.stinger === "false"),
bodyClass: route.query.class || route.query.bodyClass,
Expand Down

0 comments on commit 41b0ca1

Please sign in to comment.