Add end showcase

This commit is contained in:
2025-08-09 19:14:21 +02:00
parent 4189c95d38
commit dc3c21f885
7 changed files with 547 additions and 1 deletions
+288
View File
@@ -0,0 +1,288 @@
<script setup lang="ts">
import type { DataTableColumnSource } from 'vuestic-ui';
import NumberCard from '~/components/showcase/NumberCard.vue';
definePageMeta({
// TODO: re-enable perms
// middleware: ['admin'],
layout: 'full'
});
const app = useNuxtApp();
const { name, id } = app.$slugData.huntSlug!;
const { data } = await useFetch(`/api/admin/hunt/${id}/showcase`);
const { toggle, isFullscreen, isSupported } = useFullscreen();
const leaderboardColumns: DataTableColumnSource[] = [
'place',
'name',
'description',
{
key: 'score',
displayFormatFn: (data: number) => Number(data).toLocaleString('de')
},
'answers'
];
const columns = leaderboardColumns.map((c) =>
typeof c === 'string' ? c : c.key
);
// TODO: colors
</script>
<template>
<div
v-if="isSupported"
class="fixed left-2 top-2 opacity-25 transition-opacity hover:opacity-100"
>
<VaButton
round
border-color="primary"
color="onPrimary"
:icon="isFullscreen ? 'fullscreen_exit' : 'fullscreen'"
@click="toggle"
/>
</div>
<article
class="h-dvh w-full snap-y snap-mandatory overflow-y-scroll scroll-smooth"
v-if="data"
>
<section id="title">
<div
class="flex flex-col items-center justify-center gap-8 bg-green-300 text-center"
>
<h1 class="text-7xl">{{ $t('page.showcase.showcase_for') }}</h1>
<h1 class="text-9xl font-bold">{{ data.name || name }}</h1>
<p v-if="data.start || data.end" class="flex flex-row gap-4 text-4xl">
<span v-if="data.start">{{
$d(data.start, {
dateStyle: 'medium',
timeStyle: 'medium'
})
}}</span
><span v-if="data.start && data.end"> </span
><span v-if="data.end">{{
$d(data.end, {
dateStyle: 'medium',
timeStyle: 'medium'
})
}}</span>
</p>
</div>
</section>
<section id="numbers">
<div class="grid grid-cols-3 gap-4 bg-red-100 p-4">
<NumberCard
:title="$t('page.showcase.crew')"
:count="data._count.members + 1"
icon="support_agent"
/>
<NumberCard
:title="$t('page.showcase.quests')"
:count="data._count.quests"
icon="home"
/>
<NumberCard
:title="$t('page.showcase.users')"
:count="data.userCount"
icon="person"
/>
<NumberCard
:title="$t('page.showcase.teams')"
:count="data._count.teams"
icon="groups"
/>
<NumberCard
:title="$t('page.showcase.total_points')"
:count="data.totalScore"
icon="star"
/>
<NumberCard
:title="$t('page.showcase.pictures')"
:count="data.pictureCount"
icon="photo"
/>
</div>
</section>
<section v-for="quest in data.quests" :key="quest.id" :id="sluggy(quest)">
<div class="flex flex-col gap-4 bg-yellow-100 p-4">
<div class="my-8 flex w-full flex-row justify-around">
<h3 class="text-3xl">{{ quest.title }}</h3>
<p class="text-xl font-bold">{{ quest.question }}</p>
<p v-if="quest.textSolution" class="text-3xl">
{{ quest.textSolution }}
</p>
</div>
<ClientOnly>
<VaCarousel
stateful
:items="quest.answers"
arrows
indicators
lazy
color="onPrimary"
indicator-trigger="hover"
class="w-full flex-grow"
style="--va-carousel-background: none"
>
<template #default="{ item }"
><VaImage :src="item.picture.url" fit="contain" lazy />
<p
class="absolute top-2 mx-auto rounded bg-gray-200/75 px-2 py-1 text-center text-xl"
>
{{ item.team.name }} "{{ item.text }}"
{{ item.picture.creator.name }}
</p></template
></VaCarousel
></ClientOnly
>
</div>
</section>
<section id="leaderboard" v-if="data.leaderboard.length > 3">
<div class="flex flex-col gap-4 bg-indigo-100">
<h1 class="mt-8 text-center text-6xl">
{{ $t('page.showcase.leaderboard') }}
</h1>
<VaDataTable
class="h-full text-2xl"
virtual-scroller
striped
sticky-header
:items="data.leaderboard.slice(3)"
:columns="leaderboardColumns"
>
<template v-for="col in columns" #[col]
><span>{{ $t(`page.showcase.table.${col}`) }}</span></template
>
<template #cell(place)="{ rowIndex }">
<strong>{{ rowIndex + 4 }}</strong>
</template>
</VaDataTable>
</div>
</section>
<section id="leaderboard-third" v-if="data.leaderboard[2]">
<div class="place bg-[#AD8A56]">
<div class="place-left">
<VaIcon name="looks_3" size="10rem" />
<h2>{{ $t('page.showcase.third_place') }}</h2>
</div>
<div class="place-right">
<h3>{{ data.leaderboard[2].name }}</h3>
<p>{{ data.leaderboard[2].description }}</p>
<NumberCard
:title="$t('page.showcase.points')"
:count="data.leaderboard[2].score"
icon="star"
/>
<NumberCard
:title="$t('page.showcase.answers')"
:count="data.leaderboard[2].answers"
icon="question_mark"
/>
</div>
</div>
</section>
<section id="leaderboard-second" v-if="data.leaderboard[1]">
<div class="place bg-[#B4B4B4]">
<div class="place-left">
<VaIcon name="looks_two" size="10rem" />
<h2>{{ $t('page.showcase.second_place') }}</h2>
</div>
<div class="place-right">
<h3>{{ data.leaderboard[1].name }}</h3>
<p>{{ data.leaderboard[1].description }}</p>
<NumberCard
:title="$t('page.showcase.points')"
:count="data.leaderboard[1].score"
icon="star"
/>
<NumberCard
:title="$t('page.showcase.answers')"
:count="data.leaderboard[1].answers"
icon="question_mark"
/>
</div>
</div>
</section>
<section id="leaderboard-winner-teaser" v-if="data.leaderboard[0]">
<div class="place bg-[#C9B037]">
<div class="place-left">
<VaIcon name="looks_one" size="10rem" />
<h2>{{ $t('page.showcase.first_place') }}</h2>
</div>
<div class="place-right">
<h3 class="bg-white text-white">{{ data.leaderboard[0].name }}</h3>
<p class="bg-white text-white">
{{ data.leaderboard[0].description }}
</p>
<NumberCard
:title="$t('page.showcase.points')"
:count="data.leaderboard[0].score"
icon="star"
/>
<NumberCard
:title="$t('page.showcase.answers')"
:count="data.leaderboard[0].answers"
icon="question_mark"
/>
</div>
</div>
</section>
<section id="leaderboard-winner" v-if="data.leaderboard[0]">
<div class="place bg-[#C9B037]">
<div class="place-left">
<VaIcon name="workspace_premium" size="10rem" />
<h2>{{ $t('page.showcase.first_place') }}</h2>
</div>
<div class="place-right">
<h3>{{ data.leaderboard[0].name }}</h3>
<p>{{ data.leaderboard[0].description }}</p>
<NumberCard
:title="$t('page.showcase.points')"
:count="data.leaderboard[0].score"
icon="star"
/>
<NumberCard
:title="$t('page.showcase.answers')"
:count="data.leaderboard[0].answers"
icon="question_mark"
/>
</div>
</div>
</section>
</article>
<article v-else>pending...</article>
</template>
<style scoped>
section {
@apply mt-6 h-dvh snap-center p-6 first:mt-0;
}
section > div {
@apply h-full w-full rounded-lg;
}
.place {
@apply grid h-full w-full grid-cols-4 items-center p-4;
}
.place-left {
@apply flex h-full flex-col justify-center gap-4 text-center text-white;
}
.place-right {
@apply col-span-3 grid h-full grid-cols-2 gap-4 text-center text-white;
}
.place-right h3 {
@apply mt-auto text-6xl font-bold;
}
.place-right p {
@apply mt-auto text-3xl font-bold;
}
.place h2 {
@apply text-5xl font-bold;
}
</style>