portfolio_site/src/routes/vinge/pakubiiti/+page.svelte
Mihkel Martin Kasterpalu a3687ac56b Fix case, where pakubiiti recieved only 2 albums from the server
Use a while loop instead of the previous for loop
Cap the amount of retries to not create infinite loops
Show an error message on the client when this cap is reached without
getting the required amount of albums
2025-02-10 12:42:40 +02:00

146 lines
4.5 KiB
Svelte

<script lang="ts">
import { Separator } from '$lib/components/ui/separator/index.js';
import LoaderCircle from 'lucide-svelte/icons/loader-circle';
import { Button } from '$lib/components/ui/button/index.js';
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
import { Skeleton } from '$lib/components/ui/skeleton/index.js';
import DndGroup from '$lib/components/DNDGroup.svelte';
import type { PageData } from './$types';
import { enhance } from '$app/forms';
import type { AlbumData } from '$lib/types';
import { fade } from 'svelte/transition';
import { expoIn, expoOut } from 'svelte/easing';
import { getAlbumClientState } from '$lib/client/AlbumClientState.svelte';
let { data }: { data: PageData; form: FormData } = $props();
let loading = $state(false);
const clientState = getAlbumClientState();
</script>
{#snippet footer(loading: boolean)}
<footer class="mt-8 flex items-center justify-evenly">
<p class="font-title text-lg font-semibold">Skoor: {data.stage}</p>
{#if loading}
<Button disabled class="min-w-[4.4rem]">
<LoaderCircle class="animate-spin" />
</Button>
{:else}
<Button type="submit" class="min-w-[4.4rem]">Saada</Button>
{/if}
<p class="font-title text-lg font-semibold">Parim: {data.highscore}</p>
</footer>
{/snippet}
{#snippet playArea(albums: AlbumData | undefined, placeholder = false)}
{#if placeholder}
{#each { length: 3 } as _, i}
<section
class="grid grid-cols-3 gap-2 rounded-xl p-2 px-3 sm:gap-6 md:gap-8 lg:gap-12 xl:gap-14"
>
{#each { length: 3 }}
{#if i < 2}
<Skeleton class="h-[5rem] w-full rounded-xl border border-primary/5" />
{:else}
<Skeleton class="aspect-square h-auto max-w-full rounded-xl object-cover" />
{/if}
{/each}
</section>
{#if i < 2}
<Separator />
{/if}
{/each}
{:else if albums}
<DndGroup items={albums.names} type="names"></DndGroup>
<Separator />
<DndGroup items={albums.artists} type="artists"></DndGroup>
<Separator />
<DndGroup items={albums.images} image type="images"></DndGroup>
{/if}
{/snippet}
<AlertDialog.Root open={data.playing === false}>
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title>
{#if data?.highscore && data?.stage && data.highscore === data.stage}
Uus parim tulemus!
{:else}
Seekord ei vedanud
{/if}
</AlertDialog.Title>
<AlertDialog.Description>
{#if data.stage === 0}
Põrusid esimesel katsel.
{:else}
Vastasid õigesti <strong>{data.stage} korda.</strong>
{/if}
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<form action="?/restart" method="POST" use:enhance>
<AlertDialog.Action type="submit">Uuesti</AlertDialog.Action>
</form>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>
<header class="mb-16 flex flex-col items-center text-center font-title">
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Paku biiti</h1>
<p class="text-xl font-semibold leading-7 text-muted-foreground">
Lohista kokku õiged albumi <span class="text-red-600 dark:text-red-400">nimed</span>,
<span class="text-purple-600 dark:text-purple-400">artistid</span> ja
<span class="text-blue-600 dark:text-blue-400">pildid</span>.
</p>
</header>
<main class="w-full max-w-4xl">
<form
action="?/submit"
method="POST"
use:enhance
class="grid w-full transition-all {loading || data?.playing === false ? 'grayscale' : ''}"
>
{#if data?.streamed?.albums}
{#await data.streamed.albums}
<div
class="grid w-full gap-4"
in:fade={{ duration: 150, easing: expoIn }}
out:fade={{ duration: 150, easing: expoOut }}
>
{@render playArea(undefined, true)}
</div>
{@render footer(true)}
{:then albums}
{#if albums}
<div class="grid w-full gap-4" in:fade={{ duration: 150, delay: 150, easing: expoOut }}>
{@render playArea(albums as AlbumData)}
</div>
{@render footer(false)}
{:else}
<p class="mx-auto mt-16 max-w-prose text-center text-lg text-red-500">
<strong>Serveris tekkis mingi error.</strong>
<br />No clue miks see katki on, sorry.
</p>
<p class="mx-auto mt-6 max-w-prose text-center text-lg text-red-500">
Proovi uuesti või kirjuta mulle.
</p>
{/if}
{/await}
{:else}
<div class="grid w-full gap-4" out:fade={{ duration: 150, easing: expoOut }}>
{@render playArea(clientState.albums)}
</div>
{@render footer(false)}
{/if}
</form>
</main>
<style>
form > div {
grid-area: 1/1;
}
form > footer {
grid-area: 2/1;
}
</style>