perbaikan

This commit is contained in:
aldo 2025-12-15 23:43:48 +07:00
parent 8ae4f0989a
commit 4f2f7ae38e
4 changed files with 214 additions and 98 deletions

View File

@ -156,7 +156,7 @@ if (!isset($_SESSION['username'])) {
#timer-label { #timer-label {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
color: #333; color: darkslategray;
font-family: monospace; font-family: monospace;
margin-top: 2px; margin-top: 2px;
} }
@ -314,7 +314,7 @@ if (!isset($_SESSION['username'])) {
.modal-title { .modal-title {
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
color: #333; color: darkslategray;
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -329,7 +329,7 @@ if (!isset($_SESSION['username'])) {
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
margin-bottom: 25px; margin-bottom: 25px;
background-color: #f0f8ff; background-color: aliceblue;
padding: 10px; padding: 10px;
border-radius: 10px; border-radius: 10px;
} }
@ -361,8 +361,8 @@ if (!isset($_SESSION['username'])) {
border: 2px solid var(--primary-color); border: 2px solid var(--primary-color);
} }
.btn-grey-modal { .btn-grey-modal {
background-color: #e0e0e0; background-color: gainsboro;
color: #555; color: dimgray;
} }
@keyframes popIn { @keyframes popIn {
@ -370,6 +370,55 @@ if (!isset($_SESSION['username'])) {
to { transform: scale(1); opacity: 1; } to { transform: scale(1); opacity: 1; }
} }
/* ... existing styles ... */
.game-layout {
display: flex;
gap: 40px;
align-items: flex-start;
}
.game-main {
display: flex;
flex-direction: column;
align-items: center;
}
.game-sidebar {
width: 250px;
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
padding: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
display: flex;
flex-direction: column;
}
.mini-leaderboard-title {
text-align: center;
font-weight: bold;
margin-bottom: 10px;
color: darkslategray;
border-bottom: 2px solid lightgray;
padding-bottom: 5px;
}
.mini-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.mini-table th, .mini-table td {
padding: 5px;
text-align: left;
border-bottom: 1px solid whitesmoke;
}
.mini-table th { color: gray; font-weight: bold; }
.mini-table tr:last-child td { border-bottom: none; }
.rank-1 { color: gold; font-weight: bold; }
.rank-2 { color: silver; font-weight: bold; }
.rank-3 { color: chocolate; font-weight: bold; }
</style> </style>
</head> </head>
@ -395,6 +444,9 @@ if (!isset($_SESSION['username'])) {
</div> </div>
<div id="screen-game" class="screen"> <div id="screen-game" class="screen">
<div class="game-layout">
<!-- Main Game Area -->
<div class="game-main">
<div class="game-header"> <div class="game-header">
<button class="btn-back-icon" onclick="backToMenu()">&#8592;</button> <button class="btn-back-icon" onclick="backToMenu()">&#8592;</button>
@ -428,6 +480,26 @@ if (!isset($_SESSION['username'])) {
<div class="tool-btn btn-delete" onclick="deleteNumber()"><span>🗑</span> HAPUS</div> <div class="tool-btn btn-delete" onclick="deleteNumber()"><span>🗑</span> HAPUS</div>
<div id="btn-hint" class="tool-btn btn-hint" onclick="getHint()"><span>💡</span> BANTUAN (3)</div> <div id="btn-hint" class="tool-btn btn-hint" onclick="getHint()"><span>💡</span> BANTUAN (3)</div>
</div> </div>
</div>
<!-- Right Sidebar: Leaderboard -->
<div class="game-sidebar">
<div class="mini-leaderboard-title">🏆 Top <span id="lb-diff-name">Easy</span></div>
<table class="mini-table">
<thead>
<tr>
<th width="10%">#</th>
<th>Player</th>
<th>Time</th>
</tr>
</thead>
<tbody id="mini-lb-body">
<!-- Loaded via JS -->
<tr><td colspan="3" align="center">Loading...</td></tr>
</tbody>
</table>
</div>
</div>
<div id="modal-game-over" class="modal-overlay"> <div id="modal-game-over" class="modal-overlay">
<div class="modal-content"> <div class="modal-content">
@ -501,8 +573,52 @@ if (!isset($_SESSION['username'])) {
else if (difficulty === 'hard') { holes = 50; label = "SULIT"; } else if (difficulty === 'hard') { holes = 50; label = "SULIT"; }
document.getElementById('difficulty-label').innerText = label; document.getElementById('difficulty-label').innerText = label;
document.getElementById('lb-diff-name').innerText = label; // Update sidebar title
switchScreen('screen-game'); switchScreen('screen-game');
newGame(holes); newGame(holes);
loadLeaderboard(difficulty); // Fetch leaderboard
}
// --- Leaderboard Fetch Logic ---
function loadLeaderboard(diff) {
let tbody = document.getElementById('mini-lb-body');
tbody.innerHTML = '<tr><td colspan="3" align="center">Loading...</td></tr>';
fetch(`leaderboard.php?api=true&difficulty=${diff}`)
.then(res => res.json())
.then(data => {
tbody.innerHTML = '';
if (data.length === 0) {
tbody.innerHTML = '<tr><td colspan="3" align="center">Belum ada data</td></tr>';
return;
}
data.forEach((row, index) => {
let rank = index + 1;
let m = Math.floor(row.time_seconds / 60);
let s = row.time_seconds % 60;
let timeStr = (m < 10 ? "0"+m : m) + ":" + (s < 10 ? "0"+s : s);
let rankClass = '';
if (rank === 1) rankClass = 'rank-1';
else if (rank === 2) rankClass = 'rank-2';
else if (rank === 3) rankClass = 'rank-3';
let tr = `
<tr>
<td class="${rankClass}">#${rank}</td>
<td>${row.username}</td>
<td>${timeStr}</td>
</tr>
`;
tbody.innerHTML += tr;
});
})
.catch(err => {
console.error(err);
tbody.innerHTML = '<tr><td colspan="3" align="center" style="color:red">Error</td></tr>';
});
} }
function newGame(holesCount) { function newGame(holesCount) {
@ -736,6 +852,8 @@ if (!isset($_SESSION['username'])) {
document.getElementById("tools-row").style.display = "none"; document.getElementById("tools-row").style.display = "none";
document.getElementById("numpad-row").style.display = "none"; document.getElementById("numpad-row").style.display = "none";
loadLeaderboard(currentDifficulty);
return true; return true;
} }
@ -799,7 +917,7 @@ function saveScore() {
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded" "Content-Type": "application/x-www-form-urlencoded"
}, },
body: 'difficulty=${currentDifficulty}&time=${secondsElapsed}' body: `difficulty=${currentDifficulty}&time=${secondsElapsed}`
}) })
.then(res => res.text()) .then(res => res.text())
.then(data => console.log("SAVE SCORE:", data)) .then(data => console.log("SAVE SCORE:", data))

View File

@ -1,7 +1,7 @@
<?php <?php
require_once 'db.php'; require_once 'db.php';
// Auto-create table if it doesn't exist
try { try {
$checkTable = $conn->query("SHOW TABLES LIKE 'leaderboard_sudoku'"); $checkTable = $conn->query("SHOW TABLES LIKE 'leaderboard_sudoku'");
if ($checkTable->rowCount() == 0) { if ($checkTable->rowCount() == 0) {
@ -16,11 +16,14 @@ try {
$conn->exec($createSql); $conn->exec($createSql);
} }
} catch (PDOException $e) { } catch (PDOException $e) {
// Fail silently or log, but attempting to continue might show empty leaderboard instead of crash
} }
// Helper function to get top 10 by difficulty
function getLeaderboard($conn, $difficulty) { function getLeaderboard($conn, $difficulty) {
$allowed = ['easy', 'medium', 'hard'];
if (!in_array($difficulty, $allowed)) {
return [];
}
$sql = " $sql = "
SELECT username, time_seconds, created_at SELECT username, time_seconds, created_at
FROM leaderboard_sudoku FROM leaderboard_sudoku
@ -33,7 +36,13 @@ function getLeaderboard($conn, $difficulty) {
return $stmt->fetchAll(PDO::FETCH_ASSOC); return $stmt->fetchAll(PDO::FETCH_ASSOC);
} }
// Fetch data for each level if (isset($_GET['api']) && isset($_GET['difficulty'])) {
header('Content-Type: application/json');
$data = getLeaderboard($conn, $_GET['difficulty']);
echo json_encode($data);
exit;
}
$easyData = getLeaderboard($conn, 'easy'); $easyData = getLeaderboard($conn, 'easy');
$mediumData = getLeaderboard($conn, 'medium'); $mediumData = getLeaderboard($conn, 'medium');
$hardData = getLeaderboard($conn, 'hard'); $hardData = getLeaderboard($conn, 'hard');
@ -48,7 +57,8 @@ $hardData = getLeaderboard($conn, 'hard');
<style> <style>
body { body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #121212; background: url("Background.jpg") no-repeat center center fixed;
background-size: cover;
color: white; color: white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -63,13 +73,13 @@ $hardData = getLeaderboard($conn, 'hard');
.leaderboard-container { .leaderboard-container {
width: 100%; width: 100%;
max-width: 500px; max-width: 500px;
background: #1e1e1e; background: white;
color: darkslategray;
border-radius: 12px; border-radius: 12px;
overflow: hidden; overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.5); box-shadow: 0 4px 15px rgba(0,0,0,0.2);
} }
/* Tabs Navigation */
.tabs { .tabs {
display: flex; display: flex;
width: 100%; width: 100%;
@ -82,37 +92,35 @@ $hardData = getLeaderboard($conn, 'hard');
cursor: pointer; cursor: pointer;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
color: #ccc; color: dimgray;
background-color: #2c2c2c; background-color: whitesmoke;
transition: 0.3s; transition: 0.3s;
border-bottom: 4px solid transparent; border-bottom: 4px solid lightgray;
} }
.tab-btn:hover { .tab-btn:hover {
background-color: #333; background-color: gainsboro;
color: white; color: black;
} }
/* Active Tab Styling - Colors requested: Easy=Green, Medium=Yellow, Hard=Blue */
.tab-btn.active.easy { .tab-btn.active.easy {
background-color: #1e1e1e; background-color: white;
color: #4CAF50; /* Green */ color: limegreen;
border-bottom-color: #4CAF50; border-bottom-color: limegreen;
} }
.tab-btn.active.medium { .tab-btn.active.medium {
background-color: #1e1e1e; background-color: white;
color: #2196F3; /* Blue */ color: dodgerblue;
border-bottom-color: #2196F3; border-bottom-color: dodgerblue;
} }
.tab-btn.active.hard { .tab-btn.active.hard {
background-color: #1e1e1e; background-color: white;
color: #f44336; /* Red */ color: red;
border-bottom-color: #f44336; border-bottom-color: red;
} }
/* Content Sections */
.tab-content { .tab-content {
display: none; /* Hidden by default */ display: none;
padding: 20px; padding: 20px;
animation: fadeIn 0.4s; animation: fadeIn 0.4s;
} }
@ -130,11 +138,11 @@ $hardData = getLeaderboard($conn, 'hard');
th, td { th, td {
text-align: left; text-align: left;
padding: 12px; padding: 12px;
border-bottom: 1px solid #333; border-bottom: 1px solid whitesmoke;
} }
th { th {
color: #888; color: gray;
font-size: 14px; font-size: 14px;
text-transform: uppercase; text-transform: uppercase;
} }
@ -143,25 +151,27 @@ $hardData = getLeaderboard($conn, 'hard');
border-bottom: none; border-bottom: none;
} }
/* Rank Colors */
.rank-1 { color: gold; font-weight: bold; } .rank-1 { color: gold; font-weight: bold; }
.rank-2 { color: silver; font-weight: bold; } .rank-2 { color: silver; font-weight: bold; }
.rank-3 { color: #cd7f32; font-weight: bold; } /* Bronze */ .rank-3 { color: chocolate; font-weight: bold; }
.back-btn { .back-btn {
margin-top: 20px; margin-top: 20px;
padding: 10px 20px; padding: 10px 20px;
background-color: #333; background-color: white;
color: white; color: darkslategray;
border: none; border: none;
border-radius: 20px; border-radius: 20px;
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
font-weight: bold; font-weight: bold;
transition: 0.2s; transition: 0.2s;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
} }
.back-btn:hover { .back-btn:hover {
background-color: #444; background-color: whitesmoke;
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
} }
@keyframes fadeIn { @keyframes fadeIn {
@ -175,28 +185,23 @@ $hardData = getLeaderboard($conn, 'hard');
<h2>🏆 Leaderboard</h2> <h2>🏆 Leaderboard</h2>
<div class="leaderboard-container"> <div class="leaderboard-container">
<!-- Tabs -->
<div class="tabs"> <div class="tabs">
<button class="tab-btn easy active" onclick="openTab('easy')">MUDAH</button> <button class="tab-btn easy active" onclick="openTab('easy')">MUDAH</button>
<button class="tab-btn medium" onclick="openTab('medium')">SEDANG</button> <button class="tab-btn medium" onclick="openTab('medium')">SEDANG</button>
<button class="tab-btn hard" onclick="openTab('hard')">SULIT</button> <button class="tab-btn hard" onclick="openTab('hard')">SULIT</button>
</div> </div>
<!-- Easy Section -->
<div id="easy" class="tab-content active"> <div id="easy" class="tab-content active">
<h3 style="color: #4CAF50; margin-top: 0;">Level Mudah</h3> <h3 style="color: limegreen; margin-top: 0;">Level Mudah</h3>
<?php renderTable($easyData); ?> <?php renderTable($easyData); ?>
</div> </div>
<!-- Medium Section -->
<div id="medium" class="tab-content"> <div id="medium" class="tab-content">
<h3 style="color: #2196F3; margin-top: 0;">Level Sedang</h3> <h3 style="color: dodgerblue; margin-top: 0;">Level Sedang</h3>
<?php renderTable($mediumData); ?> <?php renderTable($mediumData); ?>
</div> </div>
<!-- Hard Section -->
<div id="hard" class="tab-content"> <div id="hard" class="tab-content">
<h3 style="color: #f44336; margin-top: 0;">Level Sulit</h3> <h3 style="color: red; margin-top: 0;">Level Sulit</h3>
<?php renderTable($hardData); ?> <?php renderTable($hardData); ?>
</div> </div>
</div> </div>
@ -205,19 +210,13 @@ $hardData = getLeaderboard($conn, 'hard');
<script> <script>
function openTab(difficulty) { function openTab(difficulty) {
// Hide all tab contents
const contents = document.querySelectorAll('.tab-content'); const contents = document.querySelectorAll('.tab-content');
contents.forEach(content => content.classList.remove('active')); contents.forEach(content => content.classList.remove('active'));
// Deactivate all buttons
const buttons = document.querySelectorAll('.tab-btn'); const buttons = document.querySelectorAll('.tab-btn');
buttons.forEach(btn => btn.classList.remove('active')); buttons.forEach(btn => btn.classList.remove('active'));
// Activate specific tab and button
document.getElementById(difficulty).classList.add('active'); document.getElementById(difficulty).classList.add('active');
// Find the button that calls this function (or match by class) needs logic if I don't pass 'this'
// Using querySelector to find the button with specific class for simplicity in this context
document.querySelector(`.tab-btn.${difficulty}`).classList.add('active'); document.querySelector(`.tab-btn.${difficulty}`).classList.add('active');
} }
</script> </script>
@ -226,7 +225,6 @@ $hardData = getLeaderboard($conn, 'hard');
</html> </html>
<?php <?php
// Helper to render table
function renderTable($data) { function renderTable($data) {
if (count($data) === 0) { if (count($data) === 0) {
echo "<p style='color: gray; text-align: center; padding: 20px;'>Belum ada data.</p>"; echo "<p style='color: gray; text-align: center; padding: 20px;'>Belum ada data.</p>";

View File

@ -54,14 +54,14 @@ if (isset($_POST['login'])) {
<title>Login</title> <title>Login</title>
<style> <style>
/* Style disamakan persis dengan register.php Anda */ /* Style disamakan persis dengan register.php Anda */
body { font-family: Arial; background:#eef2f7; display:flex; height:100vh; justify-content:center; align-items:center; margin:0; } body { font-family: Arial; background:aliceblue; display:flex; height:100vh; justify-content:center; align-items:center; margin:0; }
.card { width:350px; background:white; padding:20px; border-radius:10px; box-shadow:0 6px 20px rgba(0,0,0,0.1); } .card { width:350px; background:white; padding:20px; border-radius:10px; box-shadow:0 6px 20px rgba(0,0,0,0.1); }
.input { width:100%; padding:10px; margin:8px 0; border:1px solid #ccc; border-radius:8px; box-sizing: border-box; } .input { width:100%; padding:10px; margin:8px 0; border:1px solid lightgray; border-radius:8px; box-sizing: border-box; }
.btn { width:100%; padding:12px; background:#007bff; color:white; border:none; border-radius:8px; cursor:pointer; } .btn { width:100%; padding:12px; background:dodgerblue; color:white; border:none; border-radius:8px; cursor:pointer; }
.btn:hover { background:#0056b3; } .btn:hover { background:mediumblue; }
.err { color:#d00000; margin-bottom:10px; text-align:center; background: #ffe6e6; padding: 5px; border-radius: 5px;} .err { color:firebrick; margin-bottom:10px; text-align:center; background: mistyrose; padding: 5px; border-radius: 5px;}
.link { text-align:center; margin-top:10px; } .link { text-align:center; margin-top:10px; }
a { text-decoration: none; color: #007bff; } a { text-decoration: none; color: dodgerblue; }
</style> </style>
</head> </head>
<body> <body>

View File

@ -51,16 +51,16 @@ if (isset($_POST['register'])) {
<head> <head>
<title>Daftar Akun Baru</title> <title>Daftar Akun Baru</title>
<style> <style>
body { font-family: Arial; background:#eef2f7; display:flex; height:100vh; justify-content:center; align-items:center; margin:0; } body { font-family: Arial; background:aliceblue; display:flex; height:100vh; justify-content:center; align-items:center; margin:0; }
.card { width:350px; background:white; padding:20px; border-radius:10px; box-shadow:0 6px 20px rgba(0,0,0,0.1); } .card { width:350px; background:white; padding:20px; border-radius:10px; box-shadow:0 6px 20px rgba(0,0,0,0.1); }
.input { width:100%; padding:10px; margin:8px 0; border:1px solid #ccc; border-radius:8px; box-sizing: border-box; } .input { width:100%; padding:10px; margin:8px 0; border:1px solid lightgray; border-radius:8px; box-sizing: border-box; }
.btn { width:100%; padding:12px; background:#28a745; color:white; border:none; border-radius:8px; cursor:pointer; font-weight: bold;} .btn { width:100%; padding:12px; background:forestgreen; color:white; border:none; border-radius:8px; cursor:pointer; font-weight: bold;}
.btn:hover { background:#218838; } .btn:hover { background:darkgreen; }
.err { color:#721c24; margin-bottom:10px; text-align:center; background: #f8d7da; padding: 10px; border-radius: 5px; border: 1px solid #f5c6cb; font-size: 14px;} .err { color:darkred; margin-bottom:10px; text-align:center; background: mistyrose; padding: 10px; border-radius: 5px; border: 1px solid pink; font-size: 14px;}
.success { color:#155724; margin-bottom:10px; text-align:center; background: #d4edda; padding: 10px; border-radius: 5px; border: 1px solid #c3e6cb;} .success { color:darkgreen; margin-bottom:10px; text-align:center; background: honeydew; padding: 10px; border-radius: 5px; border: 1px solid lightgreen;}
.link { text-align:center; margin-top:10px; font-size: 14px; color: #666; } .link { text-align:center; margin-top:10px; font-size: 14px; color: gray; }
a { text-decoration: none; color: #007bff; } a { text-decoration: none; color: dodgerblue; }
h2 { text-align: center; margin-top: 0; color: #333; } h2 { text-align: center; margin-top: 0; color: darkslategray; }
p { text-align:center; color:gray; font-size: 14px; margin-bottom: 20px; } p { text-align:center; color:gray; font-size: 14px; margin-bottom: 20px; }
</style> </style>
</head> </head>