feat: Implement Flashes Tab with real flash effectiveness data
Replaces placeholder with fully functional flash analysis tab showing: - Summary stats: total enemies blinded, flash assists, blind time - Team comparison cards (T vs CT) - Flash effectiveness leaderboard (sortable DataTable) - Per-team detailed flash stats tables - Average blind duration per flash calculation - Self-flash and team-flash tracking Data includes: - Enemies blinded count - Average blind duration (in seconds) - Flash assists (kills while enemy blinded) - Teammates flashed (accidents) - Self-flashed count Completes Phase 5.7 from TODO.md (Flash Tab implementation). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,32 +1,198 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Zap, Eye } from 'lucide-svelte';
|
import { Eye, Zap, Users } from 'lucide-svelte';
|
||||||
import Card from '$lib/components/ui/Card.svelte';
|
import Card from '$lib/components/ui/Card.svelte';
|
||||||
import Badge from '$lib/components/ui/Badge.svelte';
|
import DataTable from '$lib/components/data-display/DataTable.svelte';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
|
let { data }: { data: PageData } = $props();
|
||||||
|
const { match } = data;
|
||||||
|
|
||||||
|
// Calculate flash effectiveness for each player
|
||||||
|
const flashStats = (match.players || [])
|
||||||
|
.map((player) => ({
|
||||||
|
name: player.name,
|
||||||
|
team_id: player.team_id,
|
||||||
|
enemies_blinded: player.flash_total_enemy || 0,
|
||||||
|
teammates_blinded: player.flash_total_team || 0,
|
||||||
|
self_blinded: player.flash_total_self || 0,
|
||||||
|
enemy_blind_duration: player.flash_duration_enemy || 0,
|
||||||
|
team_blind_duration: player.flash_duration_team || 0,
|
||||||
|
self_blind_duration: player.flash_duration_self || 0,
|
||||||
|
flash_assists: player.flash_assists || 0,
|
||||||
|
// Calculate average blind duration per flash
|
||||||
|
avg_blind_duration:
|
||||||
|
player.flash_total_enemy && player.flash_total_enemy > 0
|
||||||
|
? ((player.flash_duration_enemy || 0) / player.flash_total_enemy).toFixed(1)
|
||||||
|
: '0.0'
|
||||||
|
}))
|
||||||
|
.sort((a, b) => b.enemies_blinded - a.enemies_blinded);
|
||||||
|
|
||||||
|
// Separate by team
|
||||||
|
const teamAFlashStats = flashStats.filter((p) => p.team_id === 2);
|
||||||
|
const teamBFlashStats = flashStats.filter((p) => p.team_id === 3);
|
||||||
|
|
||||||
|
// Calculate team totals
|
||||||
|
const calcTeamTotals = (players: typeof flashStats) => ({
|
||||||
|
total_enemies_blinded: players.reduce((sum, p) => sum + p.enemies_blinded, 0),
|
||||||
|
total_flash_assists: players.reduce((sum, p) => sum + p.flash_assists, 0),
|
||||||
|
total_enemy_blind_time: players.reduce((sum, p) => sum + p.enemy_blind_duration, 0),
|
||||||
|
avg_per_player: (
|
||||||
|
players.reduce((sum, p) => sum + p.enemies_blinded, 0) / players.length
|
||||||
|
).toFixed(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
const teamATotals = calcTeamTotals(teamAFlashStats);
|
||||||
|
const teamBTotals = calcTeamTotals(teamBFlashStats);
|
||||||
|
|
||||||
|
// Table columns
|
||||||
|
const columns = [
|
||||||
|
{ key: 'name', label: 'Player', sortable: true },
|
||||||
|
{
|
||||||
|
key: 'enemies_blinded',
|
||||||
|
label: 'Enemies Blinded',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'avg_blind_duration',
|
||||||
|
label: 'Avg Duration (s)',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const,
|
||||||
|
formatter: (value: string) => `${value}s`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'flash_assists',
|
||||||
|
label: 'Flash Assists',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'teammates_blinded',
|
||||||
|
label: 'Team Flashed',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'self_blinded',
|
||||||
|
label: 'Self Flashed',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const
|
||||||
|
}
|
||||||
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<Card padding="lg">
|
<!-- Summary Stats -->
|
||||||
<div class="text-center">
|
<div class="grid gap-6 md:grid-cols-3">
|
||||||
<Eye class="mx-auto mb-4 h-16 w-16 text-warning" />
|
|
||||||
<h2 class="mb-2 text-2xl font-bold text-base-content">Flash Analysis</h2>
|
|
||||||
<p class="mb-4 text-base-content/60">
|
|
||||||
Flash effectiveness, enemies blinded, flash assists, and positioning heatmaps.
|
|
||||||
</p>
|
|
||||||
<Badge variant="warning" size="lg">Coming in Future Update</Badge>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<div class="grid gap-6 md:grid-cols-2">
|
|
||||||
<Card padding="lg">
|
<Card padding="lg">
|
||||||
<Zap class="mb-2 h-8 w-8 text-warning" />
|
<Eye class="mb-2 h-8 w-8 text-warning" />
|
||||||
<h3 class="mb-1 text-lg font-semibold">Flash Effectiveness</h3>
|
<div class="text-3xl font-bold text-base-content">
|
||||||
<p class="text-sm text-base-content/60">Enemies blinded and average blind duration</p>
|
{teamATotals.total_enemies_blinded + teamBTotals.total_enemies_blinded}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-base-content/60">Total Enemies Blinded</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card padding="lg">
|
<Card padding="lg">
|
||||||
<Eye class="mb-2 h-8 w-8 text-success" />
|
<Zap class="mb-2 h-8 w-8 text-success" />
|
||||||
<h3 class="mb-1 text-lg font-semibold">Flash Assists</h3>
|
<div class="text-3xl font-bold text-base-content">
|
||||||
<p class="text-sm text-base-content/60">Blinded enemies killed by teammates</p>
|
{teamATotals.total_flash_assists + teamBTotals.total_flash_assists}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-base-content/60">Total Flash Assists</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card padding="lg">
|
||||||
|
<Users class="mb-2 h-8 w-8 text-info" />
|
||||||
|
<div class="text-3xl font-bold text-base-content">
|
||||||
|
{((teamATotals.total_enemy_blind_time + teamBTotals.total_enemy_blind_time) / 1000).toFixed(
|
||||||
|
1
|
||||||
|
)}s
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-base-content/60">Total Enemy Blind Time</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Team Comparison -->
|
||||||
|
<div class="grid gap-6 md:grid-cols-2">
|
||||||
|
<Card padding="lg">
|
||||||
|
<h3 class="mb-4 text-xl font-bold text-terrorist">Terrorists</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Enemies Blinded</span>
|
||||||
|
<span class="font-mono font-bold">{teamATotals.total_enemies_blinded}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Flash Assists</span>
|
||||||
|
<span class="font-mono font-bold">{teamATotals.total_flash_assists}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Avg per Player</span>
|
||||||
|
<span class="font-mono font-bold">{teamATotals.avg_per_player}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card padding="lg">
|
||||||
|
<h3 class="mb-4 text-xl font-bold text-ct">Counter-Terrorists</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Enemies Blinded</span>
|
||||||
|
<span class="font-mono font-bold">{teamBTotals.total_enemies_blinded}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Flash Assists</span>
|
||||||
|
<span class="font-mono font-bold">{teamBTotals.total_flash_assists}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-sm text-base-content/60">Avg per Player</span>
|
||||||
|
<span class="font-mono font-bold">{teamBTotals.avg_per_player}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Flash Effectiveness Leaderboard -->
|
||||||
|
<Card padding="none">
|
||||||
|
<div class="p-6">
|
||||||
|
<h2 class="text-2xl font-bold text-base-content">Flash Effectiveness Leaderboard</h2>
|
||||||
|
<p class="mt-1 text-sm text-base-content/60">
|
||||||
|
Ranked by total enemies blinded during the match
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DataTable data={flashStats} {columns} striped hoverable />
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<!-- Team A Details -->
|
||||||
|
<Card padding="none">
|
||||||
|
<div class="border-b border-base-300 bg-terrorist/5 p-6">
|
||||||
|
<h3 class="text-xl font-bold text-terrorist">Terrorists - Flash Stats</h3>
|
||||||
|
</div>
|
||||||
|
<DataTable data={teamAFlashStats} {columns} striped hoverable />
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<!-- Team B Details -->
|
||||||
|
<Card padding="none">
|
||||||
|
<div class="border-b border-base-300 bg-ct/5 p-6">
|
||||||
|
<h3 class="text-xl font-bold text-ct">Counter-Terrorists - Flash Stats</h3>
|
||||||
|
</div>
|
||||||
|
<DataTable data={teamBFlashStats} {columns} striped hoverable />
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<!-- Info Box -->
|
||||||
|
<Card padding="lg" variant="elevated">
|
||||||
|
<div class="text-sm text-base-content/60">
|
||||||
|
<p class="mb-2 font-semibold">Understanding Flash Stats:</p>
|
||||||
|
<ul class="list-inside list-disc space-y-1">
|
||||||
|
<li><strong>Enemies Blinded:</strong> Total number of enemy players flashed</li>
|
||||||
|
<li>
|
||||||
|
<strong>Avg Duration:</strong> Average time enemies were blinded per flash (in seconds)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Flash Assists:</strong> Enemies killed by teammates while blinded by your flash
|
||||||
|
</li>
|
||||||
|
<li><strong>Team Flashed:</strong> Number of times you accidentally flashed teammates</li>
|
||||||
|
<li><strong>Self Flashed:</strong> Number of times you flashed yourself</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user