splatoon3.ink/src/components/SplatfestResultsBox.vue
Matt Isenhower 29482689f4 Migrate Tailwind CSS from v3 to v4
- Replace JS config (tailwind.config.js) with CSS @theme block in base.css
- Switch from PostCSS to @tailwindcss/vite plugin
- Convert all bg-opacity-*/border-opacity-* to slash syntax (e.g. bg-zinc-900/70)
- Add @custom-variant for mobile and ss variants
- Add @reference to Vue scoped styles using @apply
- Rename v3 utilities: rounded→rounded-sm, backdrop-blur-sm→backdrop-blur-xs,
  drop-shadow→drop-shadow-sm, rotate-[25deg]→rotate-25
- Delete obsolete tailwind.config.js and postcss.config.js
- Rename vite.config.js to .mjs for ESM compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 13:52:27 -08:00

102 lines
3.4 KiB
Vue

<template>
<ProductContainer v-if="winner" class="pt-10 pb-4" bg="bg-camo-purple" :bg-style="`background-color: ${toRgba(winner.color)};`">
<div class="space-y-2">
<div class="font-splatoon1 text-2xl lg:text-3xl text-shadow mx-2">
{{ $t('festival.results.title') }}
</div>
<div class="mx-2 px-1 bg-zinc-700/50 backdrop-blur-xs rounded-lg">
<div class="flex justify-center md:justify-center py-2">
<div class="w-36 sm:mx-4 lg:-mx-1" />
<template v-for="team in festival.teams" :key="team.id">
<div class="w-12 mx-2 sm:w-20 flex justify-center py-1 rounded-sm" :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 justify-center font-splatoon2 text-shadow text-center text-sm lg:text-base py-1 items-center">
<div class="w-36 sm:mx-2">
{{ $t(row.title) }}
</div>
<div class="flex bg-zinc-700/70 rounded-full py-1">
<div v-for="(result, i) in row.results" :key="i" class="w-16 lg:w-20 sm:mx-2">
<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 text-shadow text-sm lg:text-base mx-2 ss:hidden">
{{ $t('festival.results.won', { team: $t(`splatnet.festivals.${ festival.__splatoon3ink_id }.teams.${winnerIndex}.teamName`, winner.teamName) }) }}
</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(() => {
const rows = [
{
title: 'festival.results.conchshells',
results: results('horagaiRatio', 'isHoragaiRatioTop'),
},
{
title: 'festival.results.votes',
results: results('voteRatio', 'isVoteRatioTop'),
},
{
title: 'festival.results.open',
results: results('regularContributionRatio', 'isRegularContributionRatioTop'),
},
{
title: 'festival.results.pro',
results: results('challengeContributionRatio', 'isChallengeContributionRatioTop'),
},
];
if (props.festival.teams.find(t => t.result.tricolorContributionRatio !== null)) {
rows.push({
title: 'festival.results.tricolor',
results: results('tricolorContributionRatio', 'isTricolorContributionRatioTop'),
});
}
return rows;
});
const winnerIndex = computed(() => props.festival.teams.findIndex(t => t.result.isWinner));
const winner = computed(() => winnerIndex.value >= 0 ? props.festival.teams[winnerIndex.value] : null);
</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>