hackathon/web_src/routes/dashboard/leaderboard@dashboard.svelte

130 lines
3.4 KiB
Svelte

<script lang="ts" context="module">
export const prerender = false;
</script>
<script lang="ts">
import { goto } from '$app/navigation';
import { getContext, onMount } from 'svelte';
import { type LeaderboardResponse, QuestService } from '$lib/pb/all.pb';
import { withToken } from '$lib/pb/pbutil';
import Countdown from '$lib/components/Countdown.svelte';
import { auth } from '$lib/stores';
import ErrorModal from '$lib/components/ErrorModal.svelte';
const { open } = getContext('simple-modal');
let ranking: LeaderboardResponse = null;
let queried = false;
onMount(() => {
auth.subscribe((data) => {
if (queried) return;
if (!data.loggedIn()) return;
queried = true;
QuestService.Leaderboard({}, withToken(data.token))
.then((lr) => {
ranking = lr;
})
.catch((err) => {
open(ErrorModal, {
title: 'Could not fetch',
reason: err.message || 'Something went wrong',
btn: {
title: 'Go to dashboard',
do: () => {
goto('/dashboard');
}
}
});
});
});
});
</script>
<svelte:head>
<title>Questions | CodeQuest</title>
</svelte:head>
<div class="relative flex min-h-[calc(100vh-164px)] pb-8 mx-2">
<main class="container mx-auto pt-4 flex flex-col gap-4">
<div class="grid grid-cols-1 gap-4">
<div class="box h-24 border-2 border-sky-600 hover:bg-sky-50">
<span class="font-bold text-4xl text-sky-600">Leaderboard</span>
</div>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-3 xl:grid-cols-5">
<a class="box h-12 hover:bg-neutral-200 border-neutral-300" href="/dashboard">
<span class="txt text-neutral-600 flex items-center gap-1">
<!-- prettier-ignore -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Dashboard
</span>
</a>
<div class="box h-12 border-indigo-600 col-span-1 md:col-end-4 xl:col-end-6">
<span class="txt text-indigo-600">
{#if !$auth.info}
&nbsp;
{:else if $auth.info?.active}
<Countdown end={String($auth.info.endTime)} />
{:else if new Date(String($auth.info.endTime)) < new Date()}
Contest Over
{:else}
Starting Soon
{/if}
</span>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
{#if ranking}
{#each ranking.leaderboard as item, i}
<div class="ranking h-24 xl:col-span-2">
<div class="inline-flex items-end gap-2">
<span class="txt text-4xl">{i + 1}.</span>
<span class="txt text-2xl">{item.username}</span>
</div>
<div>
<span class="txt text-2xl">{item.points} points</span>
</div>
</div>
{/each}
{/if}
</div>
</main>
</div>
<style lang="postcss">
.box {
@apply flex items-center justify-center w-full rounded-md shadow-md border;
@apply transition;
}
.ranking {
@apply flex items-center justify-between w-full rounded-md shadow-md border;
@apply px-8;
@apply transition;
@apply text-gray-400 border-gray-400 hover:bg-sky-50;
}
.ranking:nth-child(1) {
@apply text-yellow-500 border-yellow-500 hover:bg-amber-50;
}
.ranking:nth-child(2) {
@apply text-zinc-700 border-zinc-700 hover:bg-zinc-50;
}
.ranking:nth-child(3) {
@apply text-amber-600 border-amber-600 hover:bg-amber-50;
}
.txt {
@apply font-bold tracking-wider uppercase;
}
</style>