|  | 
|  | 1 | +<script lang="ts" module> | 
|  | 2 | +	const borderColors: Record<string, string> = { | 
|  | 3 | +		Cactus: 'border-cactus', | 
|  | 4 | +		Carrot: 'border-carrot', | 
|  | 5 | +		'Cocoa Beans': 'border-cocoa', | 
|  | 6 | +		Melon: 'border-melon', | 
|  | 7 | +		Mushroom: 'border-mushroom', | 
|  | 8 | +		'Nether Wart': 'border-netherwart', | 
|  | 9 | +		Potato: 'border-potato', | 
|  | 10 | +		Pumpkin: 'border-pumpkin', | 
|  | 11 | +		'Sugar Cane': 'border-sugarcane', | 
|  | 12 | +		Wheat: 'border-wheat', | 
|  | 13 | +	}; | 
|  | 14 | +
 | 
|  | 15 | +	const ghostColors: Record<string, string> = { | 
|  | 16 | +		Cactus: 'border-cactus/50', | 
|  | 17 | +		Carrot: 'border-carrot/50', | 
|  | 18 | +		'Cocoa Beans': 'border-cocoa/50', | 
|  | 19 | +		Melon: 'border-melon/50', | 
|  | 20 | +		Mushroom: 'border-mushroom/50', | 
|  | 21 | +		'Nether Wart': 'border-netherwart/50', | 
|  | 22 | +		Potato: 'border-potato/50', | 
|  | 23 | +		Pumpkin: 'border-pumpkin/50', | 
|  | 24 | +		'Sugar Cane': 'border-sugarcane/50', | 
|  | 25 | +		Wheat: 'border-wheat/50', | 
|  | 26 | +	}; | 
|  | 27 | +</script> | 
|  | 28 | + | 
| 1 | 29 | <script lang="ts"> | 
| 2 | 30 | 	import type { ContestParticipationDto } from '$lib/api'; | 
| 3 | 31 | 	import { getReadableSkyblockDate } from '$lib/format'; | 
| 4 | 32 | 	import { cn } from '$lib/utils'; | 
|  | 33 | +	import Ghost from '@lucide/svelte/icons/ghost'; | 
| 5 | 34 | 
 | 
| 6 | 35 | 	interface Props { | 
| 7 | 36 | 		contest: ContestParticipationDto; | 
|  | 
| 15 | 44 | 
 | 
| 16 | 45 | 	let cropName = $derived(crop ?? 'Not Found'); | 
| 17 | 46 | 	let ranking = $derived((position ?? 0) > -1); | 
|  | 47 | +	let ghost = $derived(medal === 'ghost'); | 
|  | 48 | +	let borderColor = $derived( | 
|  | 49 | +		(ghost ? ghostColors[crop ?? 'Wheat'] : borderColors[crop ?? 'Wheat']) || 'var(--color-border)' | 
|  | 50 | +	); | 
| 18 | 51 | </script> | 
| 19 | 52 | 
 | 
| 20 | 53 | <a | 
| 21 | 54 | 	href="/contest/{timestamp}" | 
| 22 | 55 | 	data-sveltekit-preload-data="off" | 
| 23 | 56 | 	class={cn( | 
| 24 |  | -		`bg-card hover:bg-muted flex min-w-52 flex-col gap-1 rounded-md border-l-4 p-2 hover:shadow-lg ${crop?.replace( | 
| 25 |  | -			' ', | 
| 26 |  | -			'' | 
| 27 |  | -		)}`, | 
|  | 57 | +		`bg-card hover:bg-muted flex min-w-52 flex-col gap-1 rounded-md border-l-4 p-2 hover:shadow-lg ${borderColor}`, | 
| 28 | 58 | 		classes | 
| 29 | 59 | 	)} | 
| 30 | 60 | > | 
| 31 | 61 | 	<p class="text-sm first-letter:uppercase"> | 
| 32 | 62 | 		<span class="bg-card rounded-md p-0.5 px-1.5">{cropName}</span> | 
| 33 |  | -		<span class="text-sm font-semibold">{ranking ? `#${(position ?? -2) + 1}` : 'Unclaimed'}</span> | 
| 34 |  | -		<span class="text-xs">{ranking ? `/ ${participants}` : ''}</span> | 
|  | 63 | +		{#if ghost} | 
|  | 64 | +			<span class="text-sm font-semibold">Not Claimable</span> | 
|  | 65 | +		{:else} | 
|  | 66 | +			<span class="text-sm font-semibold">{ranking ? `#${(position ?? -2) + 1}` : 'Unclaimed'}</span> | 
|  | 67 | +			<span class="text-xs">{ranking ? `/ ${participants}` : ''}</span> | 
|  | 68 | +		{/if} | 
| 35 | 69 | 	</p> | 
| 36 | 70 | 	<p class="flex flex-row items-center gap-1 text-lg font-semibold"> | 
| 37 | 71 | 		{#if medal && medal !== 'none'} | 
| 38 |  | -			<img class="pixelated inline-block h-6 w-6 p-0.5" src="/images/medals/{medal}.webp" alt="Earned Medal" /> | 
|  | 72 | +			{#if ghost} | 
|  | 73 | +				<Ghost class="text-muted-foreground p-0.5" /> | 
|  | 74 | +			{:else} | 
|  | 75 | +				<img | 
|  | 76 | +					class="pixelated inline-block h-6 w-6 p-0.5" | 
|  | 77 | +					src="/images/medals/{medal}.webp" | 
|  | 78 | +					alt="Earned Medal" | 
|  | 79 | +				/> | 
|  | 80 | +			{/if} | 
| 39 | 81 | 		{/if} | 
| 40 | 82 | 		<span>{(collected ?? 0).toLocaleString()}</span> | 
| 41 | 83 | 	</p> | 
| 42 | 84 | 	{#if irlTime} | 
| 43 |  | -		<span class="font-mono text-xs font-semibold"> | 
|  | 85 | +		<span class="font-mono text-xs font-semibold {irlTime ? 'block' : 'hidden'}"> | 
| 44 | 86 | 			{new Date(Number(timestamp ?? 0) * 1000).toLocaleString(undefined, { | 
| 45 | 87 | 				timeStyle: 'short', | 
| 46 | 88 | 				dateStyle: 'medium', | 
| 47 | 89 | 			})} | 
| 48 | 90 | 		</span> | 
| 49 | 91 | 	{:else} | 
| 50 |  | -		<span class="font-mono text-xs font-semibold">{getReadableSkyblockDate(timestamp ?? 0)}</span> | 
|  | 92 | +		<span class="font-mono text-xs font-semibold {irlTime ? 'hidden' : 'block'}" | 
|  | 93 | +			>{getReadableSkyblockDate(timestamp ?? 0)}</span | 
|  | 94 | +		> | 
| 51 | 95 | 	{/if} | 
| 52 | 96 | </a> | 
| 53 |  | - | 
| 54 |  | -<style lang="postcss"> | 
| 55 |  | -	.Cactus { | 
| 56 |  | -		border-color: var(--color-cactus); | 
| 57 |  | -	} | 
| 58 |  | -
 | 
| 59 |  | -	.Carrot { | 
| 60 |  | -		border-color: var(--color-carrot); | 
| 61 |  | -	} | 
| 62 |  | -
 | 
| 63 |  | -	.CocoaBeans { | 
| 64 |  | -		border-color: var(--color-cocoa); | 
| 65 |  | -	} | 
| 66 |  | -
 | 
| 67 |  | -	.Melon { | 
| 68 |  | -		border-color: var(--color-melon); | 
| 69 |  | -	} | 
| 70 |  | -
 | 
| 71 |  | -	.Mushroom { | 
| 72 |  | -		border-color: var(--color-mushroom); | 
| 73 |  | -	} | 
| 74 |  | -
 | 
| 75 |  | -	.NetherWart { | 
| 76 |  | -		border-color: var(--color-netherwart); | 
| 77 |  | -	} | 
| 78 |  | -
 | 
| 79 |  | -	.Potato { | 
| 80 |  | -		border-color: var(--color-potato); | 
| 81 |  | -	} | 
| 82 |  | -
 | 
| 83 |  | -	.Pumpkin { | 
| 84 |  | -		border-color: var(--color-pumpkin); | 
| 85 |  | -	} | 
| 86 |  | -
 | 
| 87 |  | -	.SugarCane { | 
| 88 |  | -		border-color: var(--color-sugarcane); | 
| 89 |  | -	} | 
| 90 |  | -
 | 
| 91 |  | -	.Wheat { | 
| 92 |  | -		border-color: var(--color-wheat); | 
| 93 |  | -	} | 
| 94 |  | -</style> | 
|  | 
0 commit comments