Skip to content

Commit

Permalink
Change intermission-hosts graphic to be a better "lower thirds" style
Browse files Browse the repository at this point in the history
  • Loading branch information
zoton2 committed Feb 17, 2024
1 parent c7ca021 commit 2fd5efe
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 88 deletions.
3 changes: 2 additions & 1 deletion src/graphics/_misc/themes/default.theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ body {
background-color: rgba(0, 0, 0, 0.85);
}

#IntermissionPlayer .UpcomingBar .Header {
#IntermissionPlayer .UpcomingBar .Header,
#IntermissionHosts .UpcomingBar .Header {
background-color: #41245b;
}

Expand Down
3 changes: 2 additions & 1 deletion src/graphics/_misc/themes/esaw24.theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ body {
background-color: rgba(0, 0, 0, 0.85);
}

#IntermissionPlayer .UpcomingBar .Header {
#IntermissionPlayer .UpcomingBar .Header,
#IntermissionHosts .UpcomingBar .Header {
/* Copied from ".bg--darkpurple" */
background: var(--colour--darkpurple);
}
Expand Down
2 changes: 1 addition & 1 deletion src/graphics/game-layout/esaw24-base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ import MediaBox from '@shared/graphics/mediabox';
import { RunDataActiveRun } from 'speedcontrol-util/types';
import { Component, Prop, Vue } from 'vue-property-decorator';
import { State } from 'vuex-class';
import ParticipantInfo from '../_misc/components/ParticipantInfo.vue';
import CommentatorsReader from './components/CommentatorsReader.vue';
import DonationBar from './components/DonationBar.vue';
import GameCapture from './components/GameCapture.vue';
import ParticipantInfo from './components/ParticipantInfo.vue';
import Player from './components/Player.vue';
import RunInfo from './components/RunInfo.vue';
import Timer from './components/Timer.vue';
Expand Down
38 changes: 0 additions & 38 deletions src/graphics/intermission-hosts/components/Host.vue

This file was deleted.

Binary file added src/graphics/intermission-hosts/esaOhNo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 22 additions & 2 deletions src/graphics/intermission-hosts/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
/* eslint no-new: off, @typescript-eslint/explicit-function-return-type: off */

import { setUpReplicants } from '@esa-layouts/browser_shared/replicant_store';
import { UpcomingRunID } from '@esa-layouts/types/schemas';
import { SpeedcontrolUtilBrowser } from 'speedcontrol-util';
import { RunData } from 'speedcontrol-util/types';
import Vue from 'vue';
import '../_misc/common.css';
import '../_misc/theme';
import App from './main.vue';
import waitForReplicants from './store';
import store from './store';

const sc = new SpeedcontrolUtilBrowser(nodecg);

// Gets next run based on the ID supplied.
function getNextRun(id: UpcomingRunID): RunData | null {
const runIndex = sc.findRunIndex(id);
if (runIndex >= 0) {
return sc.getRunDataArray()[runIndex] ?? null;
}
return null;
}

setUpReplicants(store).then(() => {
store.watch(() => store.state.ReplicantModule.reps.upcomingRunID, (val) => {
store.commit('setNextRun', getNextRun(val));
}, { immediate: true });

waitForReplicants().then((store) => {
new Vue({
store,
el: '#App',
Expand Down
119 changes: 108 additions & 11 deletions src/graphics/intermission-hosts/main.vue
Original file line number Diff line number Diff line change
@@ -1,35 +1,132 @@
<template>
<div
class="Layout Flex"
id="IntermissionHosts"
class="Layout FlexColumn"
:style="{
'box-sizing': 'border-box',
color: 'white',
height: '1000px',
'justify-content': 'space-evenly',
'align-items': 'flex-end',
'justify-content': 'flex-end',
'align-items': 'center',
padding: '50px',
gap: '20px',
zoom,
}"
>
<host
v-for="pos in ['left', 'midleft', 'middle', 'midright', 'right']"
:key="pos"
:pos="pos"
<participant-info
v-if="donationReader"
type="reader"
:name="donationReader.name"
:pronouns="donationReader.pronouns"
:country="donationReader.country"
:style="{
zoom: '1.5',
}"
/>
<div
class="Flex UpcomingBar"
:style="{
width: '100%',
height: '80px',
}"
>
<div
class="Flex Header"
:style="{
color: 'white',
'text-transform': 'uppercase',
height: '100%',
padding: '0 25px',
'font-size': '45px',
'font-weight': 500,
}"
>
Setting Up For
</div>
<div
class="Flex"
:style="{
flex: 1,
'background-color': 'rgba(0, 0, 0, 0.3)',
height: '100%',
'font-size': '40px',
'justify-content': 'space-between',
padding: '0 27px',
}"
>
<template v-if="nextRun">
{{ nextRun.game }}
<span
class="RunInfoExtra"
:style="{
'font-size': '33px',
}"
>
<span v-if="nextRun.category">
{{ nextRun.category }}
</span>
<span v-if="nextRun.system">
{{ nextRun.system }}
</span>
<span v-if="getRunTotalPlayers(nextRun) > 0">
{{ formPlayerNamesStr(nextRun) }}
</span>
<span v-if="nextRun.estimate">
{{ nextRun.estimate }}
</span>
</span>
</template>
<template v-else>
<div class="Flex">
No More Runs
<img
src="./esaOhNo.png"
:style="{ height: '1.4em', 'margin-left': '10px' }"
>
</div>
</template>
</div>
</div>
</div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import { replicantModule } from '@esa-layouts/browser_shared/replicant_store';
import { SpeedcontrolUtilBrowser } from 'speedcontrol-util';
import { RunData } from 'speedcontrol-util/types';
import { Component, Vue } from 'vue-property-decorator';
import ParticipantInfo from '../_misc/components/ParticipantInfo.vue';
import { getZoomAmountCSS } from '../_misc/helpers';
import Host from './components/Host.vue';
import { storeModule } from './store';
@Component({
components: {
Host,
ParticipantInfo,
},
})
export default class extends Vue {
getRunTotalPlayers = SpeedcontrolUtilBrowser.getRunTotalPlayers;
zoom = getZoomAmountCSS();
get donationReader() {
return replicantModule.repsTyped.donationReaderNew;
}
get nextRun(): RunData | null { return storeModule.nextRun; }
formPlayerNamesStr(runData: RunData): string {
return runData.teams.map((team) => (
team.name || team.players.map((player) => player.name).join(', ')
)).join(' vs. ') || 'N/A';
}
}
</script>

<style>
@import url('../_misc/themes/esaw24.theme.css');
</style>

<style scoped>
.RunInfoExtra > span:not(:last-child)::after {
content: ' /';
}
</style>
55 changes: 21 additions & 34 deletions src/graphics/intermission-hosts/store.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,30 @@
import type NodeCGTypes from '@nodecg/types';
import clone from 'clone';
import { ReplicantModule, ReplicantTypes } from '@esa-layouts/browser_shared/replicant_store';
import { RunData } from 'speedcontrol-util/types';
import Vue from 'vue';
import Vuex, { Store } from 'vuex';
import { Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';

Vue.use(Vuex);

export interface Users {
[k: string]: {
[k: string]: {
display_name: string; // eslint-disable-line camelcase
country_code?: string; // eslint-disable-line camelcase
};
};
}
@Module({ name: 'OurModule' })
class OurModule extends VuexModule {
nextRun: RunData | null = null;

// Replicants and their types
const reps: {
users: NodeCGTypes.ClientReplicant<Users>;
[k: string]: NodeCGTypes.ClientReplicant<unknown>;
} = {
users: nodecg.Replicant('users', 'speedcontrol-flagcarrier'),
};
// Helper getter to return all replicants.
get reps(): ReplicantTypes {
return this.context.rootState.ReplicantModule.reps;
}

const store = new Vuex.Store({
state: {},
mutations: {
setState(state, { name, val }): void {
Vue.set(state, name, val);
},
},
});
@Mutation
setNextRun(run: RunData): void {
Vue.set(this, 'nextRun', run);
}
}

Object.keys(reps).forEach((key) => {
reps[key].on('change', (val) => {
store.commit('setState', { name: key, val: clone(val) });
});
const store = new Store({
strict: process.env.NODE_ENV !== 'production',
state: {},
modules: { ReplicantModule, OurModule },
});

export default async (): Promise<Store<Record<string, unknown>>> => {
await NodeCG.waitForReplicants(...Object.keys(reps).map((key) => reps[key]));
return store;
};
export default store;
export const storeModule = getModule(OurModule, store);

0 comments on commit 2fd5efe

Please sign in to comment.