high-score-dashboard / index.html
Honda219's picture
allow me to change the order of the tiles - Follow Up Deployment
0d84947 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HIGH SCORE DASHBOARD</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@keyframes ledGlow {
0% { box-shadow: 0 0 5px #00f, 0 0 10px #00f, 0 0 15px #00f; }
25% { box-shadow: 0 0 5px #0f0, 0 0 10px #0f0, 0 0 15px #0f0; }
50% { box-shadow: 0 0 5px #f0f, 0 0 10px #f0f, 0 0 15px #f0f; }
75% { box-shadow: 0 0 5px #ff0, 0 0 10px #ff0, 0 0 15px #ff0; }
100% { box-shadow: 0 0 5px #00f, 0 0 10px #00f, 0 0 15px #00f; }
}
@keyframes ledHover {
0% { box-shadow: 0 0 10px #f00, 0 0 20px #f00, 0 0 30px #f00; }
50% { box-shadow: 0 0 20px #0ff, 0 0 30px #0ff, 0 0 40px #0ff; }
100% { box-shadow: 0 0 10px #f00, 0 0 20px #f00, 0 0 30px #f00; }
}
.draggable {
cursor: move;
border: 1px solid rgba(0,0,0,0.1);
position: relative;
overflow: hidden;
transition: all 0.3s ease;
touch-action: none;
user-select: none;
}
.draggable.dragging {
opacity: 0.8;
transform: scale(1.02);
z-index: 100;
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.draggable.over {
border: 2px dashed #4f46e5;
}
.draggable {
position: relative;
padding: 3px;
}
.draggable::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 3px solid transparent;
border-radius: 12px;
background: linear-gradient(90deg, #f00, #0f0, #00f, #ff0, #f0f) border-box;
background-size: 500% 500%;
-webkit-mask:
linear-gradient(#fff 0 0) padding-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
animation: ledGlow 5s ease infinite;
pointer-events: none;
}
.draggable:hover::before {
animation: ledHover 1.5s ease infinite;
border-width: 4px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.hide-on-edit {
display: block;
}
.show-on-edit {
display: none;
}
.edit-mode .hide-on-edit {
display: none;
}
.edit-mode .show-on-edit {
display: block;
}
.dark-mode {
background-color: #1a202c;
color: white;
}
.dark-mode .container {
background-color: #1a202c;
color: white;
}
.dark-mode .game-card {
background-color: #2d3748;
color: white;
}
.dark-mode .game-card h3,
.dark-mode .game-card h4,
.dark-mode .game-card span,
.dark-mode .game-card .text-gray-800,
.dark-mode .game-card .text-gray-700,
.dark-mode .game-card .text-gray-600,
.dark-mode .game-card .text-gray-500 {
color: white !important;
}
/* Keep edit modal text black for visibility */
.dark-mode #gameEditModal,
.dark-mode #gameEditModal * {
color: black !important;
}
.dark-mode h1,
.dark-mode h2,
.dark-mode h3,
.dark-mode h4,
.dark-mode p,
.dark-mode span,
.dark-mode .text-gray-800,
.dark-mode .text-gray-700,
.dark-mode .text-gray-500,
.dark-mode .text-gray-600 {
color: white !important;
}
.dark-mode .bg-yellow-50 .text-yellow-600 {
color: black !important;
}
.dark-mode .bg-yellow-50 .text-gray-500 {
color: black !important;
}
.dark-mode .bg-gray-100 {
background-color: #2d3748 !important;
}
.dark-mode .bg-white {
background-color: #2d3748 !important;
}
.dark-mode .border-gray-300 {
border-color: #4a5568 !important;
}
.game-card {
transition: all 0.3s ease;
background: white;
border-radius: 10px;
overflow: hidden;
}
.score-tile {
margin-bottom: 0.75rem;
padding: 0.5rem;
}
.game-card h3,
.game-card h4,
.game-card span,
.game-card .text-gray-800,
.game-card .text-gray-700,
.game-card .text-gray-600,
.game-card .text-gray-500 {
color: black !important;
}
.led-highlight {
position: relative;
overflow: hidden;
border-radius: 6px;
}
.led-highlight::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2px solid transparent;
border-radius: 6px;
background: linear-gradient(90deg, #f00, #0f0, #00f, #ff0, #f0f) border-box;
background-size: 500% 500%;
-webkit-mask:
linear-gradient(#fff 0 0) padding-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
animation: ledGlow 5s ease infinite;
pointer-events: none;
}
.game-card:hover {
transform: translateY(-5px);
}
</style>
</head>
<body class="bg-gray-100 min-h-screen dark:bg-gray-900">
<div class="container mx-auto px-4 py-8">
<header class="flex justify-between items-center mb-8">
<h1 class="text-3xl font-bold text-indigo-800">HIGH SCORE DASHBOARD</h1>
<div class="flex space-x-4">
<button id="toggleEditBtn" class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
<i class="fas fa-edit"></i>
<span>Edit Mode</span>
</button>
<button id="addGameBtn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 show-on-edit">
<i class="fas fa-plus"></i>
<span>Add Game</span>
</button>
<button id="saveChangesBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 show-on-edit">
<i class="fas fa-save"></i>
<span>Save Changes</span>
</button>
<button id="darkModeToggle" class="bg-gray-700 hover:bg-gray-800 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
<i class="fas fa-moon"></i>
<span>Dark Mode</span>
</button>
<button id="exportBtn" class="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
<i class="fas fa-file-export"></i>
<span>Export</span>
</button>
<button id="importBtn" class="bg-pink-500 hover:bg-pink-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2">
<i class="fas fa-file-import"></i>
<span>Import</span>
</button>
</div>
</header>
<div id="uploadModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white p-6 rounded-lg w-full max-w-md">
<h2 class="text-xl font-bold mb-4">Upload Game Icon</h2>
<form id="uploadForm" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Select Image (PNG)</label>
<input type="file" id="iconUpload" accept="image/png" class="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100"/>
</div>
<div id="previewContainer" class="hidden">
<p class="text-sm font-medium text-gray-700 mb-1">Preview:</p>
<img id="uploadPreview" class="h-16 w-16 object-contain mx-auto"/>
</div>
<div class="flex justify-end space-x-3">
<button type="button" id="cancelUpload" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md">Cancel</button>
<button type="button" id="confirmUpload" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-md">Upload</button>
</div>
</form>
</div>
</div>
<div id="dashboardContainer" class="dashboard-grid">
<!-- Game cards will be added here dynamically -->
</div>
<div id="gameEditModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white p-6 rounded-lg w-full max-w-md">
<h2 class="text-xl font-bold mb-4" id="modalTitle">Add New Game</h2>
<form id="gameEditForm" class="space-y-4">
<input type="hidden" id="editGameId">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Game Name</label>
<input type="text" id="editGameName" class="w-full px-3 py-2 border border-gray-300 rounded-md" required>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Game Mode</label>
<input type="text" id="editGameMode" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">High Scores</label>
<div class="flex space-x-2 mb-2">
<button type="button" id="sortLowToHigh" class="text-xs bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded">Low to High</button>
<button type="button" id="sortHighToLow" class="text-xs bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded">High to Low</button>
</div>
<div class="space-y-2">
<div class="grid grid-cols-12 gap-2 items-center">
<span class="text-sm text-center col-span-1">1.</span>
<input type="text" pattern="[0-9]+(\.[0-9]*)?" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Score" id="editScore1">
<input type="text" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Mode" id="editMode1">
<input type="date" class="px-2 py-1 border border-gray-300 rounded-md col-span-5 min-w-[140px]" id="editDate1">
</div>
<div class="grid grid-cols-12 gap-2 items-center">
<span class="text-sm text-center col-span-1">2.</span>
<input type="text" pattern="[0-9]+(\.[0-9]*)?" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Score" id="editScore2">
<input type="text" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Mode" id="editMode2">
<input type="date" class="px-2 py-1 border border-gray-300 rounded-md col-span-5 min-w-[140px]" id="editDate2">
</div>
<div class="grid grid-cols-12 gap-2 items-center">
<span class="text-sm text-center col-span-1">3.</span>
<input type="text" pattern="[0-9]+(\.[0-9]*)?" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Score" id="editScore3">
<input type="text" class="px-2 py-1 border border-gray-300 rounded-md col-span-3" placeholder="Mode" id="editMode3">
<input type="date" class="px-2 py-1 border border-gray-300 rounded-md col-span-5 min-w-[140px]" id="editDate3">
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Play Link</label>
<input type="url" id="editPlayLink" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div class="flex justify-between items-center">
<button type="button" id="uploadGameIconBtn" class="text-blue-500 text-sm flex items-center">
<i class="fas fa-image mr-1"></i>
Change Icon
</button>
<div class="flex space-x-3">
<button type="button" id="cancelGameEdit" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md">Cancel</button>
<button type="button" id="saveGameEdit" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-md">Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
<input type="file" id="importFile" accept=".json" class="hidden">
<script>
// Sample initial data
const initialGames = [
{
id: '1',
name: 'Space Adventure',
mode: 'Normal',
icon: 'https://cdn-icons-png.flaticon.com/512/4237/4237033.png',
scores: [
{ score: 12500, date: '2023-06-15', mode: 'Normal' },
{ score: 9800, date: '2023-06-10', mode: 'Hard' },
{ score: 8700, date: '2023-06-05', mode: 'Easy' }
],
playLink: 'https://example.com/games/space'
},
{
id: '2',
name: 'Racing Challenge',
mode: 'Extreme',
icon: 'https://cdn-icons-png.flaticon.com/512/2936/2936886.png',
scores: [
{ score: 3200, date: '2023-06-12', mode: 'Extreme' },
{ score: 2900, date: '2023-06-08', mode: 'Nightmare' },
{ score: 2700, date: '2023-06-03', mode: 'Hard' }
],
playLink: 'https://example.com/games/racing'
},
{
id: '3',
name: 'Puzzle Master',
mode: 'Time Attack',
icon: 'https://cdn-icons-png.flaticon.com/512/1063/1063249.png',
scores: [
{ score: 5500, date: '2023-05-28', mode: 'Time Attack' },
{ score: 5300, date: '2023-05-25', mode: 'Puzzle Rush' },
{ score: 5200, date: '2023-05-20', mode: 'Classic' }
],
playLink: 'https://example.com/games/puzzle'
}
];
// State management
let games = JSON.parse(localStorage.getItem('gameDashboard')) || initialGames;
let editMode = false;
let currentUploadIconId = null;
// DOM elements
const dashboardContainer = document.getElementById('dashboardContainer');
const toggleEditBtn = document.getElementById('toggleEditBtn');
const addGameBtn = document.getElementById('addGameBtn');
const saveChangesBtn = document.getElementById('saveChangesBtn');
const uploadModal = document.getElementById('uploadModal');
const iconUpload = document.getElementById('iconUpload');
const uploadPreview = document.getElementById('uploadPreview');
const previewContainer = document.getElementById('previewContainer');
const cancelUpload = document.getElementById('cancelUpload');
const confirmUpload = document.getElementById('confirmUpload');
const gameEditModal = document.getElementById('gameEditModal');
const modalTitle = document.getElementById('modalTitle');
const cancelGameEdit = document.getElementById('cancelGameEdit');
const saveGameEdit = document.getElementById('saveGameEdit');
const uploadGameIconBtn = document.getElementById('uploadGameIconBtn');
// Initialize the dashboard
function renderDashboard() {
dashboardContainer.innerHTML = '';
games.forEach(game => {
const gameCard = createGameCard(game);
dashboardContainer.appendChild(gameCard);
});
}
// Create a game card element
function createGameCard(game) {
const card = document.createElement('div');
card.className = 'game-card bg-white rounded-xl overflow-hidden draggable';
card.dataset.id = game.id;
card.innerHTML = `
<div class="p-5">
<div class="flex justify-between items-start mb-4">
<div class="flex items-center">
<img src="${game.icon}" alt="${game.name} icon" class="w-12 h-12 object-contain mr-3">
<div>
<h3 class="text-lg font-semibold text-gray-800">${game.name}</h3>
</div>
</div>
<button class="edit-btn bg-gray-100 hover:bg-gray-200 text-gray-700 p-2 rounded-full hide-on-edit">
<i class="fas fa-edit"></i>
</button>
<button class="delete-btn bg-red-100 hover:bg-red-200 text-red-500 p-2 rounded-full show-on-edit">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="mb-4">
<h4 class="text-sm font-medium text-gray-700 mb-2">Top Scores</h4>
<div class="space-y-2">
${game.scores.map((score, index) => {
// Highlight the highest score (first position after sorting)
const isFirstPosition = index === 0;
return `
<div class="flex justify-between items-center score-tile ${isFirstPosition ? 'led-highlight' : ''} p-2 rounded">
<span class="text-sm font-medium text-black">
${index + 1}. ${score.score.toLocaleString()}
</span>
<span class="text-xs text-gray-500 mx-auto">${score.mode || ''}</span>
<span class="text-xs text-gray-500">${score.date}</span>
</div>
`;
}).join('')}
</div>
</div>
<a href="${game.playLink}" target="_blank" class="block w-full text-center bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-lg mb-3">
Play Now <i class="fas fa-play ml-1"></i>
</a>
</div>
`;
// Add event listeners
card.querySelector('.edit-btn').addEventListener('click', () => openEditModal(game.id));
card.querySelector('.delete-btn').addEventListener('click', () => deleteGame(game.id));
return card;
}
// Toggle edit mode
function toggleEditMode() {
editMode = !editMode;
document.body.classList.toggle('edit-mode', editMode);
if (editMode) {
toggleEditBtn.innerHTML = '<i class="fas fa-times"></i><span>Cancel Edit</span>';
} else {
toggleEditBtn.innerHTML = '<i class="fas fa-edit"></i><span>Edit Mode</span>';
}
}
// Open the game edit modal
function openEditModal(gameId = null) {
if (gameId) {
const game = games.find(g => g.id === gameId);
if (game) {
document.getElementById('editGameId').value = game.id;
document.getElementById('editGameName').value = game.name;
document.getElementById('editGameMode').value = game.mode || '';
document.getElementById('editPlayLink').value = game.playLink || '';
// Fill scores
document.getElementById('editScore1').value = game.scores[0]?.score || '';
document.getElementById('editMode1').value = game.scores[0]?.mode || '';
document.getElementById('editDate1').value = game.scores[0]?.date || '';
document.getElementById('editScore2').value = game.scores[1]?.score || '';
document.getElementById('editMode2').value = game.scores[1]?.mode || '';
document.getElementById('editDate2').value = game.scores[1]?.date || '';
document.getElementById('editScore3').value = game.scores[2]?.score || '';
document.getElementById('editMode3').value = game.scores[2]?.mode || '';
document.getElementById('editDate3').value = game.scores[2]?.date || '';
modalTitle.textContent = 'Edit Game';
currentUploadIconId = game.id;
}
} else {
// Reset for new game
document.getElementById('editGameId').value = '';
document.getElementById('editGameName').value = '';
document.getElementById('editGameMode').value = '';
document.getElementById('editPlayLink').value = '';
document.getElementById('editScore1').value = '';
document.getElementById('editDate1').value = '';
document.getElementById('editScore2').value = '';
document.getElementById('editDate2').value = '';
document.getElementById('editScore3').value = '';
document.getElementById('editDate3').value = '';
modalTitle.textContent = 'Add New Game';
currentUploadIconId = null;
}
gameEditModal.classList.remove('hidden');
}
// Save game changes
function saveGameChanges() {
const id = document.getElementById('editGameId').value || Date.now().toString();
const name = document.getElementById('editGameName').value;
const mode = document.getElementById('editGameMode').value;
const playLink = document.getElementById('editPlayLink').value;
const scores = [
{
score: parseFloat(document.getElementById('editScore1').value) || 0,
date: document.getElementById('editDate1').value || new Date().toISOString().split('T')[0],
mode: document.getElementById('editMode1').value || ''
},
{
score: parseFloat(document.getElementById('editScore2').value) || 0,
date: document.getElementById('editDate2').value || new Date().toISOString().split('T')[0],
mode: document.getElementById('editMode2').value || ''
},
{
score: parseFloat(document.getElementById('editScore3').value) || 0,
date: document.getElementById('editDate3').value || new Date().toISOString().split('T')[0],
mode: document.getElementById('editMode3').value || ''
}
].filter(score => score.score > 0);
// Keep scores in their current order (sorted by user preference)
// Default icon if no upload
const icon = currentUploadIconId
? games.find(g => g.id === currentUploadIconId)?.icon
: 'https://cdn-icons-png.flaticon.com/512/3522/3522658.png';
if (document.getElementById('editGameId').value) {
// Update existing game
const index = games.findIndex(g => g.id === id);
if (index !== -1) {
games[index] = { id, name, mode, icon, scores, playLink };
}
} else {
// Add new game
games.push({ id, name, mode, icon, scores, playLink });
}
renderDashboard();
localStorage.setItem('gameDashboard', JSON.stringify(games));
gameEditModal.classList.add('hidden');
}
// Delete a game
function deleteGame(id) {
if (confirm('Are you sure you want to delete this game?')) {
games = games.filter(game => game.id !== id);
renderDashboard();
}
}
// Save all changes to localStorage
function saveAllChanges() {
localStorage.setItem('gameDashboard', JSON.stringify(games));
alert('Changes saved successfully!');
toggleEditMode();
}
// Handle icon upload
function handleIconUpload() {
const file = iconUpload.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
uploadPreview.src = e.target.result;
previewContainer.classList.remove('hidden');
};
reader.readAsDataURL(file);
}
}
// Confirm icon upload
function confirmIconUpload() {
const file = iconUpload.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
if (currentUploadIconId) {
const game = games.find(g => g.id === currentUploadIconId);
if (game) {
game.icon = e.target.result;
renderDashboard();
}
}
uploadModal.classList.add('hidden');
iconUpload.value = '';
previewContainer.classList.add('hidden');
};
reader.readAsDataURL(file);
}
// Initialize drag and drop for game cards
function initDragAndDrop() {
let draggedItem = null;
let dragOverItem = null;
// Add draggable attribute to all game cards
document.querySelectorAll('.draggable').forEach(item => {
item.setAttribute('draggable', 'true');
});
dashboardContainer.addEventListener('dragstart', (e) => {
if (e.target.classList.contains('draggable')) {
draggedItem = e.target;
e.target.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', e.target.innerHTML);
e.dataTransfer.setDragImage(e.target, 20, 20);
}
});
dashboardContainer.addEventListener('dragend', (e) => {
if (draggedItem) {
draggedItem.classList.remove('dragging');
document.querySelectorAll('.draggable').forEach(item => {
item.classList.remove('over');
});
draggedItem = null;
dragOverItem = null;
// Update games array order based on new DOM order
const newOrder = [...dashboardContainer.children].map(child => child.dataset.id);
games.sort((a, b) => newOrder.indexOf(a.id) - newOrder.indexOf(b.id));
// Save the new order
localStorage.setItem('gameDashboard', JSON.stringify(games));
}
});
dashboardContainer.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
const target = e.target.closest('.draggable');
if (!target || target === draggedItem) return;
// Remove highlight from previous item
if (dragOverItem && dragOverItem !== target) {
dragOverItem.classList.remove('over');
}
// Highlight new target
target.classList.add('over');
dragOverItem = target;
const rect = target.getBoundingClientRect();
const next = (e.clientY - rect.top) / (rect.bottom - rect.top) > 0.5;
if (next) {
dashboardContainer.insertBefore(draggedItem, target.nextSibling);
} else {
dashboardContainer.insertBefore(draggedItem, target);
}
});
dashboardContainer.addEventListener('dragleave', (e) => {
const target = e.target.closest('.draggable');
if (target && target !== draggedItem) {
target.classList.remove('over');
}
});
}
// Event listeners
toggleEditBtn.addEventListener('click', toggleEditMode);
addGameBtn.addEventListener('click', () => openEditModal());
saveChangesBtn.addEventListener('click', saveAllChanges);
iconUpload.addEventListener('change', handleIconUpload);
cancelUpload.addEventListener('click', () => {
uploadModal.classList.add('hidden');
iconUpload.value = '';
previewContainer.classList.add('hidden');
});
confirmUpload.addEventListener('click', confirmIconUpload);
cancelGameEdit.addEventListener('click', () => gameEditModal.classList.add('hidden'));
saveGameEdit.addEventListener('click', saveGameChanges);
uploadGameIconBtn.addEventListener('click', () => uploadModal.classList.remove('hidden'));
// Export data to JSON file
function exportData() {
const dataStr = JSON.stringify(games, null, 2);
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
const exportFileDefaultName = 'high-scores-backup.json';
const linkElement = document.createElement('a');
linkElement.setAttribute('href', dataUri);
linkElement.setAttribute('download', exportFileDefaultName);
linkElement.click();
}
// Import data from JSON file
function importData() {
document.getElementById('importFile').click();
}
// Handle imported file
function handleFileImport(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
try {
const importedGames = JSON.parse(e.target.result);
if (Array.isArray(importedGames)) {
if (confirm('This will replace all current games. Continue?')) {
games = importedGames;
renderDashboard();
localStorage.setItem('gameDashboard', JSON.stringify(games));
alert('Import successful!');
}
} else {
alert('Invalid file format. Expected an array of games.');
}
} catch (error) {
alert('Error parsing JSON file: ' + error.message);
}
e.target.value = ''; // Reset file input
};
reader.readAsText(file);
}
// Dark mode toggle
const darkModeToggle = document.getElementById('darkModeToggle');
let darkMode = localStorage.getItem('darkMode') === 'true';
function toggleDarkMode() {
darkMode = !darkMode;
document.body.classList.toggle('dark-mode', darkMode);
localStorage.setItem('darkMode', darkMode);
if (darkMode) {
darkModeToggle.innerHTML = '<i class="fas fa-sun"></i><span>Light Mode</span>';
} else {
darkModeToggle.innerHTML = '<i class="fas fa-moon"></i><span>Dark Mode</span>';
}
}
// Initialize dark mode
if (darkMode) {
document.body.classList.add('dark-mode');
darkModeToggle.innerHTML = '<i class="fas fa-sun"></i><span>Light Mode</span>';
}
darkModeToggle.addEventListener('click', toggleDarkMode);
// Event listeners for export/import
document.getElementById('exportBtn').addEventListener('click', exportData);
document.getElementById('importBtn').addEventListener('click', importData);
document.getElementById('importFile').addEventListener('change', handleFileImport);
// Sort buttons event listeners
document.getElementById('sortLowToHigh').addEventListener('click', () => {
const score1 = document.getElementById('editScore1').value;
const score2 = document.getElementById('editScore2').value;
const score3 = document.getElementById('editScore3').value;
const mode1 = document.getElementById('editMode1').value;
const mode2 = document.getElementById('editMode2').value;
const mode3 = document.getElementById('editMode3').value;
const date1 = document.getElementById('editDate1').value;
const date2 = document.getElementById('editDate2').value;
const date3 = document.getElementById('editDate3').value;
const scores = [
{score: parseFloat(score1) || 0, mode: mode1, date: date1},
{score: parseFloat(score2) || 0, mode: mode2, date: date2},
{score: parseFloat(score3) || 0, mode: mode3, date: date3}
].filter(s => s.score > 0);
scores.sort((a, b) => a.score - b.score);
// Update the fields with sorted values
document.getElementById('editScore1').value = scores[0]?.score || '';
document.getElementById('editMode1').value = scores[0]?.mode || '';
document.getElementById('editDate1').value = scores[0]?.date || '';
document.getElementById('editScore2').value = scores[1]?.score || '';
document.getElementById('editMode2').value = scores[1]?.mode || '';
document.getElementById('editDate2').value = scores[1]?.date || '';
document.getElementById('editScore3').value = scores[2]?.score || '';
document.getElementById('editMode3').value = scores[2]?.mode || '';
document.getElementById('editDate3').value = scores[2]?.date || '';
});
document.getElementById('sortHighToLow').addEventListener('click', () => {
const score1 = document.getElementById('editScore1').value;
const score2 = document.getElementById('editScore2').value;
const score3 = document.getElementById('editScore3').value;
const mode1 = document.getElementById('editMode1').value;
const mode2 = document.getElementById('editMode2').value;
const mode3 = document.getElementById('editMode3').value;
const date1 = document.getElementById('editDate1').value;
const date2 = document.getElementById('editDate2').value;
const date3 = document.getElementById('editDate3').value;
const scores = [
{score: parseFloat(score1) || 0, mode: mode1, date: date1},
{score: parseFloat(score2) || 0, mode: mode2, date: date2},
{score: parseFloat(score3) || 0, mode: mode3, date: date3}
].filter(s => s.score > 0);
scores.sort((a, b) => b.score - a.score);
// Update the fields with sorted values
document.getElementById('editScore1').value = scores[0]?.score || '';
document.getElementById('editMode1').value = scores[0]?.mode || '';
document.getElementById('editDate1').value = scores[0]?.date || '';
document.getElementById('editScore2').value = scores[1]?.score || '';
document.getElementById('editMode2').value = scores[1]?.mode || '';
document.getElementById('editDate2').value = scores[1]?.date || '';
document.getElementById('editScore3').value = scores[2]?.score || '';
document.getElementById('editMode3').value = scores[2]?.mode || '';
document.getElementById('editDate3').value = scores[2]?.date || '';
});
// Initialize the dashboard
renderDashboard();
initDragAndDrop();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Honda219/high-score-dashboard" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>