Compare commits

...

3 Commits

Author SHA1 Message Date
6e4a7f0ac9 update team sorting
All checks were successful
deploy / build-and-deploy (/testvaro, /opt/website-test, website-test) (push) Successful in 20s
deploy / build-and-deploy (/varo, /opt/website, website) (push) Successful in 23s
2025-06-23 21:12:00 +02:00
55f5f25e5a show death message on dead user hover 2025-06-23 20:27:49 +02:00
03ee87d7cf fix bit badge value not updating 2025-06-23 20:02:46 +02:00
5 changed files with 37 additions and 43 deletions

View File

@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import Skeleton from '@assets/img/steve.png';
import type { GetDeathsRes } from '@db/schema/death.ts'; import type { GetDeathsRes } from '@db/schema/death.ts';
import { type ActionReturnType, actions } from 'astro:actions'; import { type ActionReturnType, actions } from 'astro:actions';
@ -13,20 +12,24 @@
const entries = teams.map((team) => ({ const entries = teams.map((team) => ({
...team, ...team,
memberOne: Object.assign(team.memberOne, { memberOne: Object.assign(team.memberOne, {
dead: team.memberOne.id != null ? deaths.findIndex((d) => d.deadUserId === team.memberOne.id) !== -1 : null deathMessage: deaths.find((d) => d.deadUserId === team.memberOne.id)?.message ?? null
}), }),
memberTwo: Object.assign(team.memberTwo, { memberTwo: Object.assign(team.memberTwo, {
dead: team.memberTwo.id != null ? deaths.findIndex((d) => d.deadUserId === team.memberTwo.id) !== -1 : null deathMessage: deaths.find((d) => d.deadUserId === team.memberTwo.id)?.message ?? null
}), }),
kills: deaths.filter((d) => d.killerUserId === team.memberOne.id || d.killerUserId === team.memberTwo.id).length kills: deaths.filter((d) => d.killerUserId === team.memberOne.id || d.killerUserId === team.memberTwo.id).length
})); }));
entries.sort((a, b) => { entries.sort((a, b) => {
const aAllowed = !!a.memberOne.id && !!a.memberTwo.id && !(a.memberOne.dead && a.memberTwo.dead); const aBothSignedUp = a.memberOne.id != null && a.memberTwo.id != null;
const bAllowed = !!b.memberOne.id && !!b.memberTwo.id && !(b.memberOne.dead && b.memberTwo.dead); const aBothDeathMessage = a.memberOne.deathMessage != null && a.memberTwo.deathMessage != null;
if (!aAllowed && !bAllowed) {
return 0; const bBothSignedUp = b.memberOne.id != null && b.memberTwo.id != null;
} else if (!aAllowed || !bAllowed) { const bBothDeathMessage = b.memberOne.deathMessage != null && b.memberTwo.deathMessage != null;
return (bAllowed as unknown as number) - (aAllowed as unknown as number);
if (!aBothSignedUp || !bBothSignedUp) {
return Number(bBothSignedUp) - Number(aBothSignedUp);
} else if (aBothDeathMessage && !bBothDeathMessage || !aBothDeathMessage && bBothDeathMessage) {
return Number(aBothDeathMessage) - Number(bBothDeathMessage);
} }
return b.kills - a.kills; return b.kills - a.kills;
@ -51,7 +54,7 @@
<div class="rounded-sm min-w-3 w-3 min-h-3 h-3" style="background-color: {team.color}"></div> <div class="rounded-sm min-w-3 w-3 min-h-3 h-3" style="background-color: {team.color}"></div>
<h3 <h3
class="text-xs sm:text-xl break-all" class="text-xs sm:text-xl break-all"
class:line-through={team.memberOne.dead && team.memberTwo.dead} class:line-through={team.memberOne.deathMessage !== null && team.memberTwo.deathMessage !== null}
class:text-red-200={!team.memberOne} class:text-red-200={!team.memberOne}
> >
{team.name} {team.name}
@ -62,33 +65,25 @@
{/if} {/if}
</td> </td>
<td class="max-w-9 overflow-ellipsis"> <td class="max-w-9 overflow-ellipsis">
<div class="flex items-center gap-x-2"> <div class="flex items-center gap-x-2 w-max tooltip" data-tip={team.memberOne.deathMessage}>
{#if team.memberOne.id != null} {#if team.memberOne.id != null}
<img <img class="h-4 pixelated" src="https://mc-heads.net/head/{team.memberOne.username}/8" alt="head" />
class="h-4 pixelated"
src={team.memberOne.dead ? Skeleton.src : `https://mc-heads.net/head/${team.memberOne.username}/8`}
alt="head"
/>
{/if} {/if}
<span <span
class="text-xs sm:text-md break-all" class="text-xs sm:text-md break-all"
class:line-through={team.memberOne.dead} class:line-through={team.memberOne.deathMessage !== null}
class:text-gray-500={team.memberOne.id == null}>{team.memberOne.username}</span class:text-gray-500={team.memberOne.id == null}>{team.memberOne.username}</span
> >
</div> </div>
</td> </td>
<td> <td>
<div class="flex items-center gap-x-2"> <div class="flex items-center gap-x-2 w-max tooltip" data-tip={team.memberTwo.deathMessage}>
{#if team.memberTwo.id != null} {#if team.memberTwo.id != null}
<img <img class="h-4 pixelated" src="https://mc-heads.net/head/{team.memberTwo.username}/8" alt="head" />
class="h-4 pixelated"
src={team.memberTwo.dead ? Skeleton.src : `https://mc-heads.net/head/${team.memberTwo.username}/8`}
alt="head"
/>
{/if} {/if}
<span <span
class="text-xs sm:text-md break-all" class="text-xs sm:text-md break-all"
class:line-through={team.memberTwo.dead} class:line-through={team.memberTwo.deathMessage !== null}
class:text-gray-500={team.memberTwo.id == null}>{team.memberTwo.username}</span class:text-gray-500={team.memberTwo.id == null}>{team.memberTwo.username}</span
> >
</div> </div>

View File

@ -9,20 +9,17 @@
// inputs // inputs
let { available, value = $bindable(), readonly }: Props = $props(); let { available, value = $bindable(), readonly }: Props = $props();
// idk why, but this is needed to trigger loop reactivity
let reactiveValue = $derived(value);
// callbacks // callbacks
function onOptionSelect(e: Event) { function onOptionSelect(e: Event) {
const selected = Number((e.target as HTMLSelectElement).value); const selected = Number((e.target as HTMLSelectElement).value);
reactiveValue |= selected; value |= selected;
(e.target as HTMLSelectElement).value = '-'; (e.target as HTMLSelectElement).value = '-';
} }
function onBadgeRemove(flag: number) { function onBadgeRemove(flag: number) {
reactiveValue &= ~flag; value &= ~flag;
} }
</script> </script>
@ -31,20 +28,22 @@
<select class="select select-xs w-min" onchange={onOptionSelect}> <select class="select select-xs w-min" onchange={onOptionSelect}>
<option selected hidden>-</option> <option selected hidden>-</option>
{#each Object.entries(available) as [flag, badge] (flag)} {#each Object.entries(available) as [flag, badge] (flag)}
<option value={flag} hidden={(reactiveValue & Number(flag)) !== 0}>{badge}</option> <option value={flag} hidden={(value & Number(flag)) !== 0}>{badge}</option>
{/each} {/each}
</select> </select>
{/if} {/if}
<div class="flex flow flex-wrap gap-2"> <div class="flex flow flex-wrap gap-2">
{#each Object.entries(available) as [flag, badge] (flag)} {#key value}
{#if (reactiveValue & Number(flag)) !== 0} {#each Object.entries(available) as [flag, badge] (flag)}
<div class="badge badge-outline gap-1"> {#if (value & Number(flag)) !== 0}
{#if !readonly} <div class="badge badge-outline gap-1">
<button class="cursor-pointer" type="button" onclick={() => onBadgeRemove(Number(flag))}>✕</button> {#if !readonly}
{/if} <button class="cursor-pointer" type="button" onclick={() => onBadgeRemove(Number(flag))}>✕</button>
<span>{badge}</span> {/if}
</div> <span>{badge}</span>
{/if} </div>
{/each} {/if}
{/each}
{/key}
</div> </div>
</div> </div>

View File

@ -6,7 +6,7 @@ import { Session } from '@util/session.ts';
import { Permissions } from '@util/permissions.ts'; import { Permissions } from '@util/permissions.ts';
import { BASE_PATH } from 'astro:env/server'; import { BASE_PATH } from 'astro:env/server';
const session = Session.sessionFromCookies(Astro.cookies, Permissions.Admin); const session = Session.sessionFromCookies(Astro.cookies, Permissions.Users);
if (!session) return Astro.redirect(`${BASE_PATH}/admin`); if (!session) return Astro.redirect(`${BASE_PATH}/admin`);
--- ---

View File

@ -6,7 +6,7 @@ import { Session } from '@util/session.ts';
import { Permissions } from '@util/permissions.ts'; import { Permissions } from '@util/permissions.ts';
import { BASE_PATH } from 'astro:env/server'; import { BASE_PATH } from 'astro:env/server';
const session = Session.sessionFromCookies(Astro.cookies, Permissions.Admin); const session = Session.sessionFromCookies(Astro.cookies, Permissions.Users);
if (!session) return Astro.redirect(`${BASE_PATH}/admin`); if (!session) return Astro.redirect(`${BASE_PATH}/admin`);
--- ---

View File

@ -6,7 +6,7 @@ import { Session } from '@util/session.ts';
import { Permissions } from '@util/permissions.ts'; import { Permissions } from '@util/permissions.ts';
import { BASE_PATH } from 'astro:env/server'; import { BASE_PATH } from 'astro:env/server';
const session = Session.sessionFromCookies(Astro.cookies, Permissions.Admin); const session = Session.sessionFromCookies(Astro.cookies, Permissions.Users);
if (!session) return Astro.redirect(`${BASE_PATH}/admin`); if (!session) return Astro.redirect(`${BASE_PATH}/admin`);
--- ---