feat: Complete scoreboard with avatar, score, and player color indicators

Enhance match details scoreboard with additional visual information for better
player identification and context.

## Changes

### Avatar Column
- Display player profile images in first column (40x40px)
- Rounded style with border for consistent appearance
- Non-sortable for visual continuity

### Score Column
- Show in-game score for each player
- Sortable to identify top performers
- Monospace font for numeric alignment

### Player Color Indicators
- Add colored dot next to player names
- Map CS2 player colors (green, yellow, purple, blue, orange, grey) to hex values
- Visual indicator helps identify specific players during match review

## Implementation Details

Created `playerColors` mapping object to convert CS2's player color names to
hex color codes for display. Updated Player name column render function to
include inline colored dot element.

All columns maintain existing team color styling (terrorist/CT) for consistency.

Note: MVP and K/D ratio columns already existed in scoreboard.

This completes Phase 2 Feature 1 - scoreboard now provides comprehensive player
information at a glance.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-12 20:05:51 +01:00
parent ae7d880bc1
commit 05ef985851

View File

@@ -42,8 +42,28 @@
// Sort by kills descending // Sort by kills descending
const sortedPlayers = hasPlayerData ? playersWithStats.sort((a, b) => b.kills - a.kills) : []; const sortedPlayers = hasPlayerData ? playersWithStats.sort((a, b) => b.kills - a.kills) : [];
// Player color mapping for scoreboard indicators
const playerColors: Record<string, string> = {
green: '#22c55e',
yellow: '#eab308',
purple: '#a855f7',
blue: '#3b82f6',
orange: '#f97316',
grey: '#6b7280'
};
// Prepare data table columns // Prepare data table columns
const detailsColumns = [ const detailsColumns = [
{
key: 'avatar' as keyof (typeof playersWithStats)[0],
label: '',
sortable: false,
align: 'center' as const,
render: (value: string | number | boolean | undefined, row: (typeof playersWithStats)[0]) => {
const avatarUrl = row.avatar || '';
return `<img src="${avatarUrl}" alt="${row.name}" class="h-10 w-10 rounded-full border-2 border-base-300" />`;
}
},
{ {
key: 'name' as keyof (typeof playersWithStats)[0], key: 'name' as keyof (typeof playersWithStats)[0],
label: 'Player', label: 'Player',
@@ -51,9 +71,21 @@
render: (value: string | number | boolean | undefined, row: (typeof playersWithStats)[0]) => { render: (value: string | number | boolean | undefined, row: (typeof playersWithStats)[0]) => {
const strValue = value !== undefined ? String(value) : ''; const strValue = value !== undefined ? String(value) : '';
const teamClass = row.team_id === firstTeamId ? 'text-terrorist' : 'text-ct'; const teamClass = row.team_id === firstTeamId ? 'text-terrorist' : 'text-ct';
return `<a href="/player/${row.id}" class="font-medium hover:underline ${teamClass}">${strValue}</a>`; // Color indicator dot
const colorHex = row.color ? playerColors[row.color] : undefined;
const colorDot = colorHex
? `<span class="inline-block h-3 w-3 rounded-full mr-2" style="background-color: ${colorHex}"></span>`
: '';
return `<a href="/player/${row.id}" class="flex items-center font-medium hover:underline ${teamClass}">${colorDot}${strValue}</a>`;
} }
}, },
{
key: 'score' as keyof (typeof playersWithStats)[0],
label: 'Score',
sortable: true,
align: 'center' as const,
class: 'font-mono font-semibold'
},
{ {
key: 'kills' as keyof (typeof playersWithStats)[0], key: 'kills' as keyof (typeof playersWithStats)[0],
label: 'K', label: 'K',