Add a Splatfest results box

This commit is contained in:
Matt Isenhower 2022-09-25 16:40:51 -04:00
parent 5264884e3f
commit 9f3fb1dbff
4 changed files with 114 additions and 2 deletions

View File

@ -1,6 +1,6 @@
<template>
<div class="relative">
<div class="absolute inset-0 product-mask rounded-2xl -z-10" :class="props.bg"></div>
<div class="absolute inset-0 product-mask rounded-2xl -z-10" :class="props.bg" :style="bgStyle"></div>
<slot />
</div>
</template>
@ -11,6 +11,7 @@ const props = defineProps({
type: String,
default: 'bg-splatoon-blue',
},
bgStyle: String,
})
</script>

View File

@ -0,0 +1,90 @@
<template>
<ProductContainer class="pt-10 pb-4" bg="bg-camo-purple" :bgStyle="`background-color: ${toRgba(winner.color)};`">
<div class="space-y-2">
<div class="font-splatoon1 text-3xl mx-2">
Results!
</div>
<div class="mx-2 px-1 bg-zinc-700 bg-opacity-50 backdrop-blur-sm rounded-lg">
<div class="flex justify-end py-2">
<template v-for="team in festival.teams" :key="team.id">
<div class="w-20 mx-2 flex justify-center py-1 rounded" :style="`background-color: ${toRgba(team.color)};`">
<img :src="team.image.url" class="w-6 h-6" />
</div>
</template>
</div>
<template v-for="row in resultRows" :key="row.title">
<div class="flex font-splatoon2 text-shadow text-center py-1 items-center">
<div class="w-36 mx-2">
{{ row.title }}
</div>
<div class="flex bg-zinc-700 bg-opacity-70 rounded-full py-1">
<div class="w-20 mx-2" v-for="(result, i) in row.results" :key="i">
<div :class="result.isTop ? 'text-splatoon-yellow' : 'text-zinc-300'">
{{ (result.ratio * 100).toFixed(2) }}%
</div>
</div>
</div>
</div>
</template>
</div>
<div class="font-splatoon2 text-splatoon-yellow text-center mx-2 ss:hidden">
Team {{ winner.teamName }} Wins!
</div>
</div>
</ProductContainer>
</template>
<script setup>
import { computed } from 'vue';
import ProductContainer from './ProductContainer.vue';
const props = defineProps({
festival: Object,
});
function toRgba(color) {
return `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${color.a})`;
}
function results(ratioKey, topKey) {
return props.festival.teams.map(team => ({
ratio: team.result[ratioKey],
isTop: team.result[topKey],
}));
}
const resultRows = computed(() => {
return [
{
title: 'Conch Shells',
results: results('horagaiRatio', 'isHoragaiRatioTop'),
},
{
title: 'Votes',
results: results('voteRatio', 'isVoteRatioTop'),
},
{
title: 'Open',
results: results('regularContributionRatio', 'isRegularContributionRatioTop'),
},
{
title: 'Pro',
results: results('challengeContributionRatio', 'isChallengeContributionRatioTop'),
},
];
});
const winner = computed(() => props.festival.teams.find(t => t.result.isWinner));
</script>
<style scoped>
:deep(.bg-camo-purple) {
background-image: url('@/assets/img/camo-transparent-bg.png'),
linear-gradient(180deg, rgba(2, 0, 36, 0.10) 0%, rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0.25) 100%);
background-size: cover;
}
</style>

View File

@ -27,6 +27,7 @@ function defineSplatfestRegionStore(region) {
return {
...node,
status: getStatus(node),
hasResults: node.teams.some(t => t.result),
};
}));
@ -34,6 +35,12 @@ function defineSplatfestRegionStore(region) {
const activeFestival = computed(() => festivals.value?.find(f => f.status === STATUS_ACTIVE));
const upcomingFestival = computed(() => festivals.value?.find(f => f.status === STATUS_UPCOMING));
// A "recent festival" is one that ended within the past 3 days
const recentFestival = computed(() => festivals.value?.find(f =>
f.status === STATUS_PAST &&
time.now - Date.parse(f.endTime) < 3 * 24 * 60 * 60 * 1000
));
// TODO: Eventually this needs to be handled on a per-region basis.
const tricolor = computed(() => {
let fest = useSchedulesDataStore().data?.currentFest;
@ -48,7 +55,7 @@ function defineSplatfestRegionStore(region) {
};
});
return { festivals, previousFestivals, activeFestival, upcomingFestival, tricolor };
return { festivals, previousFestivals, activeFestival, upcomingFestival, recentFestival, tricolor };
});
}

View File

@ -20,6 +20,19 @@
class="flex-1 max-w-md md:-rotate-1"
/>
</div>
<div class="flex items-center justify-center flex-col space-y-6 md:flex-row md:space-x-6 md:space-y-0" v-if="usSplatfests.recentFestival">
<SplatfestBox
:festival="usSplatfests.recentFestival"
class="max-w-md md:-rotate-1"
/>
<SplatfestResultsBox
v-if="usSplatfests.recentFestival.hasResults"
:festival="usSplatfests.recentFestival"
class="max-w-md md:rotate-1"
/>
</div>
</div>
</div>
</MainLayout>
@ -31,5 +44,6 @@ import ScheduleBox from '../components/ScheduleBox.vue';
import { useUSSplatfestsStore } from '@/stores/splatfests';
import SplatfestBox from '../components/SplatfestBox.vue';
import SplatfestResultsBox from '../components/SplatfestResultsBox.vue';
const usSplatfests = useUSSplatfestsStore();
</script>