Add end showcase
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
count: number | string;
|
||||
title: string;
|
||||
icon: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="card">
|
||||
<h3>{{ Number(count).toLocaleString('de') }}</h3>
|
||||
<VaIcon :name="icon" size="10rem" />
|
||||
<p>{{ title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
@apply m-4 grid grid-cols-2 items-center justify-items-center gap-8 rounded-lg p-4 text-3xl shadow-lg;
|
||||
}
|
||||
|
||||
.card > *:nth-child(1) {
|
||||
@apply col-span-2 mt-auto text-9xl font-bold;
|
||||
}
|
||||
.card > *:nth-child(3) {
|
||||
@apply mr-auto text-left text-6xl;
|
||||
}
|
||||
</style>
|
||||
@@ -53,6 +53,28 @@
|
||||
"no_hunt_joined": "Noch keinem Hunt beigetreten!",
|
||||
"open_to_join": "Bereit zum Beitreten:",
|
||||
"start": "Start: {start}"
|
||||
},
|
||||
"showcase": {
|
||||
"showcase_for": "Abschluss für",
|
||||
"crew": "Crew",
|
||||
"quests": "Quests",
|
||||
"users": "Spieler",
|
||||
"teams": "Teams",
|
||||
"total_points": "Punkte erzielt",
|
||||
"pictures": "Bilder",
|
||||
"leaderboard": "Rangliste",
|
||||
"third_place": "Dritter Platz",
|
||||
"second_place": "Zweiter Platz",
|
||||
"first_place": "Erster Platz",
|
||||
"points": "Punkte",
|
||||
"answers": "Antworten",
|
||||
"table": {
|
||||
"answers": "Antworten",
|
||||
"place": "Platz",
|
||||
"name": "Name",
|
||||
"description": "Beschreibung",
|
||||
"score": "Punkte"
|
||||
}
|
||||
}
|
||||
},
|
||||
"validation": {
|
||||
|
||||
@@ -53,6 +53,28 @@
|
||||
"no_hunt_joined": "No hunt joined yet!",
|
||||
"open_to_join": "Open to join hunts:",
|
||||
"start": "Start: {start}"
|
||||
},
|
||||
"showcase": {
|
||||
"showcase_for": "Showcase for",
|
||||
"crew": "Crew",
|
||||
"quests": "Quests",
|
||||
"users": "Users",
|
||||
"teams": "Teams",
|
||||
"total_points": "Total points earned",
|
||||
"pictures": "Pictures",
|
||||
"leaderboard": "Leaderboard",
|
||||
"third_place": "Third place",
|
||||
"second_place": "Second place",
|
||||
"first_place": "First place",
|
||||
"points": "Points",
|
||||
"answers": "Answers",
|
||||
"table": {
|
||||
"answers": "Answers",
|
||||
"place": "Place",
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
"score": "Score"
|
||||
}
|
||||
}
|
||||
},
|
||||
"validation": {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<Suspense>
|
||||
<slot />
|
||||
</Suspense>
|
||||
</template>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user