mirror of
https://github.com/misenhower/splatoon3.ink.git
synced 2026-03-21 17:54:13 -05:00
Add a dialog for showing upcoming schedules
This commit is contained in:
parent
2e2522c487
commit
bc96496c55
|
|
@ -6,8 +6,8 @@
|
|||
<div class="fixed inset-0 bg-zinc-900/80 transition-opacity backdrop-blur-sm" />
|
||||
</TransitionChild>
|
||||
|
||||
<div class="fixed inset-0 z-20 overflow-y-auto">
|
||||
<div class="flex min-h-full justify-center p-4 text-center items-center">
|
||||
<div class="fixed inset-0 z-20" :class="noScroll ? 'overflow-hidden' : 'overflow-y-auto'">
|
||||
<div class="flex justify-center p-4 text-center" :class="noScroll ? 'h-full overflow-hidden' : 'min-h-full items-center'">
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-0 scale-95"
|
||||
enter-to="opacity-100 translate-y-0 scale-100" leave="ease-in duration-200"
|
||||
|
|
@ -31,6 +31,7 @@ defineProps({
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
noScroll: Boolean,
|
||||
innerClass: String,
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<ProductContainer :bg="type.bg" class="w-full pt-10 pb-8">
|
||||
<ProductContainer :bg="type.bg" class="w-full pt-10 pb-4">
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center space-x-2 mx-2">
|
||||
<img :src="type.img" />
|
||||
|
|
@ -67,12 +67,21 @@
|
|||
|
||||
<ScheduleRow :schedule="nextSchedule" />
|
||||
</div>
|
||||
|
||||
<div class="text-center pt-2">
|
||||
<button class="bg-zinc-300 bg-opacity-50 hover:bg-opacity-70 px-2 py-1 rounded-full font-splatoon2 text-shadow" @click="open = true">
|
||||
<span class="inline-block rotate-[25deg] text-red"></span>
|
||||
All Upcoming Schedules
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ScheduleDialog :type="props.type" :show="open" @close="open = false" />
|
||||
</ProductContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useUSSplatfestsStore } from '@/stores/splatfests';
|
||||
import ProductContainer from './ProductContainer.vue';
|
||||
import StageImage from './StageImage.vue';
|
||||
|
|
@ -80,6 +89,7 @@ import ScheduleRow from './ScheduleRow.vue';
|
|||
import RuleIcon from './RuleIcon.vue';
|
||||
import SquidTape from './SquidTape.vue';
|
||||
import { useScheduleTypes } from './concerns/scheduleTypes.mjs';
|
||||
import ScheduleDialog from './ScheduleDialog.vue';
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
|
|
@ -94,6 +104,8 @@ const type = computed(() => types[props.type]);
|
|||
const store = computed(() => type.value.store);
|
||||
const nextSchedule = computed(() => store.value.upcomingSchedules?.[0]);
|
||||
const tricolor = computed(() => useUSSplatfestsStore().tricolor);
|
||||
|
||||
const open = ref(false);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
87
src/components/ScheduleDialog.vue
Normal file
87
src/components/ScheduleDialog.vue
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<template>
|
||||
<ModalDialog inner-class="md:-rotate-1" no-scroll>
|
||||
<div class="h-full w-full max-w-2xl isolate rounded-2xl overflow-hidden" :class="type.bg">
|
||||
<div class="relative h-full overflow-hidden">
|
||||
<div class="absolute inset-x-0 bg-zinc-800/40 backdrop-blur-md z-30 pt-10 pb-4">
|
||||
<div class="flex items-center space-x-2 mx-2">
|
||||
<img :src="type.img" />
|
||||
<div class="font-splatoon1 lg:text-2xl xl:text-3xl text-shadow">
|
||||
{{ $t(type.name) }}
|
||||
</div>
|
||||
<div v-if="type.badge" class="font-splatoon2 text-xs lg:text-sm xl:text-base bg-splatoon-blue rounded px-1 drop-shadow">
|
||||
{{ $t(type.badge) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="text-zinc-300 bg-zinc-800/50 rounded-full p-1 absolute top-3 right-3 z-40" @click="$emit('close')">
|
||||
<span class="sr-only">Close</span>
|
||||
<XMarkIcon class="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<div class="h-full overflow-y-auto pt-24 pb-8">
|
||||
<template v-for="{ title, schedules } in sections" :key="title">
|
||||
<div class="mt-6 mx-2 space-y-2 text-left">
|
||||
<SquidTape class="font-splatoon2 text-sm drop-shadow -rotate-6 -mx-2">
|
||||
<div class="px-2">{{ $t(title) }}</div>
|
||||
</SquidTape>
|
||||
|
||||
<ScheduleRow v-for="schedule in schedules" :key="schedule.startTime" :schedule="schedule" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import ScheduleRow from './ScheduleRow.vue';
|
||||
import SquidTape from './SquidTape.vue';
|
||||
import { useScheduleTypes } from './concerns/scheduleTypes.mjs';
|
||||
import ModalDialog from './ModalDialog.vue';
|
||||
import { XMarkIcon } from '@heroicons/vue/24/outline'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { types } = useScheduleTypes();
|
||||
|
||||
const type = computed(() => types[props.type]);
|
||||
const store = computed(() => type.value.store);
|
||||
|
||||
const sections = computed(() => [
|
||||
{
|
||||
title: 'times.now',
|
||||
schedules: [store.value.activeSchedule],
|
||||
},
|
||||
{
|
||||
title: 'times.next',
|
||||
schedules: store.value.upcomingSchedules?.slice(0, 1),
|
||||
},
|
||||
{
|
||||
title: 'times.future',
|
||||
schedules: store.value.upcomingSchedules?.slice(1),
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.product-mask {
|
||||
mask-image: url('@/assets/img/tag-card-header.svg');
|
||||
mask-position: top;
|
||||
mask-size: 2000px auto;
|
||||
mask-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.bg-tapes {
|
||||
background-image: url('@/assets/img/tapes-transparent.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: contain;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -28,7 +28,12 @@
|
|||
</div>
|
||||
|
||||
<div class="text-sm text-zinc-300 text-shadow">
|
||||
{{ $t('time.in', { time: formatDurationFromNow(props.schedule.startTime) }) }}
|
||||
<template v-if="time.isUpcoming(props.schedule.startTime)">
|
||||
{{ $t('time.in', { time: formatDurationFromNow(props.schedule.startTime) }) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('time.remaining', { time: formatDurationFromNow(props.schedule.endTime) }) }}
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-zinc-300 text-shadow">
|
||||
|
|
@ -61,10 +66,13 @@
|
|||
import StageImage from './StageImage.vue';
|
||||
import RuleIcon from './RuleIcon.vue';
|
||||
import { formatDurationFromNow } from '../common/time';
|
||||
import { useTimeStore } from '../stores/time.mjs';
|
||||
|
||||
const props = defineProps({
|
||||
schedule: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const time = useTimeStore();
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user