File size: 4,098 Bytes
0f00bbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<script lang="ts">
	import type { Match } from '$lib/types';
	import { prettyMap } from '$lib/utils/format';
	import { mapColorClasses } from '$lib/utils/map-colors';
	import { cn } from '$lib/utils';

	interface Props {
		matches: Match[];
	}
	let { matches }: Props = $props();

	const mapsDist = $derived.by(() => {
		const counts = new Map<string, number>();
		for (const m of matches) counts.set(m.map_name, (counts.get(m.map_name) ?? 0) + 1);
		return Array.from(counts.entries())
			.map(([name, count]) => ({ name, count }))
			.sort((a, b) => b.count - a.count);
	});

	const totalMaps = $derived(mapsDist.reduce((s, m) => s + m.count, 0));
	const maxCount = $derived(Math.max(1, ...mapsDist.map((m) => m.count)));

	// Histogram of rounds-per-match — buckets of 4 rounds.
	const roundsHist = $derived.by(() => {
		const buckets = new Map<string, number>();
		for (const m of matches) {
			const r = m.rounds_played;
			if (!r) continue;
			// pinch into [start, start+3] buckets; e.g. 13-16, 17-20, etc.
			const start = Math.floor((r - 1) / 4) * 4 + 1;
			const key = `${start}-${start + 3}`;
			buckets.set(key, (buckets.get(key) ?? 0) + 1);
		}
		return Array.from(buckets.entries())
			.map(([range, count]) => ({ range, count, sortKey: Number(range.split('-')[0]) }))
			.sort((a, b) => a.sortKey - b.sortKey);
	});
	const roundsMax = $derived(Math.max(1, ...roundsHist.map((b) => b.count)));
</script>

<section class="mx-auto mt-12 max-w-5xl">
	<h2
		class="text-center font-heading text-xs font-semibold tracking-[0.2em] text-muted-foreground uppercase"
	>
		Statistics
	</h2>

	<div class="mt-6 grid gap-4 lg:grid-cols-2">
		<!-- Maps distribution -->
		<div class="rounded-md border bg-card p-4">
			<div class="mb-3 flex items-baseline justify-between gap-2">
				<div>
					<div class="font-heading text-sm font-semibold">Maps distribution</div>
					<p class="text-[11px] text-muted-foreground">
						Maps rendered per CS2 map ({totalMaps} total)
					</p>
				</div>
			</div>
			<div class="space-y-1">
				{#each mapsDist as m (m.name)}
					{@const pct = (m.count / maxCount) * 100}
					{@const sharePct = totalMaps ? (m.count / totalMaps) * 100 : 0}
					<div class="grid grid-cols-[5.5rem_1fr_3.5rem] items-center gap-2 text-xs">
						<span
							class={cn(
								'truncate rounded-sm border px-1.5 py-0.5 text-center text-[10px] font-medium capitalize',
								mapColorClasses(m.name)
							)}
							title={m.name}>{prettyMap(m.name)}</span
						>
						<div class="relative h-3 overflow-hidden rounded-sm bg-muted/40">
							<div
								class={cn('absolute inset-y-0 left-0 rounded-sm border-r', mapColorClasses(m.name))}
								style="width: {pct}%"
							></div>
						</div>
						<span class="text-right font-mono text-muted-foreground tabular-nums">
							{m.count}<span class="ml-1 text-[10px] text-muted-foreground/60"
								>{sharePct.toFixed(0)}%</span
							>
						</span>
					</div>
				{/each}
			</div>
		</div>

		<!-- Rounds-per-match histogram -->
		<div class="rounded-md border bg-card p-4">
			<div class="mb-3">
				<div class="font-heading text-sm font-semibold">Rounds per map</div>
				<p class="text-[11px] text-muted-foreground">
					How many maps fall into each round-count band (regulation = 24)
				</p>
			</div>
			<!-- Two rows: bars (definite-height parent so the % heights resolve) + labels. -->
			<div class="flex h-32 items-end gap-1.5">
				{#each roundsHist as b (b.range)}
					{@const h = Math.max(2, (b.count / roundsMax) * 100)}
					<div
						class="min-w-0 flex-1 rounded-sm bg-foreground/70 transition-colors hover:bg-foreground"
						style="height: {h}%"
						title={`${b.range} rounds: ${b.count} maps`}
					></div>
				{/each}
			</div>
			<div class="mt-1 flex gap-1.5">
				{#each roundsHist as b (b.range)}
					<div
						class="min-w-0 flex-1 truncate text-center font-mono text-[10px] text-muted-foreground/80"
					>
						{b.range}
					</div>
				{/each}
			</div>
			<div class="mt-1 text-center text-[10px] text-muted-foreground/70">rounds played</div>
		</div>
	</div>
</section>