Two teams try and fill in any horizontal, vertical, or diagonal line on a bingo board by playing maps on osu!
osu.bingo
osu
1<script lang="ts">
2 import { cubicInOut } from 'svelte/easing';
3 import { tweened } from 'svelte/motion';
4
5 export let tab = 0;
6 export let duration = 150;
7
8 const bar1 = tweened(0, {
9 duration,
10 easing: cubicInOut
11 });
12 const bar2 = tweened(0, {
13 duration,
14 easing: cubicInOut
15 });
16
17 let data: HTMLElement;
18 let icons: HTMLElement[] = [];
19 let panes: HTMLElement[] = [];
20
21 $: {
22 if (data) {
23 icons = [];
24 panes = [];
25 data.childNodes.forEach((v) => {
26 if ((v as HTMLElement)?.classList?.contains('pane')) panes.push(v as HTMLElement);
27 if ((v as HTMLElement)?.classList?.contains('icon')) icons.push(v as HTMLElement);
28 });
29 }
30
31 switchTabs(tab);
32 }
33
34 const switchTabs = (n: number) => {
35 tab = n;
36
37 const interval = 1 / panes.length;
38 bar1.set(tab * interval);
39 bar2.set((panes.length - (tab + 1)) * interval);
40 };
41</script>
42
43<!-- Used to get the slot data -->
44<div class="hidden" bind:this={data}>
45 <slot />
46</div>
47
48<div class="flex size-full bg-zinc-800">
49 {#if panes[tab]}
50 <div class="size-full">
51 {@html panes[tab].innerHTML}
52 </div>
53 {/if}
54 <div class="space-evenly relative flex h-full w-[50px] flex-col align-middle">
55 {#each icons as icon, i}
56 <button on:click={() => switchTabs(i)} class="z-10 size-full">
57 {@html icon.innerHTML}
58 </button>
59 {/each}
60 <!-- Tab blockers -->
61 <div
62 class="absolute top-0 z-0 w-full rounded-bl-xl bg-zinc-900"
63 style="height: calc(100% * {$bar1})"
64 ></div>
65 <div
66 class="absolute bottom-0 z-0 w-full rounded-tl-xl bg-zinc-900"
67 style="height: calc(100% * {$bar2})"
68 ></div>
69 </div>
70</div>