show kill details on kill number hover
All checks were successful
deploy / build-and-deploy (/testvaro, /opt/website-test, website-test) (push) Successful in 24s
deploy / build-and-deploy (/varo, /opt/website, website) (push) Successful in 14s

This commit is contained in:
2025-06-24 00:00:05 +02:00
parent 6e4a7f0ac9
commit e5f253ebc1
2 changed files with 42 additions and 24 deletions

View File

@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import type { GetDeathsRes } from '@db/schema/death.ts';
import { type ActionReturnType, actions } from 'astro:actions'; import { type ActionReturnType, actions } from 'astro:actions';
import type { db } from '@db/database.ts';
interface Props { interface Props {
teams: Exclude<ActionReturnType<typeof actions.team.teams>['data'], undefined>['teams']; teams: Exclude<ActionReturnType<typeof actions.team.teams>['data'], undefined>['teams'];
deaths: GetDeathsRes; deaths: Awaited<ReturnType<typeof db.getDeaths>>;
} }
const { teams, deaths }: Props = $props(); const { teams, deaths }: Props = $props();
@ -12,27 +12,27 @@
const entries = teams.map((team) => ({ const entries = teams.map((team) => ({
...team, ...team,
memberOne: Object.assign(team.memberOne, { memberOne: Object.assign(team.memberOne, {
deathMessage: deaths.find((d) => d.deadUserId === team.memberOne.id)?.message ?? null dead: deaths.find((d) => d.killed.id === team.memberOne.id) ?? null
}), }),
memberTwo: Object.assign(team.memberTwo, { memberTwo: Object.assign(team.memberTwo, {
deathMessage: deaths.find((d) => d.deadUserId === team.memberTwo.id)?.message ?? null dead: deaths.find((d) => d.killed.id === team.memberTwo.id) ?? null
}), }),
kills: deaths.filter((d) => d.killerUserId === team.memberOne.id || d.killerUserId === team.memberTwo.id).length kills: deaths.filter((d) => d.killer?.id === team.memberOne.id || d.killer?.id === team.memberTwo.id)
})); }));
entries.sort((a, b) => { entries.sort((a, b) => {
const aBothSignedUp = a.memberOne.id != null && a.memberTwo.id != null; const aBothSignedUp = a.memberOne.id != null && a.memberTwo.id != null;
const aBothDeathMessage = a.memberOne.deathMessage != null && a.memberTwo.deathMessage != null; const aBothDead = a.memberOne.dead && a.memberTwo.dead;
const bBothSignedUp = b.memberOne.id != null && b.memberTwo.id != null; const bBothSignedUp = b.memberOne.id != null && b.memberTwo.id != null;
const bBothDeathMessage = b.memberOne.deathMessage != null && b.memberTwo.deathMessage != null; const bBothDead = b.memberOne.dead && b.memberTwo.dead;
if (!aBothSignedUp || !bBothSignedUp) { if (!aBothSignedUp || !bBothSignedUp) {
return Number(bBothSignedUp) - Number(aBothSignedUp); return Number(bBothSignedUp) - Number(aBothSignedUp);
} else if (aBothDeathMessage && !bBothDeathMessage || !aBothDeathMessage && bBothDeathMessage) { } else if ((aBothDead && !bBothDead) || (!aBothDead && bBothDead)) {
return Number(aBothDeathMessage) - Number(bBothDeathMessage); return Number(!!aBothDead) - Number(!!bBothDead);
} }
return b.kills - a.kills; return b.kills.length - a.kills.length;
}); });
</script> </script>
@ -54,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.deathMessage !== null && team.memberTwo.deathMessage !== null} class:line-through={team.memberOne.dead && team.memberTwo.dead}
class:text-red-200={!team.memberOne} class:text-red-200={!team.memberOne}
> >
{team.name} {team.name}
@ -65,34 +65,37 @@
{/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 w-max tooltip" data-tip={team.memberOne.deathMessage}> <div class="flex items-center gap-x-2 w-max tooltip" data-tip={team.memberOne.dead?.message}>
{#if team.memberOne.id != null} {#if team.memberOne.id != null}
<img class="h-4 pixelated" src="https://mc-heads.net/head/{team.memberOne.username}/8" alt="head" /> <img class="h-4 pixelated" 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.deathMessage !== null} class:line-through={team.memberOne.dead}
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 w-max tooltip" data-tip={team.memberTwo.deathMessage}> <div class="flex items-center gap-x-2 w-max tooltip" data-tip={team.memberTwo.dead?.message}>
{#if team.memberTwo.id != null} {#if team.memberTwo.id != null}
<img class="h-4 pixelated" src="https://mc-heads.net/head/{team.memberTwo.username}/8" alt="head" /> <img class="h-4 pixelated" 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.deathMessage !== null} class:line-through={team.memberTwo.dead}
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>
</td> </td>
<td> <td>
<span class="text-xs sm:text-md"> <span class="text-xs sm:text-md tooltip tooltip-right">
{deaths.filter( <span class="tooltip-content text-left space-y-1">
(death) => death.killerUserId === team.memberOne.id || death.killerUserId === team.memberTwo.id {#each team.kills as kill, i (i)}
).length} <p>{kill.killer!.username} 🔪 {kill.killed.username}</p>
{/each}
</span>
{team.kills.length}
</span> </span>
</td> </td>
</tr> </tr>

View File

@ -1,4 +1,4 @@
import { int, mysqlTable, varchar } from 'drizzle-orm/mysql-core'; import { alias, int, mysqlTable, varchar } from 'drizzle-orm/mysql-core';
import type { MySql2Database } from 'drizzle-orm/mysql2'; import type { MySql2Database } from 'drizzle-orm/mysql2';
import { user } from './user.ts'; import { user } from './user.ts';
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
@ -24,7 +24,6 @@ export type GetDeathByUserIdReq = {
}; };
export type GetDeathsReq = {}; export type GetDeathsReq = {};
export type GetDeathsRes = (typeof death.$inferSelect)[];
export async function addDeath(db: Database, values: AddDeathReq) { export async function addDeath(db: Database, values: AddDeathReq) {
await db.insert(death).values(values); await db.insert(death).values(values);
@ -36,7 +35,23 @@ export async function getDeathByUserId(db: Database, values: GetDeathByUserIdReq
}); });
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars export async function getDeaths(db: Database, _values: GetDeathsReq) {
export async function getDeaths(db: Database, values: GetDeathsReq): Promise<GetDeathsReq> { const killed = alias(user, 'killed');
return db.query.death.findMany(); const killer = alias(user, 'killer');
return db
.select({
message: death.message,
killed: {
id: killed.id,
username: killed.username
},
killer: {
id: killer.id,
username: killer.username
}
})
.from(death)
.innerJoin(killed, eq(death.deadUserId, killed.id))
.leftJoin(killer, eq(death.killerUserId, killer.id));
} }