Add a dialog for showing upcoming schedules

This commit is contained in:
Matt Isenhower 2022-10-29 16:20:46 -07:00
parent 2e2522c487
commit bc96496c55
4 changed files with 113 additions and 5 deletions

View File

@ -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>

View File

@ -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">&#57445;</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>

View 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>

View File

@ -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>