Two teams try and fill in any horizontal, vertical, or diagonal line on a bingo board by playing maps on osu! osu.bingo
osu
at microservice 91 lines 2.9 kB view raw
1<script lang="ts"> 2 import { fly } from 'svelte/transition'; 3 import { X } from 'lucide-svelte'; 4 import MapCard from './MapCard.svelte'; 5 import { square as store } from '$lib/stores'; 6 import type { Writable } from 'svelte/store'; 7 import ScoreList from './ScoreList.svelte'; 8 9 export let tiebreaker: string; 10 export let gameStore: Writable<Bingo.Card | null>; 11 12 let square: Bingo.Card.FullSquare | null = null; 13 let sidebar: HTMLDivElement; 14 let transition = false; 15 16 store.subscribe(async (index) => { 17 if (index == null || $gameStore?.squares == null) { 18 square = null; 19 return; 20 } 21 22 square = $gameStore.squares[index]; 23 24 square.scores.sort((a, b) => { 25 if (tiebreaker == 'accuracy') return b.accuracy - a.accuracy; 26 if (tiebreaker == 'combo') return b.max_combo - a.max_combo; 27 if (tiebreaker == 'pp') return (b.pp ?? 0) - (a.pp ?? 0); 28 return b.score - a.score; 29 }); 30 square.scores.sort((a, b) => (b.claimworthy ? 1 : 0) - (a.claimworthy ? 1 : 0)); 31 transition = !transition; 32 }); 33 gameStore.subscribe((value) => { 34 if (!value) return; 35 36 const newSquare = value.squares?.find((x) => x.id == square?.id); 37 if (newSquare) { 38 square = newSquare; 39 40 square.scores.sort((a, b) => { 41 if (tiebreaker == 'accuracy') return b.accuracy - a.accuracy; 42 if (tiebreaker == 'combo') return b.max_combo - a.max_combo; 43 if (tiebreaker == 'pp') return (b.pp ?? 0) - (a.pp ?? 0); 44 return b.score - a.score; 45 }); 46 square.scores.sort((a, b) => (b.claimworthy ? 1 : 0) - (a.claimworthy ? 1 : 0)); 47 } 48 }); 49 const close = () => { 50 $store = null; 51 }; 52</script> 53 54{#if square != null} 55 <div 56 bind:this={sidebar} 57 class="group/sidebar relative size-full overflow-hidden rounded-xl bg-zinc-800 transition" 58 data-claimer={square.claimed_by?.team_name ?? 'UNCLAIMED'} 59 > 60 <div 61 class="absolute top-0 flex h-14 w-full items-center bg-gradient-to-b to-zinc-800 p-2 font-rounded text-xl transition group-data-[claimer=BLUE]/sidebar:from-blue-600 group-data-[claimer=RED]/sidebar:from-amber-600 group-data-[claimer=UNCLAIMED]/sidebar:from-zinc-600" 62 > 63 <button 64 on:click={close} 65 class="flex size-10 items-center justify-center rounded p-1 hover:bg-[rgba(0,0,0,0.5)]" 66 > 67 <X /> 68 </button> 69 Back to team chat 70 </div> 71 72 <!-- This looks stupid, but is necessary for the transition to look the way it does --> 73 {#if transition} 74 <div in:fly={{ x: 100, duration: 300 }} out:fly={{ x: -100, duration: 150 }}> 75 <div class="absolute top-14 w-full"> 76 <MapCard map={square.data} /> 77 </div> 78 79 <ScoreList scores={square.scores} {tiebreaker} /> 80 </div> 81 {:else} 82 <div in:fly={{ x: 100, duration: 300 }} out:fly={{ x: -100, duration: 150 }}> 83 <div class="absolute top-14 w-full"> 84 <MapCard map={square.data} /> 85 </div> 86 87 <ScoreList scores={square.scores} {tiebreaker} /> 88 </div> 89 {/if} 90 </div> 91{/if}