Complete overhaul of all 7 match sub-pages (Overview, Flashes, Economy, Details, Weapons, Damage, Chat) with consistent neon design system. Key changes: - Update Card/Tabs components with void backgrounds and neon accents - Add decorative blur orbs and grid pattern to match layout hero - Convert DaisyUI classes to custom Tailwind with neon colors - Update chart components with neon-themed tooltips and grid styling - Add RoundTimeline neon glow on selection with void-themed tooltips Puns added throughout: - "Hall of Shame" for players who flash teammates more than enemies - "Needs Therapy Award" for high team damage - "MVP (Most Violent Player)" badge - "The Poverty Round", "YOLO Buy" economy labels - "Multi-Threat Level", "Can't Touch This", "Molotov Mixologist" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
131 lines
2.6 KiB
Svelte
131 lines
2.6 KiB
Svelte
<script lang="ts">
|
|
import { onMount, onDestroy } from 'svelte';
|
|
import {
|
|
Chart,
|
|
BarController,
|
|
BarElement,
|
|
LinearScale,
|
|
CategoryScale,
|
|
Title,
|
|
Tooltip,
|
|
Legend,
|
|
type ChartConfiguration
|
|
} from 'chart.js';
|
|
|
|
// Register Chart.js components
|
|
Chart.register(BarController, BarElement, LinearScale, CategoryScale, Title, Tooltip, Legend);
|
|
|
|
interface Props {
|
|
data: {
|
|
labels: string[];
|
|
datasets: Array<{
|
|
label: string;
|
|
data: number[];
|
|
backgroundColor?: string | string[];
|
|
borderColor?: string | string[];
|
|
borderWidth?: number;
|
|
}>;
|
|
};
|
|
options?: Partial<ChartConfiguration<'bar'>['options']>;
|
|
height?: number;
|
|
horizontal?: boolean;
|
|
class?: string;
|
|
}
|
|
|
|
let {
|
|
data,
|
|
options = {},
|
|
height = 300,
|
|
horizontal = false,
|
|
class: className = ''
|
|
}: Props = $props();
|
|
|
|
let canvas: HTMLCanvasElement;
|
|
let chart: Chart<'bar'> | null = null;
|
|
|
|
// Convert Svelte 5 $state proxy to plain object for Chart.js compatibility
|
|
// Using JSON parse/stringify to handle Svelte proxies that structuredClone can't handle
|
|
const plainData = $derived(JSON.parse(JSON.stringify(data)));
|
|
|
|
const defaultOptions: ChartConfiguration<'bar'>['options'] = {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
indexAxis: horizontal ? 'y' : 'x',
|
|
plugins: {
|
|
legend: {
|
|
display: true,
|
|
position: 'top',
|
|
labels: {
|
|
color: 'rgba(255, 255, 255, 0.7)',
|
|
font: {
|
|
family: 'Inter, system-ui, sans-serif',
|
|
size: 12
|
|
}
|
|
}
|
|
},
|
|
tooltip: {
|
|
backgroundColor: 'rgba(18, 18, 26, 0.95)',
|
|
padding: 12,
|
|
titleColor: '#fff',
|
|
bodyColor: 'rgba(255, 255, 255, 0.8)',
|
|
borderColor: 'rgba(0, 212, 255, 0.3)',
|
|
borderWidth: 1
|
|
}
|
|
},
|
|
scales: {
|
|
x: {
|
|
grid: {
|
|
color: 'rgba(255, 255, 255, 0.05)'
|
|
},
|
|
ticks: {
|
|
color: 'rgba(255, 255, 255, 0.5)',
|
|
font: {
|
|
size: 11
|
|
}
|
|
}
|
|
},
|
|
y: {
|
|
grid: {
|
|
color: 'rgba(255, 255, 255, 0.05)'
|
|
},
|
|
ticks: {
|
|
color: 'rgba(255, 255, 255, 0.5)',
|
|
font: {
|
|
size: 11
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
onMount(() => {
|
|
const ctx = canvas.getContext('2d');
|
|
if (ctx) {
|
|
chart = new Chart(ctx, {
|
|
type: 'bar',
|
|
data: plainData,
|
|
options: { ...defaultOptions, ...options }
|
|
});
|
|
}
|
|
});
|
|
|
|
onDestroy(() => {
|
|
if (chart) {
|
|
chart.destroy();
|
|
}
|
|
});
|
|
|
|
// Watch for data changes and update chart
|
|
$effect(() => {
|
|
if (chart && plainData) {
|
|
chart.data = plainData;
|
|
chart.options = { ...defaultOptions, ...options };
|
|
chart.update();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<div class="relative w-full {className}" style="height: {height}px">
|
|
<canvas bind:this={canvas}></canvas>
|
|
</div>
|