<!DOCTYPE html>
<html>
<head>
<title>Basketball Tracker</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; margin-top: 20px; }
.team-scores { margin-bottom: 20px; font-size: 20px; font-weight: bold; }
.opponent, .player { margin: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; display: inline-block; width: 200px; }
.player.highlight { border: 2px solid blue; }
button { font-size: 16px; padding: 5px 10px; margin: 5px; cursor: pointer; }
.stats { font-size: 14px; margin-top: 5px; }
.tabs { margin: 20px; }
.tab-content { display: none; }
.tab-content.active { display: block; }
.roster-table, .box-score-table { margin: 0 auto; border-collapse: collapse; }
.roster-table th, .roster-table td, .box-score-table th, .box-score-table td { border: 1px solid #ccc; padding: 8px; text-align: center; }
.roster-table th, .box-score-table th { background-color: #f2f2f2; cursor: pointer; }
.roster-table th.active, .box-score-table th.active { background-color: blue; color: white; font-weight: bold; }
.roster-table td { cursor: pointer; }
.period { margin-bottom: 20px; font-size: 18px; }
.checkmark { font-size: 18px; }
.player-name { width: 50%; }
.period-scores { margin-top: 20px; text-align: left; display: inline-block; }
.period-scores table { margin: 0 auto; border-collapse: collapse; }
.period-scores th, .period-scores td { border: 1px solid #ccc; padding: 8px; text-align: center; }
.period-scores th { background-color: #f2f2f2; }
.tab-button.active { background-color: blue; color: white; }
.box-score-table td.checked { background-color: #d3d3d3; } /* Darker gray for checked cells */
</style>
</head>
<body>
<!-- Team Scores and Period -->
<div class="team-scores">
<span>Panthers: <span id="our-team-score">0</span></span> |
<span>Opponent: <span id="opponent-score">0</span></span>
</div>
<div class="period">
Period: <span id="current-period">1</span>
</div>
<!-- Tabs and Undo Button -->
<div class="tabs">
<button id="shot-counter-tab" class="tab-button active" onclick="switchTab('shot-counter')">Shot Counter</button>
<button id="roster-tab" class="tab-button" onclick="switchTab('roster')">Roster</button>
<button id="box-score-tab" class="tab-button" onclick="switchTab('box-score')">Box Score</button>
<button onclick="undoAction()">Undo</button>
</div>
<!-- Shot Counter Tab -->
<div id="shot-counter" class="tab-content active">
<!-- Opponent Team Section -->
<div class="opponent">
<h3>Opponent Team</h3>
<div>
<button onclick="recordOpponentShot(true)">Made</button>
<button onclick="recordOpponentShot(false)">Missed</button>
</div>
<div class="stats">
Made: <span id="opponent-made">0</span> |
Missed: <span id="opponent-missed">0</span> |
Points: <span id="opponent-points">0</span>
</div>
</div>
<!-- Player Sections -->
<div id="players"></div>
</div>
<!-- Roster Tab -->
<div id="roster" class="tab-content">
<h3>Roster</h3>
<button onclick="addPlayer()">Add Player</button>
<table class="roster-table">
<thead id="roster-header"></thead>
<tbody id="roster-body"></tbody>
</table>
<!-- Period Scores -->
<div class="period-scores">
<h3>Period Scores</h3>
<table id="period-scores-table">
<thead>
<tr>
<th>Period</th>
<th>Panthers</th>
<th>Opponent</th>
</tr>
</thead>
<tbody id="period-scores-body"></tbody>
</table>
</div>
</div>
<!-- Box Score Tab -->
<div id="box-score" class="tab-content">
<h3>Box Score</h3>
<table class="box-score-table">
<thead id="box-score-header"></thead>
<tbody id="box-score-body"></tbody>
</table>
</div>
<script>
const players = [];
const opponent = { made: 0, missed: 0, points: 0 };
let currentPeriod = 1;
const rosterCheckmarks = [];
const periodScores = { ourTeam: Array(8).fill(0), opponent: Array(8).fill(0) };
const actionHistory = [];
// Initialize the app
function init() {
renderRosterHeader();
renderPeriodScores();
renderBoxScore();
addPlayer();
addPlayer();
}
// Render roster header
function renderRosterHeader() {
const rosterHeader = document.getElementById('roster-header');
rosterHeader.innerHTML = `
<tr>
<th>Player</th>
${Array.from({ length: 8 }, (_, i) => `
<th onclick="setPeriod(${i + 1})" class="${i === 0 ? 'active' : ''}">${i + 1}</th>
`).join('')}
</tr>
`;
}
// Render period scores
function renderPeriodScores() {
const periodScoresBody = document.getElementById('period-scores-body');
periodScoresBody.innerHTML = Array.from({ length: 8 }, (_, i) => `
<tr>
<td>${i + 1}</td>
<td id="our-period-${i + 1}">0</td>
<td id="opponent-period-${i + 1}">0</td>
</tr>
`).join('') + `
<tr>
<td>Total</td>
<td id="our-total-score">0</td>
<td id="opponent-total-score">0</td>
</tr>
`;
}
// Update period scores
function updatePeriodScores() {
const ourTotal = periodScores.ourTeam.reduce((sum, score) => sum + score, 0);
const opponentTotal = periodScores.opponent.reduce((sum, score) => sum + score, 0);
periodScores.ourTeam.forEach((score, index) => {
document.getElementById(`our-period-${index + 1}`).textContent = score;
});
periodScores.opponent.forEach((score, index) => {
document.getElementById(`opponent-period-${index + 1}`).textContent = score;
});
document.getElementById('our-total-score').textContent = ourTotal;
document.getElementById('opponent-total-score').textContent = opponentTotal;
}
// Render box score
function renderBoxScore() {
const boxScoreHeader = document.getElementById('box-score-header');
const boxScoreBody = document.getElementById('box-score-body');
// Render header
boxScoreHeader.innerHTML = `
<tr>
<th>Player</th>
${Array.from({ length: 8 }, (_, i) => `<th>${i + 1}</th>`).join('')}
</tr>
`;
// Render body
boxScoreBody.innerHTML = players.map((player, index) => `
<tr>
<td>${player.name || `Player ${index + 1}`}</td>
${Array.from({ length: 8 }, (_, i) => `
<td id="box-score-${index}-${i + 1}" class="${rosterCheckmarks[index][i] ? 'checked' : ''}">
${player.pointsByPeriod?.[i] || 0}
</td>
`).join('')}
</tr>
`).join('');
}
// Update box score
function updateBoxScore() {
players.forEach((player, index) => {
Array.from({ length: 8 }, (_, i) => {
const cell = document.getElementById(`box-score-${index}-${i + 1}`);
cell.textContent = player.pointsByPeriod?.[i] || 0;
cell.classList.toggle('checked', rosterCheckmarks[index][i]);
});
});
}
// Add a new player
function addPlayer() {
const playerIndex = players.length;
players.push({ made: 0, missed: 0, points: 0, pointsByPeriod: Array(8).fill(0) });
rosterCheckmarks.push(Array(8).fill(false));
// Add player to Shot Counter tab
const playerDiv = document.createElement('div');
playerDiv.className = 'player';
playerDiv.id = `player-${playerIndex}`;
playerDiv.innerHTML = `
<input type="text" class="player-name" value="Player ${playerIndex + 1}" placeholder="Enter name" oninput="updateRosterName(${playerIndex}, this.value)">
<div>
<button onclick="recordShot(${playerIndex}, true)">Made</button>
<button onclick="recordShot(${playerIndex}, false)">Missed</button>
</div>
<div class="stats">
Made: <span id="made-${playerIndex}">0</span> |
Missed: <span id="missed-${playerIndex}">0</span> |
%: <span id="percentage-${playerIndex}">0%</span> |
Points: <span id="points-${playerIndex}">0</span>
</div>
`;
document.getElementById('players').appendChild(playerDiv);
// Add player to Roster tab
const row = document.createElement('tr');
row.innerHTML = `
<td><input type="text" class="player-name" value="Player ${playerIndex + 1}" placeholder="Enter name" oninput="updatePlayerName(${playerIndex}, this.value)"></td>
${Array.from({ length: 8 }, (_, i) => `
<td onclick="toggleCheckmark(${playerIndex}, ${i})"><span class="checkmark">${rosterCheckmarks[playerIndex][i] ? '✓' : ''}</span></td>
`).join('')}
`;
document.getElementById('roster-body').appendChild(row);
// Update box score
renderBoxScore();
sortPlayers();
}
// Update roster name from Shot Counter tab
function updateRosterName(playerIndex, name) {
players[playerIndex].name = name;
document.querySelectorAll('.roster-name')[playerIndex].value = name;
updateBoxScore();
}
// Update player name from Roster tab
function updatePlayerName(playerIndex, name) {
players[playerIndex].name = name;
document.querySelectorAll('.player-name')[playerIndex].value = name;
updateBoxScore();
}
// Record a shot for a player
function recordShot(playerIndex, isMade) {
actionHistory.push({ type: 'player', playerIndex, isMade, period: currentPeriod });
const player = players[playerIndex];
if (isMade) {
player.made++;
player.points += 2;
player.pointsByPeriod[currentPeriod - 1] += 2; // Add points to the current period
periodScores.ourTeam[currentPeriod - 1] += 2; // Add points to the period scores
} else {
player.missed++;
}
updateStats(playerIndex);
updateTeamScore();
updatePeriodScores();
updateBoxScore();
highlightPlayer(playerIndex);
}
// Record a shot for the opponent
function recordOpponentShot(isMade) {
actionHistory.push({ type: 'opponent', isMade, period: currentPeriod });
if (isMade) {
opponent.made++;
opponent.points += 2;
periodScores.opponent[currentPeriod - 1] += 2; // Add points to the period scores
} else {
opponent.missed++;
}
updateOpponentStats();
updateTeamScore();
updatePeriodScores();
}
// Update player stats
function updateStats(playerIndex) {
const player = players[playerIndex];
const total = player.made + player.missed;
const percentage = total > 0 ? ((player.made / total) * 100).toFixed(1) : 0;
document.getElementById(`made-${playerIndex}`).textContent = player.made;
document.getElementById(`missed-${playerIndex}`).textContent = player.missed;
document.getElementById(`percentage-${playerIndex}`).textContent = `${percentage}%`;
document.getElementById(`points-${playerIndex}`).textContent = player.points;
}
// Update opponent stats
function updateOpponentStats() {
document.getElementById('opponent-made').textContent = opponent.made;
document.getElementById('opponent-missed').textContent = opponent.missed;
document.getElementById('opponent-points').textContent = opponent.points;
}
// Update team scores
function updateTeamScore() {
const ourTeamScore = players.reduce((sum, player) => sum + player.points, 0);
document.getElementById('our-team-score').textContent = ourTeamScore;
document.getElementById('opponent-score').textContent = opponent.points;
}
// Switch tabs
function switchTab(tabName) {
document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
document.getElementById(tabName).classList.add('active');
document.querySelectorAll('.tab-button').forEach(button => button.classList.remove('active'));
document.getElementById(`${tabName}-tab`).classList.add('active');
}
// Toggle checkmark for a player
function toggleCheckmark(playerIndex, columnIndex) {
rosterCheckmarks[playerIndex][columnIndex] = !rosterCheckmarks[playerIndex][columnIndex];
const cell = document.querySelector(`#roster-body tr:nth-child(${playerIndex + 1}) td:nth-child(${columnIndex + 2}) .checkmark`);
cell.textContent = rosterCheckmarks[playerIndex][columnIndex] ? '✓' : '';
updateBoxScore();
sortPlayers();
highlightPlayer(playerIndex);
}
// Set the current period
function setPeriod(period) {
currentPeriod = period;
document.getElementById('current-period').textContent = period;
// Highlight the clicked period header
document.querySelectorAll('.roster-table th').forEach((th, index) => {
th.classList.toggle('active', index === period);
});
sortPlayers();
highlightPlayers();
}
// Sort players based on checkmarks
function sortPlayers() {
const playersDiv = document.getElementById('players');
const sortedPlayers = players
.map((player, index) => ({ ...player, index, hasCheckmark: rosterCheckmarks[index][currentPeriod - 1] }))
.sort((a, b) => b.hasCheckmark - a.hasCheckmark);
sortedPlayers.forEach((player) => {
playersDiv.appendChild(document.getElementById(`player-${player.index}`));
});
}
// Highlight a player
function highlightPlayer(playerIndex) {
const playerDiv = document.getElementById(`player-${playerIndex}`);
playerDiv.classList.toggle('highlight', rosterCheckmarks[playerIndex][currentPeriod - 1]);
}
// Highlight all players
function highlightPlayers() {
players.forEach((_, index) => highlightPlayer(index));
}
// Undo the last action
function undoAction() {
if (actionHistory.length === 0) return;
const lastAction = actionHistory.pop();
if (lastAction.type === 'player') {
const player = players[lastAction.playerIndex];
if (lastAction.isMade) {
player.made--;
player.points -= 2;
player.pointsByPeriod[lastAction.period - 1] -= 2; // Remove points from the period
periodScores.ourTeam[lastAction.period - 1] -= 2; // Remove points from the period scores
} else {
player.missed--;
}
updateStats(lastAction.playerIndex);
} else if (lastAction.type === 'opponent') {
if (lastAction.isMade) {
opponent.made--;
opponent.points -= 2;
periodScores.opponent[lastAction.period - 1] -= 2; // Remove points from the period scores
} else {
opponent.missed--;
}
updateOpponentStats();
}
updateTeamScore();
updatePeriodScores();
updateBoxScore();
highlightPlayers();
}
// Initialize the app
init();
</script>
</body>
</html>