mirror of
https://github.com/misenhower/splatoon3.ink.git
synced 2026-08-25 10:04:30 -05:00
Add basic Splatfest support
This commit is contained in:
BIN
src/assets/img/camo-transparent-bg.png
Normal file
BIN
src/assets/img/camo-transparent-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 914 KiB |
@@ -60,7 +60,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { useAnarchyOpenSchedulesStore, useAnarchySeriesSchedulesStore, useRegularSchedulesStore } from '../stores/schedules';
|
||||
import { useAnarchyOpenSchedulesStore, useAnarchySeriesSchedulesStore, useRegularSchedulesStore, useSplatfestSchedulesStore } from '../stores/schedules';
|
||||
import ProductContainer from './ProductContainer.vue';
|
||||
import StageImage from './StageImage.vue';
|
||||
import ScheduleRow from './ScheduleRow.vue';
|
||||
@@ -100,6 +100,13 @@ const types = {
|
||||
img: battleBankaraSvg,
|
||||
bg: 'bg-splatoon-battle-ranked bg-tapes',
|
||||
},
|
||||
splatfest: {
|
||||
name: 'Splatfest Battle',
|
||||
badge: null,
|
||||
store: useSplatfestSchedulesStore(),
|
||||
img: battleRegularSvg,
|
||||
bg: 'bg-splatoon-battle-regular bg-tapes',
|
||||
},
|
||||
};
|
||||
|
||||
const type = computed(() => types[props.type]);
|
||||
|
||||
73
src/components/SplatfestBox.vue
Normal file
73
src/components/SplatfestBox.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<ProductContainer class="pt-10 pb-4" bg="bg-zinc-500 bg-camo-purple">
|
||||
<div class="space-y-2">
|
||||
<div class="font-splatoon1 text-3xl mx-2">
|
||||
{{ title }}
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mx-2">
|
||||
<div class="font-splatoon2 text-zinc-200 text-lg text-center text-shadow bg-zinc-700 px-4 py-1 rounded-full bg-opacity-50 backdrop-blur-sm">
|
||||
{{ festival.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<img :src="props.festival.image.url" />
|
||||
|
||||
<div class="flex -mt-3 mb-4">
|
||||
<template v-for="team in festival.teams" :key="team.id">
|
||||
<div class="flex-1 flex justify-center items-center">
|
||||
<SquidTape class="font-splatoon2 text-shadow -rotate-3" bg="" :style="`background-color: ${toRgba(team.color)};`">
|
||||
<div class="px-2">
|
||||
{{ team.teamName }}
|
||||
</div>
|
||||
</SquidTape>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="font-splatoon2 text-splatoon-yellow text-center mx-2">
|
||||
{{ formatDateTime(festival.startTime) }}
|
||||
–
|
||||
{{ formatDateTime(festival.endTime) }}
|
||||
</div>
|
||||
</div>
|
||||
</ProductContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import ProductContainer from './ProductContainer.vue';
|
||||
import { STATUS_PAST, STATUS_ACTIVE, STATUS_UPCOMING } from '@/stores/splatfests';
|
||||
import SquidTape from './SquidTape.vue';
|
||||
import { formatDateTime } from '../common/time';
|
||||
|
||||
const props = defineProps({
|
||||
festival: Object,
|
||||
});
|
||||
|
||||
const title = computed(() => {
|
||||
switch (props.festival.status) {
|
||||
case STATUS_PAST:
|
||||
return 'Recent Splatfest';
|
||||
case STATUS_UPCOMING:
|
||||
return 'Upcoming Splatfest';
|
||||
case STATUS_ACTIVE:
|
||||
default:
|
||||
return 'Splatfest';
|
||||
}
|
||||
});
|
||||
|
||||
function toRgba(color) {
|
||||
return `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${color.a})`;
|
||||
}
|
||||
</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>
|
||||
@@ -41,11 +41,13 @@ function defineEndpointStore(id, endpoint, transform = null) {
|
||||
|
||||
export const useSchedulesDataStore = defineEndpointStore('schedules', '/data/schedules.json', d => d.data);
|
||||
export const useGearDataStore = defineEndpointStore('gear', '/data/gear.json', d => d.data);
|
||||
export const useFestivalsDataStore = defineEndpointStore('festivals', '/data/festivals.json');
|
||||
|
||||
export const useDataStore = defineStore('data', () => {
|
||||
const stores = {
|
||||
schedules: useSchedulesDataStore(),
|
||||
gear: useGearDataStore(),
|
||||
festivals: useFestivalsDataStore(),
|
||||
};
|
||||
let updateDataTimer;
|
||||
|
||||
@@ -93,6 +95,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
stopUpdating,
|
||||
schedules: computed(() => stores.schedules.data),
|
||||
gear: computed(() => stores.gear.data),
|
||||
festivals: computed(() => stores.festivals.data),
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -28,17 +28,24 @@ export const useRegularSchedulesStore = defineScheduleStore('regular', {
|
||||
settings: node => node.regularMatchSetting,
|
||||
});
|
||||
|
||||
// Anarchy Battle
|
||||
// Anarchy Battle (Series)
|
||||
export const useAnarchySeriesSchedulesStore = defineScheduleStore('anarchy/series', {
|
||||
nodes: () => useSchedulesDataStore().data?.bankaraSchedules.nodes,
|
||||
settings: node => node.bankaraMatchSettings?.find(s => s.mode === 'CHALLENGE'),
|
||||
});
|
||||
|
||||
// Anarchy Battle (Open)
|
||||
export const useAnarchyOpenSchedulesStore = defineScheduleStore('anarchy/open', {
|
||||
nodes: () => useSchedulesDataStore().data?.bankaraSchedules.nodes,
|
||||
settings: node => node.bankaraMatchSettings?.find(s => s.mode === 'OPEN'),
|
||||
});
|
||||
|
||||
// Splatfest Battle
|
||||
export const useSplatfestSchedulesStore = defineScheduleStore('splatfest', {
|
||||
nodes: () => useSchedulesDataStore().data?.festSchedules.nodes,
|
||||
settings: node => node.festMatchSetting,
|
||||
});
|
||||
|
||||
// Salmon Run
|
||||
export const useSalmonRunSchedulesStore = defineScheduleStore('salmonRun', {
|
||||
nodes: () => useSchedulesDataStore().data?.coopGroupingSchedule.regularSchedules.nodes,
|
||||
@@ -49,5 +56,6 @@ if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useRegularSchedulesStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAnarchySeriesSchedulesStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAnarchyOpenSchedulesStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useSplatfestSchedulesStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useSalmonRunSchedulesStore, import.meta.hot));
|
||||
}
|
||||
|
||||
51
src/stores/splatfests.mjs
Normal file
51
src/stores/splatfests.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
import { acceptHMRUpdate, defineStore } from "pinia";
|
||||
import { computed } from "vue";
|
||||
import { useFestivalsDataStore } from "./data.mjs";
|
||||
import { useTimeStore } from "./time.mjs";
|
||||
|
||||
export const STATUS_PAST = 'past';
|
||||
export const STATUS_ACTIVE = 'active';
|
||||
export const STATUS_UPCOMING = 'upcoming';
|
||||
|
||||
function defineSplatfestRegionStore(region) {
|
||||
return defineStore(`splatfests/${region}`, () => {
|
||||
const time = useTimeStore();
|
||||
const store = useFestivalsDataStore();
|
||||
|
||||
function getStatus(node) {
|
||||
switch (true) {
|
||||
case time.isActive(node.startTime, node.endTime):
|
||||
return STATUS_ACTIVE;
|
||||
case time.isUpcoming(node.startTime):
|
||||
return STATUS_UPCOMING;
|
||||
default:
|
||||
return STATUS_PAST;
|
||||
}
|
||||
}
|
||||
|
||||
const festivals = computed(() => store.data?.[region]?.data.festRecords.nodes.map(node => {
|
||||
return {
|
||||
...node,
|
||||
status: getStatus(node),
|
||||
};
|
||||
}));
|
||||
|
||||
const previousFestivals = computed(() => festivals.value?.filter(f => f.status === STATUS_PAST));
|
||||
const activeFestival = computed(() => festivals.value?.find(f => f.status === STATUS_ACTIVE));
|
||||
const upcomingFestival = computed(() => festivals.value?.find(f => f.status === STATUS_UPCOMING))
|
||||
|
||||
return { festivals, previousFestivals, activeFestival, upcomingFestival };
|
||||
});
|
||||
}
|
||||
|
||||
export const useUSSplatfestsStore = defineSplatfestRegionStore('US');
|
||||
export const useEUSplatfestsStore = defineSplatfestRegionStore('EU');
|
||||
export const useJPSplatfestsStore = defineSplatfestRegionStore('JP');
|
||||
export const useAPSplatfestsStore = defineSplatfestRegionStore('AP');
|
||||
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useUSSplatfestsStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useEUSplatfestsStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useJPSplatfestsStore, import.meta.hot));
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAPSplatfestsStore, import.meta.hot));
|
||||
}
|
||||
@@ -1,12 +1,25 @@
|
||||
<template>
|
||||
<MainLayout title="Map Schedules">
|
||||
<div class="grow flex items-center justify-center">
|
||||
<div class="mx-4 md:mx-12 max-w-screen-2xl w-full">
|
||||
<div class="flex flex-col space-y-6 md:flex-row md:space-x-6 md:space-y-0">
|
||||
<div class="mx-4 md:mx-12 max-w-screen-2xl w-full space-y-10">
|
||||
<div class="flex flex-col space-y-6 md:flex-row md:space-x-6 md:space-y-0 justify-center" v-if="usSplatfests.activeFestival">
|
||||
<div>
|
||||
<SplatfestBox :festival="usSplatfests.activeFestival" class="flex-1 max-w-md md:-rotate-1" />
|
||||
</div>
|
||||
<ScheduleBox type="splatfest" class="flex-1 max-w-lg md:rotate-1" />
|
||||
</div>
|
||||
<div class="flex flex-col space-y-6 md:flex-row md:space-x-6 md:space-y-0" v-else>
|
||||
<ScheduleBox type="regular" class="flex-1 md:-rotate-1" />
|
||||
<ScheduleBox type="anarchySeries" class="flex-1 md:rotate-1" />
|
||||
<ScheduleBox type="anarchyOpen" class="flex-1 md:-rotate-1" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center" v-if="usSplatfests.upcomingFestival">
|
||||
<SplatfestBox
|
||||
:festival="usSplatfests.upcomingFestival"
|
||||
class="flex-1 max-w-md md:-rotate-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MainLayout>
|
||||
@@ -15,4 +28,8 @@
|
||||
<script setup>
|
||||
import MainLayout from '@/layouts/MainLayout.vue'
|
||||
import ScheduleBox from '../components/ScheduleBox.vue';
|
||||
|
||||
import { useUSSplatfestsStore } from '@/stores/splatfests';
|
||||
import SplatfestBox from '../components/SplatfestBox.vue';
|
||||
const usSplatfests = useUSSplatfestsStore();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user