Print function correction + player analysis fix and player stats fix
This commit is contained in:
@@ -65,28 +65,6 @@
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
background: #f8f9fa;
|
||||
border: 2px solid #e9ecef;
|
||||
cursor: pointer;
|
||||
padding: 12px 20px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.nav-btn:hover {
|
||||
background: #e9ecef;
|
||||
border-color: #007bff;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-1px);
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.nav-btn.secondary {
|
||||
background: #6c757d;
|
||||
border-color: #495057;
|
||||
@@ -146,10 +124,142 @@
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Tab Navigation */
|
||||
.tab-navigation {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
margin-bottom: 25px;
|
||||
border-bottom: 2px solid #f1f3f4;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
color: #007bff;
|
||||
border-bottom-color: #007bff;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
color: #007bff;
|
||||
background: rgba(0, 123, 255, 0.05);
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Tournament Leaders Section */
|
||||
.tournament-leaders {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.tournament-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #e9ecef;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tournament-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, #ffc107, #fd7e14);
|
||||
}
|
||||
|
||||
.tournament-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tournament-name {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tournament-date {
|
||||
background: #f8f9fa;
|
||||
color: #666;
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.leaders-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.leader-category {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.leader-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.leader-name {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.leader-score {
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.leader-score.tens {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
/* Compact Stats Overview */
|
||||
.stats-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -453,7 +563,25 @@
|
||||
}
|
||||
|
||||
.stats-overview {
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
|
||||
}
|
||||
|
||||
.tournament-leaders {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.leaders-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tab-navigation {
|
||||
flex-wrap: wrap;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -461,7 +589,7 @@
|
||||
<body>
|
||||
<!-- Navigation Bar -->
|
||||
<div class="navbar">
|
||||
<div class="navbar-title">👤 Player Analysis</div>
|
||||
<div class="navbar-title">🎯 Player Analysis</div>
|
||||
<div class="navbar-controls">
|
||||
<a href="/" class="nav-btn primary">← Dashboard</a>
|
||||
<a href="/archive" class="nav-btn secondary">📚 Archive</a>
|
||||
@@ -473,52 +601,84 @@
|
||||
<div class="stats-overview">
|
||||
<div class="stat-card">
|
||||
<span class="stat-icon">👥</span>
|
||||
<div class="stat-value" id="totalPlayers">{{ players|length }}</div>
|
||||
<div class="stat-value" id="totalPlayers">Loading...</div>
|
||||
<div class="stat-label">Total Players</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-icon">📊</span>
|
||||
<div class="stat-value" id="avgTournaments">{{ overview_stats.avg_tournaments if overview_stats else 0 }}</div>
|
||||
<div class="stat-label">Avg Tournaments</div>
|
||||
<span class="stat-icon">🎯</span>
|
||||
<div class="stat-value" id="totalTournaments">Loading...</div>
|
||||
<div class="stat-label">Total Tournaments</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-icon">🏆</span>
|
||||
<div class="stat-value" id="topScore">{{ overview_stats.top_score if overview_stats else 0 }}</div>
|
||||
<div class="stat-label">Highest Score</div>
|
||||
<div class="stat-value" id="score20Targets">Loading...</div>
|
||||
<div class="stat-label">Best 20 Targets</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-icon">🎖️</span>
|
||||
<div class="stat-value" id="score40Targets">Loading...</div>
|
||||
<div class="stat-label">Best 40 Targets</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-icon">🥇</span>
|
||||
<div class="stat-value" id="score4Targets">Loading...</div>
|
||||
<div class="stat-label">Best 4 Targets</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
<div class="section">
|
||||
<div class="section-title">Select a Player to Analyze</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<div class="controls">
|
||||
<input type="text" class="search-box" id="searchBox" placeholder="🔍 Search players by name...">
|
||||
|
||||
<select class="sort-select" id="sortSelect">
|
||||
<option value="name">Sort by Name</option>
|
||||
<option value="best_score">Sort by Best Score</option>
|
||||
<option value="average_score">Sort by Average Score</option>
|
||||
<option value="total_tournaments">Sort by Total Tournaments</option>
|
||||
<option value="total_leagues">Sort by Total Leagues</option>
|
||||
<option value="total_shots">Sort by Total Shots</option>
|
||||
</select>
|
||||
<div class="tab-navigation">
|
||||
<button class="tab-btn active" onclick="switchTab('tournament-leaders')">🏆 Overall Champions</button>
|
||||
<button class="tab-btn" onclick="switchTab('players')">👥 All Players</button>
|
||||
</div>
|
||||
|
||||
<!-- Players Grid -->
|
||||
<div class="players-grid" id="playersGrid">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading players...</p>
|
||||
<!-- Tournament Leaders Tab -->
|
||||
<div id="tournament-leaders" class="tab-content active">
|
||||
<div class="section-title">Overall Champions by Tournament Type</div>
|
||||
|
||||
<div class="tournament-leaders" id="tournamentLeaders">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading tournament data...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Players Tab -->
|
||||
<div id="players" class="tab-content">
|
||||
<div class="section-title">Select a Player to Analyze</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<div class="controls">
|
||||
<input type="text" class="search-box" id="searchBox" placeholder="🔍 Search players by name...">
|
||||
|
||||
<select class="sort-select" id="sortSelect">
|
||||
<option value="name">Sort by Name</option>
|
||||
<option value="best_score">Sort by Best Score</option>
|
||||
<option value="average_score">Sort by Average Score</option>
|
||||
<option value="total_tournaments">Sort by Total Tournaments</option>
|
||||
<option value="total_leagues">Sort by Total Leagues</option>
|
||||
<option value="total_shots">Sort by Total Shots</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Players Grid -->
|
||||
<div class="players-grid" id="playersGrid">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading players...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Players data from Flask
|
||||
let playersData = {{ players|tojson }};
|
||||
let filteredPlayers = [...playersData];
|
||||
// Global data
|
||||
let playersData = [];
|
||||
let tournamentData = [];
|
||||
let filteredPlayers = [];
|
||||
let currentFilter = 'all';
|
||||
let currentSort = 'name';
|
||||
let playersWithStats = [];
|
||||
@@ -526,9 +686,180 @@
|
||||
// Initialize page
|
||||
function initializePage() {
|
||||
loadPlayerStats();
|
||||
loadTournamentLeaders();
|
||||
setupEventListeners();
|
||||
}
|
||||
|
||||
// Switch between tabs
|
||||
function switchTab(tabName) {
|
||||
// Hide all tab contents
|
||||
document.querySelectorAll('.tab-content').forEach(content => {
|
||||
content.classList.remove('active');
|
||||
});
|
||||
|
||||
// Remove active class from all tab buttons
|
||||
document.querySelectorAll('.tab-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
|
||||
// Show selected tab content
|
||||
document.getElementById(tabName).classList.add('active');
|
||||
|
||||
// Add active class to clicked button
|
||||
event.target.classList.add('active');
|
||||
}
|
||||
|
||||
// Load tournament leaders data
|
||||
async function loadTournamentLeaders() {
|
||||
try {
|
||||
const response = await fetch('/api/archive/tournament-leaders');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
tournamentData = result.tournament_types;
|
||||
renderTournamentLeaders();
|
||||
updateOverallStats();
|
||||
} else {
|
||||
console.error('Failed to load tournament data:', result.message);
|
||||
document.getElementById('tournamentLeaders').innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">🎯</div>
|
||||
<h3>Unable to Load Tournament Data</h3>
|
||||
<p>${result.message || 'Please try refreshing the page'}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading tournament data:', error);
|
||||
document.getElementById('tournamentLeaders').innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">🎯</div>
|
||||
<h3>Unable to Load Tournament Data</h3>
|
||||
<p>Please try refreshing the page</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Render tournament leaders
|
||||
function renderTournamentLeaders() {
|
||||
const leadersContainer = document.getElementById('tournamentLeaders');
|
||||
|
||||
if (tournamentData.length === 0) {
|
||||
leadersContainer.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">🎯</div>
|
||||
<h3>No Tournament Data Available</h3>
|
||||
<p>Tournament results will appear here once available</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
leadersContainer.innerHTML = tournamentData.map(tournamentType => `
|
||||
<div class="tournament-card">
|
||||
<div class="tournament-header">
|
||||
<div class="tournament-name">${tournamentType.name}</div>
|
||||
<div class="tournament-date">${tournamentType.total_tournaments} tournament${tournamentType.total_tournaments !== 1 ? 's' : ''}</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-bottom: 15px; color: #666; font-size: 0.9rem; font-weight: 500;">
|
||||
${tournamentType.description}
|
||||
</div>
|
||||
|
||||
<div class="leaders-grid">
|
||||
<div class="leader-category">
|
||||
<div class="category-title">🏆 Best Score</div>
|
||||
<div class="leader-info">
|
||||
<div class="leader-name">${tournamentType.best_score.player_name || 'No data'}</div>
|
||||
<div class="leader-score">${tournamentType.best_score.score || 0}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="leader-category">
|
||||
<div class="category-title">🎪 Most 10s</div>
|
||||
<div class="leader-info">
|
||||
<div class="leader-name">${tournamentType.most_tens.player_name || 'No data'}</div>
|
||||
<div class="leader-score tens">${tournamentType.most_tens.tens || 0} 10s</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Update overall statistics
|
||||
function updateOverallStats() {
|
||||
let totalTournaments = 0;
|
||||
let score20Targets = 0;
|
||||
let score40Targets = 0;
|
||||
let score4Targets = 0;
|
||||
|
||||
// Calculate statistics across all tournament types
|
||||
tournamentData.forEach(tournamentType => {
|
||||
totalTournaments += tournamentType.total_tournaments || 0;
|
||||
|
||||
// Get best scores for each tournament type
|
||||
if (tournamentType.id === '20_targets' && tournamentType.best_score) {
|
||||
score20Targets = tournamentType.best_score.score || 0;
|
||||
} else if (tournamentType.id === '40_targets' && tournamentType.best_score) {
|
||||
score40Targets = tournamentType.best_score.score || 0;
|
||||
} else if (tournamentType.id === '4_targets' && tournamentType.best_score) {
|
||||
score4Targets = tournamentType.best_score.score || 0;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('totalTournaments').textContent = totalTournaments;
|
||||
document.getElementById('score20Targets').textContent = score20Targets || '-';
|
||||
document.getElementById('score40Targets').textContent = score40Targets || '-';
|
||||
document.getElementById('score4Targets').textContent = score4Targets || '-';
|
||||
}
|
||||
|
||||
// Get tournament type display name
|
||||
function getTournamentTypeDisplay(tournamentType) {
|
||||
const typeMap = {
|
||||
'20_targets': '20 Targets (2 shots each)',
|
||||
'40_targets': '40 Targets (2 shots each)',
|
||||
'4_targets': '4 Targets (5 shots each)'
|
||||
};
|
||||
return typeMap[tournamentType] || tournamentType;
|
||||
}
|
||||
|
||||
// Format date for display
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return 'Unknown Date';
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
if (isNaN(date.getTime())) {
|
||||
// Try to parse filename format YYYYMMDD_HHMMSS
|
||||
if (dateString.length >= 8) {
|
||||
const year = dateString.substring(0, 4);
|
||||
const month = dateString.substring(4, 6);
|
||||
const day = dateString.substring(6, 8);
|
||||
const parsedDate = new Date(`${year}-${month}-${day}`);
|
||||
if (!isNaN(parsedDate.getTime())) {
|
||||
return parsedDate.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
}
|
||||
}
|
||||
return 'Unknown Date';
|
||||
}
|
||||
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
} catch (error) {
|
||||
return 'Unknown Date';
|
||||
}
|
||||
}
|
||||
|
||||
// Load player statistics
|
||||
async function loadPlayerStats() {
|
||||
try {
|
||||
@@ -539,9 +870,13 @@
|
||||
playersWithStats = result.players;
|
||||
playersData = playersWithStats;
|
||||
filteredPlayers = [...playersWithStats];
|
||||
|
||||
// Update total players count
|
||||
document.getElementById('totalPlayers').textContent = playersData.length;
|
||||
|
||||
filterAndSortPlayers();
|
||||
} else {
|
||||
console.error('Failed to load player stats');
|
||||
console.error('Failed to load player stats:', result.message);
|
||||
renderPlayersBasic();
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -554,22 +889,12 @@
|
||||
function setupEventListeners() {
|
||||
const searchBox = document.getElementById('searchBox');
|
||||
const sortSelect = document.getElementById('sortSelect');
|
||||
const filterButtons = document.querySelectorAll('.filter-btn');
|
||||
|
||||
searchBox.addEventListener('input', filterAndSortPlayers);
|
||||
sortSelect.addEventListener('change', (e) => {
|
||||
currentSort = e.target.value;
|
||||
filterAndSortPlayers();
|
||||
});
|
||||
|
||||
filterButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
filterButtons.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
currentFilter = btn.dataset.filter;
|
||||
filterAndSortPlayers();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Filter and sort players
|
||||
@@ -675,42 +1000,70 @@
|
||||
|
||||
// Render players without stats (fallback)
|
||||
function renderPlayersBasic() {
|
||||
const playersGrid = document.getElementById('playersGrid');
|
||||
|
||||
playersGrid.innerHTML = playersData.map(player => `
|
||||
<div class="player-card ${player.current_player ? 'current-player' : 'archived-player'}"
|
||||
onclick="viewPlayerStats(${player.id})">
|
||||
<div class="player-header">
|
||||
<div class="player-name">${player.name}</div>
|
||||
<div class="player-badge ${player.current_player ? 'current' : 'archived'}">
|
||||
${player.current_player ? 'Current' : 'Archived'}
|
||||
</div>
|
||||
</div>
|
||||
// If we can't get stats, try to get basic player list
|
||||
fetch('/api/players')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const basicPlayers = data.players || [];
|
||||
const playersGrid = document.getElementById('playersGrid');
|
||||
|
||||
<div class="player-stats">
|
||||
<div class="stat-item">
|
||||
<span class="icon">🎯</span>
|
||||
<span class="label">Tournaments:</span>
|
||||
<span class="value">Loading...</span>
|
||||
if (basicPlayers.length === 0) {
|
||||
playersGrid.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">👤</div>
|
||||
<h3>No Players Found</h3>
|
||||
<p>No player data available</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
playersGrid.innerHTML = basicPlayers.map(player => `
|
||||
<div class="player-card ${player.enabled ? 'current-player' : 'archived-player'}"
|
||||
onclick="viewPlayerStats(${player.id})">
|
||||
<div class="player-header">
|
||||
<div class="player-name">${player.name}</div>
|
||||
<div class="player-badge ${player.enabled ? 'current' : 'archived'}">
|
||||
${player.enabled ? 'Current' : 'Archived'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="player-stats">
|
||||
<div class="stat-item">
|
||||
<span class="icon">🎯</span>
|
||||
<span class="label">Tournaments:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">🏆</span>
|
||||
<span class="label">Leagues:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">📈</span>
|
||||
<span class="label">Best Score:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">📊</span>
|
||||
<span class="label">Average:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">🏆</span>
|
||||
<span class="label">Leagues:</span>
|
||||
<span class="value">Loading...</span>
|
||||
`).join('');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading basic players:', error);
|
||||
const playersGrid = document.getElementById('playersGrid');
|
||||
playersGrid.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">❌</div>
|
||||
<h3>Error Loading Players</h3>
|
||||
<p>Unable to load player data</p>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">📈</span>
|
||||
<span class="label">Best Score:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="icon">📊</span>
|
||||
<span class="label">Average:</span>
|
||||
<span class="value">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Create mini performance chart for player
|
||||
|
||||
Reference in New Issue
Block a user