+ Grafica

This commit is contained in:
Flatlogic Bot 2025-09-28 23:26:12 +00:00
parent 188419fc12
commit 6972ed7543
9 changed files with 736 additions and 697 deletions

268
admin.php
View File

@ -47,9 +47,9 @@ function create_puzzle_pieces($source_image_path, $puzzle_id, $pieces_count) {
// Grid dimensions // Grid dimensions
$cols = 0; $cols = 0;
$rows = 0; $rows = 0;
if ($pieces_count == 16) { $cols = 4; $rows = 4; } if ($pieces_count == 16) { $cols = 4; $rows = 4; }
elseif ($pieces_count == 32) { $cols = 8; $rows = 4; } elseif ($pieces_count == 32) { $cols = 8; $rows = 4; }
elseif ($pieces_count == 64) { $cols = 8; $rows = 8; } elseif ($pieces_count == 64) { $cols = 8; $rows = 8; }
else { else {
error_log("Invalid pieces count: " . $pieces_count); error_log("Invalid pieces count: " . $pieces_count);
return false; return false;
@ -104,8 +104,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_puzzle'])) {
$upload_path = $upload_dir . $safe_filename; $upload_path = $upload_dir . $safe_filename;
if (move_uploaded_file($image_file['tmp_name'], $upload_path)) { if (move_uploaded_file($image_file['tmp_name'], $upload_path)) {
$stmt = $pdo->prepare('INSERT INTO puzzles (name, original_image, file_name, pieces, is_public, created_at) VALUES (?, ?, ?, ?, ?, NOW())'); $stmt = $pdo->prepare('INSERT INTO puzzles (name, file_name, pieces, is_public, is_admin_upload) VALUES (?, ?, ?, ?, 1)');
$stmt->execute([$puzzle_name, $safe_filename, $safe_filename, $pieces, $is_public]); $stmt->execute([$puzzle_name, $safe_filename, $pieces, $is_public]);
$puzzle_id = $pdo->lastInsertId(); $puzzle_id = $pdo->lastInsertId();
create_puzzle_pieces($upload_path, $puzzle_id, $pieces); create_puzzle_pieces($upload_path, $puzzle_id, $pieces);
@ -123,12 +123,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_puzzle'])) {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_puzzle'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_puzzle'])) {
$puzzle_id_to_delete = $_POST['puzzle_id']; $puzzle_id_to_delete = $_POST['puzzle_id'];
$stmt = $pdo->prepare('SELECT original_image FROM puzzles WHERE id = ?'); $stmt = $pdo->prepare('SELECT file_name FROM puzzles WHERE id = ?');
$stmt->execute([$puzzle_id_to_delete]); $stmt->execute([$puzzle_id_to_delete]);
$puzzle = $stmt->fetch(PDO::FETCH_ASSOC); $puzzle = $stmt->fetch(PDO::FETCH_ASSOC);
if ($puzzle) { if ($puzzle) {
$original_image_path = __DIR__ . '/uploads/' . $puzzle['original_image']; $original_image_path = __DIR__ . '/uploads/' . $puzzle['file_name'];
if (file_exists($original_image_path)) { if (file_exists($original_image_path)) {
unlink($original_image_path); unlink($original_image_path);
} }
@ -155,168 +155,132 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_puzzle'])) {
} }
$puzzles = $pdo->query('SELECT id, name, original_image, pieces, is_public, created_at FROM puzzles ORDER BY created_at DESC')->fetchAll(PDO::FETCH_ASSOC); $puzzles = $pdo->query('SELECT id, name, file_name, pieces, is_public, created_at FROM puzzles ORDER BY created_at DESC')->fetchAll(PDO::FETCH_ASSOC);
// Fetch users // Fetch users
$users = $pdo->query('SELECT id, username, email, created_at FROM users ORDER BY created_at DESC')->fetchAll(PDO::FETCH_ASSOC); $users = $pdo->query('SELECT id, username, email, created_at FROM users ORDER BY created_at DESC')->fetchAll(PDO::FETCH_ASSOC);
$page_title = 'Pannello di Amministrazione';
require_once 'includes/header.php';
?> ?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pannello di Amministrazione</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.upload-form {
background-color: #f8f9fa;
padding: 2rem;
border-radius: 0.5rem;
margin-bottom: 2rem;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="#">Admin Puzzle</a>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<div class="container mt-5"> <main class="container mt-5">
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])):
<div class="alert alert-success">Puzzle aggiunto con successo!</div> ?><div class="alert alert-success">Puzzle aggiunto con successo!</div>
<?php endif; ?> <?php endif; ?>
<?php if (isset($_GET['deleted'])): ?> <?php if (isset($_GET['deleted'])):
<div class="alert alert-info">Puzzle eliminato con successo.</div> ?><div class="alert alert-info">Puzzle eliminato con successo.</div>
<?php endif; ?> <?php endif; ?>
<?php if (isset($_GET['error'])): ?> <?php if (isset($_GET['error'])):
<div class="alert alert-danger">Errore durante l'upload. Controlla i dati e riprova.</div> ?><div class="alert alert-danger">Errore durante l\'upload. Controlla i dati e riprova.</div>
<?php endif; ?> <?php endif; ?>
<!-- Upload Form --> <!-- Upload Form -->
<div class="upload-form"> <div class="card p-4 mb-4">
<h2 class="mb-4">Aggiungi Nuovo Puzzle</h2> <h2 class="mb-4">Aggiungi Nuovo Puzzle</h2>
<form action="admin.php" method="POST" enctype="multipart/form-data"> <form action="admin.php" method="POST" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label for="puzzle_name" class="form-label">Nome del Puzzle</label> <label for="puzzle_name" class="form-label">Nome del Puzzle</label>
<input type="text" class="form-control" id="puzzle_name" name="puzzle_name" required> <input type="text" class="form-control" id="puzzle_name" name="puzzle_name" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="puzzle_image" class="form-label">Immagine</label> <label for="puzzle_image" class="form-label">Immagine</label>
<input type="file" class="form-control" id="puzzle_image" name="puzzle_image" accept="image/jpeg, image/png, image/gif" required> <input type="file" class="form-control" id="puzzle_image" name="puzzle_image" accept="image/jpeg, image/png, image/gif" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="pieces" class="form-label">Numero di Pezzi</label> <label for="pieces" class="form-label">Numero di Pezzi</label>
<select class="form-select" id="pieces" name="pieces"> <select class="form-select" id="pieces" name="pieces">
<option value="16">16 (4x4)</option> <option value="16">16 (4x4)</option>
<option value="32">32 (8x4)</option> <option value="32">32 (8x4)</option>
<option value="64">64 (8x8)</option> <option value="64">64 (8x8)</option>
</select> </select>
</div> </div>
<div class="form-check mb-3"> <div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="is_public" name="is_public" value="1" checked> <input class="form-check-input" type="checkbox" id="is_public" name="is_public" value="1" checked>
<label class="form-check-label" for="is_public"> <label class="form-check-label" for="is_public">
Rendi Pubblico Rendi Pubblico
</label> </label>
</div> </div>
<button type="submit" name="add_puzzle" class="btn btn-primary">Aggiungi Puzzle</button> <button type="submit" name="add_puzzle" class="btn btn-primary">Aggiungi Puzzle</button>
</form> </form>
</div> </div>
<h1 class="mb-4">Gestione Puzzle</h1> <h1 class="mb-4">Gestione Puzzle</h1>
<div class="table-responsive"> <div class="table-responsive card p-3">
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered table-dark">
<thead class="table-dark"> <thead>
<tr>
<th>ID</th>
<th>Nome</th>
<th>Immagine</th>
<th>Pezzi</th>
<th>Pubblico</th>
<th>Creato il</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php if (empty($puzzles)):
?><tr class="text-center"><td colspan="7">Nessun puzzle trovato.</td></tr>
<?php else:
?><?php foreach ($puzzles as $puzzle):
$image_path = __DIR__ . '/uploads/' . $puzzle['file_name'];
if (file_exists($image_path)) {
$imageUrl = 'uploads/' . htmlspecialchars($puzzle['file_name']) . '?v=' . filemtime($image_path);
} else {
$imageUrl = 'assets/images/placeholder.png';
}
?><tr >
<td><?php echo htmlspecialchars($puzzle['id']); ?></td>
<td><a href="puzzle.php?id=<?php echo htmlspecialchars($puzzle['id']); ?>" target="_blank"><?php echo htmlspecialchars($puzzle['name']); ?></a></td>
<td><img src="<?php echo $imageUrl; ?>" alt="Puzzle" width="100" class="rounded"></td>
<td><?php echo htmlspecialchars($puzzle['pieces']); ?></td>
<td><?php echo $puzzle['is_public'] ? 'Sì' : 'No'; ?></td>
<td><?php echo htmlspecialchars($puzzle['created_at']); ?></td>
<td>
<form method="POST" action="admin.php" onsubmit="return confirm('Sei sicuro di voler eliminare questo puzzle? L\\'azione è irreversibile.');">
<input type="hidden" name="puzzle_id" value="<?php echo htmlspecialchars($puzzle['id']); ?>">
<button type="submit" name="delete_puzzle" class="btn btn-danger btn-sm">Elimina</button>
</form>
</td>
</tr>
<?php endforeach; ?><?php endif; ?>
</tbody>
</table>
</div>
<!-- User Management Section -->
<div class="mt-5">
<h1 class="mb-4">Gestione Utenti</h1>
<div class="table-responsive card p-3">
<table class="table table-striped table-bordered table-dark">
<thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Nome</th> <th>Username</th>
<th>Immagine</th> <th>Email</th>
<th>Pezzi</th> <th>Registrato il</th>
<th>Pubblico</th>
<th>Creato il</th>
<th>Azioni</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php if (empty($puzzles)): ?> <?php if (empty($users)):
<tr> ?><tr class="text-center"><td colspan="4">Nessun utente trovato.</td></tr>
<td colspan="7" class="text-center">Nessun puzzle trovato.</td> <?php else:
</tr> ?><?php foreach ($users as $user):
<?php else: ?> ?><tr >
<?php foreach ($puzzles as $puzzle): <td><?php echo htmlspecialchars($user['id']); ?></td>
$image_path = __DIR__ . '/uploads/' . $puzzle['original_image']; <td><?php echo htmlspecialchars($user['username']); ?></td>
if (file_exists($image_path)) { <td><?php echo htmlspecialchars($user['email']); ?></td>
$imageUrl = 'uploads/' . htmlspecialchars($puzzle['original_image']) . '?v=' . filemtime($image_path); <td><?php echo htmlspecialchars($user['created_at']); ?></td>
} else {
$imageUrl = 'assets/images/placeholder.png';
}
?>
<tr>
<td><?php echo htmlspecialchars($puzzle['id']); ?></td>
<td><a href="puzzle.php?id=<?php echo htmlspecialchars($puzzle['id']); ?>" target="_blank"><?php echo htmlspecialchars($puzzle['name']); ?></a></td>
<td><img src="<?php echo $imageUrl; ?>" alt="Puzzle" width="100"></td>
<td><?php echo htmlspecialchars($puzzle['pieces']); ?></td>
<td><?php echo $puzzle['is_public'] ? 'Sì' : 'No'; ?></td>
<td><?php echo htmlspecialchars($puzzle['created_at']); ?></td>
<td>
<form method="POST" action="admin.php" onsubmit="return confirm('Sei sicuro di voler eliminare questo puzzle? L'azione è irreversibile.');">
<input type="hidden" name="puzzle_id" value="<?php echo htmlspecialchars($puzzle['id']); ?>">
<button type="submit" name="delete_puzzle" class="btn btn-danger btn-sm">Elimina</button>
</form>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?><?php endif; ?>
<?php endif; ?>
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- User Management Section -->
<div class="mt-5">
<h1 class="mb-4">Gestione Utenti</h1>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Registrato il</th>
</tr>
</thead>
<tbody>
<?php if (empty($users)): ?>
<tr>
<td colspan="4" class="text-center">Nessun utente trovato.</td>
</tr>
<?php else: ?>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo htmlspecialchars($user['id']); ?></td>
<td><?php echo htmlspecialchars($user['username']); ?></td>
<td><?php echo htmlspecialchars($user['email']); ?></td>
<td><?php echo htmlspecialchars($user['created_at']); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div> </div>
<footer class="text-center mt-5 py-3 bg-light"> </main>
<p>&copy; <?php echo date("Y"); ?> Puzzle Game</p>
</footer> <?php require_once 'includes/footer.php'; ?>
</body>
</html>

View File

@ -1,114 +1,193 @@
/* IMPORT TYPOGRAPHY */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Orbitron:wght@400;600;700;900&display=swap');
/* PALETTE */
:root { :root {
--bg-slate-900: #0F172A; --bg-primary: #0F172A; /* slate-900 - Deep space background */
--bg-slate-800: #1E293B; --bg-secondary: #1E293B; /* slate-800 - Card backgrounds */
--text-cyan-400: #22D3EE; --accent-primary: #06B6D4; /* cyan-500 - CTAs and highlights */
--bg-cyan-500: #06B6D4; --accent-glow: #22D3EE; /* cyan-400 - Hover states */
--border-slate-700: #334155; --text-primary: #F8FAFC; /* slate-50 - Primary text */
--text-slate-200: #E2E8F0; --text-secondary: #94A3B8; /* slate-400 - Secondary text */
--text-slate-400: #94A3B8;
} }
/* GENERAL STYLES */
body { body {
background-color: var(--bg-slate-900); background: var(--bg-primary);
color: var(--text-slate-200); color: var(--text-primary);
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
} }
.navbar { h1, h2, h3, h4, h5, h6 {
background-color: rgba(30, 41, 59, 0.8); /* bg-slate-800 with opacity */ font-family: 'Orbitron', sans-serif;
backdrop-filter: blur(10px); color: var(--accent-primary);
-webkit-backdrop-filter: blur(10px); font-weight: 700;
border-bottom: 1px solid var(--border-slate-700);
} }
.puzzle-board { a {
background-color: var(--bg-slate-900); color: var(--accent-primary);
border: 2px dashed var(--border-slate-700); text-decoration: none;
aspect-ratio: 4 / 3; transition: color 0.3s ease;
transition: background-color 0.3s;
} }
.pieces-tray { a:hover {
background-color: var(--bg-slate-800); color: var(--accent-glow);
border-radius: 0.75rem;
max-height: 80vh;
overflow-y: auto;
border: 1px solid var(--border-slate-700);
} }
.btn-cyan { .btn-primary {
background-color: var(--bg-cyan-500); background-color: var(--accent-primary);
color: var(--bg-slate-900); border-color: var(--accent-primary);
font-weight: bold; color: var(--bg-primary) !important;
border: none; font-weight: 600;
transition: background-color 0.2s; transition: background-color 0.3s ease, border-color 0.3s ease, transform 0.2s ease;
} }
.btn-cyan:hover { .btn-primary:hover {
background-color: var(--text-cyan-400); background-color: var(--accent-glow);
color: var(--bg-slate-900); border-color: var(--accent-glow);
transform: translateY(-2px);
} }
.form-select { .form-control {
background-color: var(--bg-slate-800); background-color: var(--bg-secondary);
color: var(--text-slate-200); border: 1px solid rgba(6, 182, 212, 0.15);
border-color: var(--border-slate-700); color: var(--text-primary);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%2394a3b8' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}
.form-select:focus {
background-color: var(--bg-slate-800);
color: var(--text-slate-200);
border-color: var(--text-cyan-400);
box-shadow: 0 0 0 0.25rem rgba(34, 211, 238, 0.25);
} }
.text-cyan { .form-control:focus {
color: var(--text-cyan-400); background-color: var(--bg-secondary);
border-color: var(--accent-primary);
color: var(--text-primary);
box-shadow: 0 0 0 0.2rem rgba(6, 182, 212, 0.25);
} }
.text-slate-400 { /* HEADER */
color: var(--text-slate-400); header.navbar {
background: rgba(15, 23, 42, 0.95) !important;
backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(6, 182, 212, 0.1);
height: 64px;
position: sticky;
top: 0;
z-index: 1000;
} }
.rounded-xl { .navbar-brand, .nav-link {
border-radius: 0.75rem; color: var(--text-primary) !important;
font-family: 'Orbitron', sans-serif;
} }
/* --- Gallery --- */ .navbar-brand:hover, .nav-link:hover {
.gallery-scroll-container { color: var(--accent-glow) !important;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: var(--border-slate-700) var(--bg-slate-900);
} }
.gallery-scroll-container::-webkit-scrollbar { /* MAIN CONTENT */
height: 8px; main {
background: linear-gradient(135deg, var(--bg-primary) 0%, #131c31 100%);
padding: 40px 24px;
min-height: calc(100vh - 64px);
} }
.gallery-scroll-container::-webkit-scrollbar-track { /* PUZZLE CARDS */
background: var(--bg-slate-900); .puzzle-gallery .card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(8px);
border: 1px solid rgba(6, 182, 212, 0.15);
border-radius: 16px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
overflow: hidden;
} }
.gallery-scroll-container::-webkit-scrollbar-thumb { .puzzle-gallery .card:hover {
background-color: var(--border-slate-700); transform: translateY(-4px) scale(1.02);
border-radius: 10px; box-shadow: 0 12px 32px rgba(6, 182, 212, 0.25);
border: 2px solid var(--bg-slate-900);
} }
.gallery-item { .card-title {
display: block; color: var(--accent-primary);
flex: 0 0 auto; /* Prevent shrinking */
width: 150px; /* Fixed width for items */
height: 112px; /* Fixed height for items (4:3 ratio) */
transition: transform 0.2s ease-in-out;
} }
.gallery-item:hover { .card-text {
transform: scale(1.05); color: var(--text-secondary);
} }
.gallery-item img { .card-body{
background: var(--bg-secondary);
}
/* LEADERBOARD */
.leaderboard-sidebar {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(8px);
border: 1px solid rgba(6, 182, 212, 0.15);
border-radius: 16px;
padding: 20px;
}
.leaderboard-sidebar h3 {
color: var(--accent-primary);
font-family: 'Orbitron', sans-serif;
}
.leaderboard-sidebar table {
width: 100%; width: 100%;
height: 100%; color: var(--text-primary);
object-fit: cover; /* Ensure images fill the container */ }
.leaderboard-sidebar th {
color: var(--accent-primary);
border-bottom: 1px solid rgba(6, 182, 212, 0.15);
}
.leaderboard-sidebar td {
padding: 8px 4px;
border-bottom: 1px solid rgba(30, 41, 59, 0.5);
}
/* PUZZLE PAGE */
#puzzle-container {
border: 2px solid var(--accent-primary);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 8px 24px rgba(6, 182, 212, 0.2);
}
#piece-container {
border: 2px dashed var(--text-secondary);
border-radius: 16px;
padding: 1rem;
background: rgba(30, 41, 59, 0.5);
}
.puzzle-piece {
cursor: grab;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.puzzle-piece:active {
cursor: grabbing;
}
.puzzle-piece:hover {
transform: scale(1.1);
box-shadow: 0 0 15px var(--accent-glow);
}
.bg-dark {
background-color: var(--bg-secondary) !important;
}
.text-white {
color: var(--text-primary) !important;
}
.border-dark{
border-color: #06b6d4 !important;
}
.table-dark {
--bs-table-bg: var(--bg-secondary);
--bs-table-border-color: var(--accent-primary);
} }

15
includes/footer.php Normal file
View File

@ -0,0 +1,15 @@
<!-- Footer -->
<footer class="text-center py-3 mt-auto">
<small>&copy; <?php echo date("Y"); ?> Photo Puzzle. Creato con ❤️.</small>
<?php if (isset($_SESSION['is_admin']) && $_SESSION['is_admin']): ?>
<small class="d-block"><a href="admin.php">Admin Panel</a></small>
<?php endif; ?>
</footer>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<!-- Custom JS -->
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

55
includes/header.php Normal file
View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo isset($page_title) ? htmlspecialchars($page_title) : 'Photo Puzzle'; ?></title>
<meta name="description" content="<?php echo isset($page_description) ? htmlspecialchars($page_description) : 'Crea e risolvi puzzle fotografici.'; ?>">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body class="d-flex flex-column min-vh-100">
<!-- Sticky Header -->
<header class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<a class="navbar-brand fw-bold" href="index.php">Photo Puzzle</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<?php if (isset($_SESSION['user_id'])): ?>
<li class="nav-item">
<a class="nav-link" href="index.php">Gioca</a>
</li>
<li class="nav-item">
<a class="nav-link" href="leaderboard.php">Classifica</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout (<?php echo htmlspecialchars($_SESSION['username']); ?>)</a>
</li>
<?php if (isset($_SESSION['is_admin']) && $_SESSION['is_admin']): ?>
<li class="nav-item">
<a class="nav-link" href="admin.php">Admin</a>
</li>
<?php endif; ?>
<?php else: ?>
<li class="nav-item">
<a class="nav-link" href="login.php">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="register.php">Registrati</a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</header>

246
index.php
View File

@ -35,10 +35,23 @@ $gallery_images = [];
// --- DATA FETCHING --- // --- DATA FETCHING ---
try { try {
$pdo = db(); $pdo = db();
// Fetch puzzles
$stmt = $pdo->query("SELECT id, file_name, name FROM puzzles WHERE is_public = 1 OR is_admin_upload = 1 ORDER BY created_at DESC"); $stmt = $pdo->query("SELECT id, file_name, name FROM puzzles WHERE is_public = 1 OR is_admin_upload = 1 ORDER BY created_at DESC");
$gallery_images = $stmt->fetchAll(PDO::FETCH_ASSOC); $gallery_images = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Fetch leaderboard
$leaderboard_stmt = $pdo->query("
SELECT u.username, s.score
FROM scores s
JOIN users u ON s.user_id = u.id
ORDER BY s.score DESC
LIMIT 10
");
$leaderboard_scores = $leaderboard_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) { } catch (PDOException $e) {
$error_message = "Impossibile caricare la galleria."; $error_message = "Impossibile caricare i dati della pagina.";
// Optionally log the error: error_log($e->getMessage());
} }
@ -108,144 +121,109 @@ if (isset($_SESSION['selected_puzzle'])) {
} }
?> ?>
<!DOCTYPE html> <?php
<html lang="it"> $page_title = 'Photo Puzzle - Gioca e Crea';
<head> $page_description = 'Crea e risolvi puzzle fotografici direttamente nel tuo browser. Scegli dalla nostra galleria o carica la tua immagine.';
<meta charset="UTF-8"> require_once 'includes/header.php';
<meta name="viewport" content="width=device-width, initial-scale=1.0"> ?>
<title>Photo Puzzle</title>
<meta name="description" content="Crea e risolvi puzzle fotografici direttamente nel tuo browser. Scegli dalla nostra galleria o carica la tua immagine.">
<!-- Open Graph -->
<meta property="og:title" content="Photo Puzzle - Gioca Ora!">
<meta property="og:description" content="Un gioco di puzzle moderno dove puoi usare le tue immagini o scegliere dalla galleria.">
<meta property="og:type" content="website">
<meta property="og:url" content=""> <!-- Add site URL here -->
<meta property="og:image" content="https://picsum.photos/1200/630?random=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body class="d-flex flex-column min-vh-100">
<!-- Sticky Header -->
<header class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<a class="navbar-brand fw-bold text-cyan" href="index.php">Photo Puzzle</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<?php if (isset($_SESSION['user_id'])): ?>
<li class="nav-item">
<a class="nav-link" href="index.php">Gioca</a>
</li>
<li class="nav-item">
<a class="nav-link" href="leaderboard.php">Classifica</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout (<?php echo htmlspecialchars($_SESSION['username']); ?>)</a>
</li>
<?php else: ?>
<li class="nav-item">
<a class="nav-link" href="login.php">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="register.php">Registrati</a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</header>
<!-- Main Content --> <!-- Main Content -->
<main class="container-fluid my-3 my-md-4 flex-grow-1"> <main class="flex-grow-1">
<div class="container py-5">
<div class="row">
<!-- Main content (Puzzles) -->
<div class="col-lg-8">
<!-- Gallery Section -->
<section class="puzzle-gallery mb-5" aria-labelledby="gallery-heading">
<h1 id="gallery-heading" class="text-center mb-4">Scegli un Puzzle</h1>
<?php if (!empty($gallery_images)): ?>
<div class="row row-cols-1 row-cols-sm-2 row-cols-xl-3 g-4">
<?php foreach ($gallery_images as $img): ?>
<div class="col">
<a href="puzzle.php?id=<?php echo $img['id']; ?>" class="text-decoration-none">
<div class="card h-100">
<img src="uploads/<?php echo htmlspecialchars($img['file_name']); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($img['name']); ?>" style="height: 200px; object-fit: cover;">
<div class="card-body">
<h5 class="card-title"><?php echo htmlspecialchars($img['name']); ?></h5>
</div>
</div>
</a>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="text-center p-5 rounded" style="background: var(--bg-secondary);">
<p class="text-secondary">Nessun puzzle disponibile al momento. Caricane uno tu!</p>
</div>
<?php endif; ?>
</section>
<!-- Gallery Section --> <?php if (isset($_SESSION['user_id'])): ?>
<?php if (!empty($gallery_images)): ?> <!-- Upload Section for Logged-in Users -->
<section class="mb-4" aria-labelledby="gallery-heading"> <section class="p-4 rounded" style="background: var(--bg-secondary);" aria-labelledby="upload-heading">
<h2 id="gallery-heading" class="h4 text-cyan">Galleria Pubblica</h2> <h2 id="upload-heading">Crea un nuovo Puzzle</h2>
<div class="gallery-scroll-container d-flex gap-3 pb-3"> <p class="text-secondary mb-4">Carica un'immagine per iniziare una nuova sfida.</p>
<?php foreach ($gallery_images as $img): ?>
<a href="puzzle.php?id=<?php echo $img['id']; ?>" class="gallery-item" title="<?php echo htmlspecialchars($img['name']); ?>"> <?php if ($error_message): ?>
<img src="uploads/<?php echo htmlspecialchars($img['file_name']); ?>" alt="<?php echo htmlspecialchars($img['name']); ?>" loading="lazy" class="rounded-xl"> <div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
</a> <?php endif; ?>
<?php endforeach; ?>
<form action="index.php" method="post" enctype="multipart/form-data">
<div class="row g-3">
<div class="col-md-6">
<label for="puzzle_name" class="form-label">Nome del Puzzle</label>
<input type="text" class="form-control" id="puzzle_name" name="puzzle_name" placeholder="Es: Tramonto a Venezia" required>
</div>
<div class="col-md-6">
<label for="puzzle_image_upload" class="form-label">Seleziona immagine (max 5MB)</label>
<input class="form-control" type="file" name="puzzle_image" id="puzzle_image_upload" accept="image/jpeg,image/png,image/gif" required>
</div>
</div>
<div class="form-check form-switch my-3">
<input class="form-check-input" type="checkbox" role="switch" id="share_puzzle" name="share_puzzle" value="1" checked>
<label class="form-check-label" for="share_puzzle">Condividi nella galleria pubblica</label>
</div>
<div class="text-start">
<button type="submit" class="btn btn-primary">Crea e Gioca</button>
</div>
</form>
</section>
<?php endif; ?>
</div> </div>
</section>
<?php endif; ?>
<div class="row g-3 g-md-4"> <!-- Leaderboard Sidebar -->
<!-- Puzzle Board --> <div class="col-lg-4">
<section class="col-lg-8" aria-labelledby="puzzle-board-heading"> <aside class="leaderboard-sidebar">
<div class="puzzle-board rounded-xl d-flex align-items-center justify-content-center p-3"> <h2 class="h4 mb-3">Top 10 Giocatori</h2>
<div class="text-center w-100"> <?php if (!empty($leaderboard_scores)): ?>
<h1 id="puzzle-board-heading" class="visually-hidden">Tavola del Puzzle</h1> <table class="table table-borderless">
<thead>
<?php if ($error_message): ?> <tr>
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div> <th>#</th>
<?php endif; ?> <th>Utente</th>
<th>Punteggio</th>
<?php if ($uploaded_image && file_exists($uploaded_image)): ?> </tr>
<img src="<?php echo htmlspecialchars($uploaded_image); ?>" alt="Immagine del puzzle caricata" class="img-fluid rounded-xl"> </thead>
<?php else: ?> <tbody>
<h2 class="h4 text-cyan">Crea un nuovo Puzzle</h2> <?php foreach ($leaderboard_scores as $index => $score): ?>
<p class="text-slate-400 mb-4">Carica un'immagine per iniziare.</p> <tr>
<td><?php echo $index + 1; ?></td>
<form action="index.php" method="post" enctype="multipart/form-data" style="max-width: 500px; margin: auto;"> <td><?php echo htmlspecialchars($score['username']); ?></td>
<div class="mb-3 text-start"> <td><?php echo htmlspecialchars($score['score']); ?></td>
<label for="puzzle_name" class="form-label">Nome del Puzzle</label> </tr>
<input type="text" class="form-control" id="puzzle_name" name="puzzle_name" placeholder="Es: Tramonto a Venezia" required> <?php endforeach; ?>
</div> </tbody>
</table>
<div class="mb-3 text-start"> <?php else: ?>
<label for="puzzle_image_upload" class="form-label">Seleziona immagine</label> <p class="text-secondary">Nessun punteggio ancora. Inizia a giocare!</p>
<input class="form-control" type="file" name="puzzle_image" id="puzzle_image_upload" accept="image/jpeg,image/png,image/gif" required> <?php endif; ?>
</div> <div class="text-center mt-3">
<a href="leaderboard.php" class="btn btn-outline-primary btn-sm">Vedi Classifica Completa</a>
<div class="form-check form-switch mb-3 text-start">
<input class="form-check-input" type="checkbox" role="switch" id="share_puzzle" name="share_puzzle" value="1" checked>
<label class="form-check-label" for="share_puzzle">Condividi nella galleria pubblica</label>
</div>
<div class="text-center">
<button type="submit" class="btn btn-cyan">Crea Puzzle</button>
</div>
</form>
<?php endif; ?>
</div> </div>
</div> </aside>
</section> </div>
<!-- Pieces Tray -->
<aside class="col-lg-4" aria-labelledby="pieces-tray-heading">
<div class="pieces-tray p-3">
<h2 id="pieces-tray-heading" class="h4 text-cyan mb-3">Pezzi</h2>
<div class="d-flex justify-content-center align-items-center" style="min-height: 200px;">
<p class="text-slate-400">I pezzi del puzzle appariranno qui.</p>
</div>
<!-- Pieces will be dynamically added here -->
</div>
</aside>
</div> </div>
</main> </div>
</main>
<!-- Footer --> <?php require_once 'includes/footer.php'; ?>
<footer class="text-center text-slate-400 py-3 mt-auto">
<small>&copy; <?php echo date("Y"); ?> Photo Puzzle. Creato con ❤️.</small>
<small class="d-block"><a href="admin.php" class="text-slate-400">Admin</a></small>
</footer>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<!-- Custom JS -->
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

View File

@ -25,73 +25,46 @@ $stmt = $pdo->query("
"); ");
$scores = $stmt->fetchAll(PDO::FETCH_ASSOC); $scores = $stmt->fetchAll(PDO::FETCH_ASSOC);
$page_title = 'Classifica';
require_once 'includes/header.php';
?> ?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Classifica</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="index.php">Puzzle Game</a>
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="index.php">Gioca</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="leaderboard.php">Classifica</a>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</div>
</nav>
<div class="container mt-5"> <main class="container mt-5">
<h1 class="mb-4 text-center">Classifica Generale</h1> <h1 class="mb-4 text-center">Classifica Generale</h1>
<div class="table-responsive"> <div class="table-responsive card p-3">
<table class="table table-striped table-hover"> <table class="table table-striped table-hover table-dark">
<thead class="table-dark"> <thead>
<tr>
<th>#</th>
<th>Utente</th>
<th>Puzzle</th>
<th>Punteggio</th>
<th>Tempo</th>
<th>Mosse</th>
<th>Data</th>
</tr>
</thead>
<tbody>
<?php if (empty($scores)): ?>
<tr> <tr>
<th>#</th> <td colspan="7" class="text-center">Nessun punteggio registrato.</td>
<th>Utente</th>
<th>Puzzle</th>
<th>Punteggio</th>
<th>Tempo</th>
<th>Mosse</th>
<th>Data</th>
</tr> </tr>
</thead> <?php else: ?>
<tbody> <?php foreach ($scores as $index => $score): ?>
<?php if (empty($scores)): ?>
<tr> <tr>
<td colspan="7" class="text-center">Nessun punteggio registrato.</td> <td><?php echo $index + 1; ?></td>
<td><?php echo htmlspecialchars($score['username']); ?></td>
<td><?php echo htmlspecialchars($score['puzzle_name']); ?></td>
<td><?php echo htmlspecialchars($score['score']); ?></td>
<td><?php echo htmlspecialchars($score['time_taken']); ?>s</td>
<td><?php echo htmlspecialchars($score['moves']); ?></td>
<td><?php echo htmlspecialchars(date("d/m/Y H:i", strtotime($score['completed_at']))); ?></td>
</tr> </tr>
<?php else: ?> <?php endforeach; ?>
<?php foreach ($scores as $index => $score): ?> <?php endif; ?>
<tr> </tbody>
<td><?php echo $index + 1; ?></td> </table>
<td><?php echo htmlspecialchars($score['username']); ?></td>
<td><?php echo htmlspecialchars($score['puzzle_name']); ?></td>
<td><?php echo htmlspecialchars($score['score']); ?></td>
<td><?php echo htmlspecialchars($score['time_taken']); ?>s</td>
<td><?php echo htmlspecialchars($score['moves']); ?></td>
<td><?php echo htmlspecialchars(date("d/m/Y H:i", strtotime($score['completed_at']))); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div> </div>
</main>
<footer class="text-center mt-5 py-3 bg-light"> <?php require_once 'includes/footer.php'; ?>
<p>&copy; <?php echo date("Y"); ?> Puzzle Game</p>
</footer>
</body>
</html>

View File

@ -1,3 +1,4 @@
<?php <?php
session_start(); session_start();
require_once 'db/config.php'; require_once 'db/config.php';
@ -47,61 +48,50 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
} }
} }
} }
$page_title = 'Login';
require_once 'includes/header.php';
?> ?>
<!DOCTYPE html>
<html lang="it"> <main class="container my-auto">
<head> <div class="row justify-content-center">
<meta charset="UTF-8"> <div class="col-md-6 col-lg-4">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <div class="card p-4 shadow-sm">
<title>Login</title> <h1 class="h3 text-center mb-4">Login</h1>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <?php if ($error_message): ?>
<style> <div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
body { <?php endif; ?>
display: flex;
align-items: center; <a href="google-auth.php" class="btn btn-danger w-100 mb-3">
justify-content: center; <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-google" viewBox="0 0 16 16">
height: 100vh; <path d="M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.25C2.806 7.48 2.5 8.522 2.5 9.5s.306 2.02.812 2.834c.632 1.842 2.405 3.25 4.492 3.25 1.257 0 2.34-.47 3.162-1.224l.064-.064a3.837 3.837 0 0 0 1.15-2.487H8v-2h7.545z"/>
background-color: #f8f9fa; </svg> Accedi con Google
} </a>
.login-container {
max-width: 400px; <div class="d-flex align-items-center my-3">
padding: 2rem; <hr class="flex-grow-1">
border: 1px solid #dee2e6; <span class="px-2 text-muted">oppure</span>
border-radius: 0.5rem; <hr class="flex-grow-1">
background-color: #fff; </div>
}
</style> <form method="post" action="login.php">
</head> <div class="mb-3">
<body> <label for="username" class="form-label">Nome Utente</label>
<div class="login-container"> <input type="text" class="form-control" id="username" name="username" required>
<h2 class="text-center mb-4">Login</h2> </div>
<?php if ($error_message): ?> <div class="mb-3">
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div> <label for="password" class="form-label">Password</label>
<?php endif; ?> <input type="password" class="form-control" id="password" name="password" required>
<a href="google-auth.php" class="btn btn-danger w-100 mb-3"> </div>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-google" viewBox="0 0 16 16"> <button type="submit" class="btn btn-primary w-100">Accedi</button>
<path d="M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.25C2.806 7.48 2.5 8.522 2.5 9.5s.306 2.02.812 2.834c.632 1.842 2.405 3.25 4.492 3.25 1.257 0 2.34-.47 3.162-1.224l.064-.064a3.837 3.837 0 0 0 1.15-2.487H8v-2h7.545z"/> </form>
</svg> Accedi con Google
</a> <div class="text-center mt-3">
<div class="d-flex align-items-center my-3"> <p class="mb-0">Non hai un account? <a href="register.php">Registrati</a></p>
<hr class="flex-grow-1"> </div>
<span class="px-2 text-muted">oppure</span>
<hr class="flex-grow-1">
</div>
<form method="post" action="login.php">
<div class="mb-3">
<label for="username" class="form-label">Nome Utente</label>
<input type="text" class="form-control" id="username" name="username" required>
</div> </div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Accedi</button>
</form>
<div class="text-center mt-3">
<p>Non hai un account? <a href="register.php">Registrati</a></p>
</div> </div>
</div> </div>
</body> </main>
</html>
<?php require_once 'includes/footer.php'; ?>

View File

@ -120,187 +120,184 @@ if ($puzzle_id > 0) {
} else { } else {
$error_message = "ID del puzzle non valido."; $error_message = "ID del puzzle non valido.";
} }
$page_title = 'Risolvi: ' . ($puzzle ? htmlspecialchars($puzzle['name']) : 'Puzzle');
require_once 'includes/header.php';
?> ?>
<!DOCTYPE html>
<html lang="it"> <style>
<head> #puzzle-board {
<meta charset="UTF-8"> display: grid;
<meta name="viewport" content="width=device-width, initial-scale=1.0"> grid-template-columns: repeat(<?php echo $cols; ?>, 1fr);
<title>Risolvi: <?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Puzzle'; ?></title> grid-template-rows: repeat(<?php echo $rows; ?>, 1fr);
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> aspect-ratio: <?php echo $source_width; ?> / <?php echo $source_height; ?>;
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>"> max-width: 100%;
<style> }
#puzzle-board { border: 2px dashed #ccc; background-color: #f8f9fa; display: grid; grid-template-columns: repeat(<?php echo $cols; ?>, 1fr); grid-template-rows: repeat(<?php echo $rows; ?>, 1fr); aspect-ratio: <?php echo $source_width; ?> / <?php echo $source_height; ?>; max-width: 100%; } </style>
.drop-zone { border: 1px solid #eee; width: 100%; height: 100%; }
.drop-zone.hovered { background-color: #e9ecef; } <div id="win-message">
.puzzle-piece { cursor: grab; width: 100%; height: 100%; object-fit: cover; box-shadow: 0 0 5px rgba(0,0,0,0.5); } <h2>Complimenti!</h2>
#pieces-tray { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; min-height: 150px; background-color: #f0f0f0; border-radius: 10px; } <p>Hai risolto il puzzle!</p>
#pieces-tray .puzzle-piece { width: 80px; height: auto; margin: 4px; } <p>Punteggio: <strong id="final-score">0</strong></p>
#win-message { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(40, 167, 69, 0.95); color: white; padding: 40px; border-radius: 15px; text-align: center; z-index: 1000; } <a href="leaderboard.php" class="btn btn-warning">Classifica</a>
</style> <a href="index.php" class="btn btn-light">Gioca Ancora</a>
</head> </div>
<body>
<div id="win-message"> <main class="container mt-4">
<h2>Complimenti!</h2> <div class="text-center mb-4">
<p>Hai risolto il puzzle!</p> <h1><?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Risolvi il Puzzle'; ?></h1>
<p>Punteggio: <strong id="final-score">0</strong></p> <div class="d-flex justify-content-center align-items-center gap-3">
<a href="leaderboard.php" class="btn btn-warning">Classifica</a> <a href="index.php" class="btn btn-secondary btn-sm">Torna alla Galleria</a>
<a href="index.php" class="btn btn-light">Gioca Ancora</a> <span class="badge bg-primary">Tempo: <span id="timer">0s</span></span>
<span class="badge bg-info">Mosse: <span id="move-counter">0</span></span>
</div>
</div> </div>
<div class="container mt-4"> <?php if ($error_message): ?>
<div class="text-center mb-4"> <div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
<h1><?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Risolvi il Puzzle'; ?></h1> <?php elseif ($puzzle): ?>
<div class="d-flex justify-content-center align-items-center gap-3"> <div class="text-center mb-3">
<a href="index.php" class="btn btn-secondary btn-sm">Torna alla Galleria</a> <form method="GET" action="puzzle.php" class="d-inline-flex align-items-center">
<span class="badge bg-primary">Tempo: <span id="timer">0s</span></span> <input type="hidden" name="id" value="<?php echo $puzzle_id; ?>">
<span class="badge bg-info">Mosse: <span id="move-counter">0</span></span> <label for="difficulty" class="form-label me-2 mb-0">Difficoltà:</label>
</div> <select name="difficulty" id="difficulty" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="16" <?php if ($difficulty == 16) echo 'selected'; ?>>Facile (16 pezzi)</option>
<option value="32" <?php if ($difficulty == 32) echo 'selected'; ?>>Medio (32 pezzi)</option>
<option value="64" <?php if ($difficulty == 64) echo 'selected'; ?>>Difficile (64 pezzi)</option>
</select>
</form>
</div> </div>
<?php if ($error_message): ?> <div class="row">
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div> <div class="col-lg-8 col-md-12 mb-3">
<?php elseif ($puzzle): ?> <div id="puzzle-board" class="puzzle-board shadow-lg rounded"></div>
<div class="text-center mb-3">
<form method="GET" action="puzzle.php" class="d-inline-flex align-items-center">
<input type="hidden" name="id" value="<?php echo $puzzle_id; ?>">
<label for="difficulty" class="form-label me-2 mb-0">Difficoltà:</label>
<select name="difficulty" id="difficulty" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="16" <?php if ($difficulty == 16) echo 'selected'; ?>>Facile (16 pezzi)</option>
<option value="32" <?php if ($difficulty == 32) echo 'selected'; ?>>Medio (32 pezzi)</option>
<option value="64" <?php if ($difficulty == 64) echo 'selected'; ?>>Difficile (64 pezzi)</option>
</select>
</form>
</div> </div>
<div class="col-lg-4 col-md-12">
<div class="row"> <div class="card p-2">
<div class="col-lg-8 col-md-12 mb-3"> <h2 class="h5 text-center">I Tuoi Pezzi</h2>
<div id="puzzle-board"></div> <div id="pieces-tray" class="pieces-tray p-2">
</div>
<div class="col-lg-4 col-md-12">
<h2 class="h5">I Tuoi Pezzi</h2>
<div id="pieces-tray" class="p-2">
<?php foreach ($pieces as $piece_path): ?> <?php foreach ($pieces as $piece_path): ?>
<img src="<?php echo htmlspecialchars($piece_path); ?>" class="puzzle-piece" alt="Pezzo del puzzle" draggable="true"> <img src="<?php echo htmlspecialchars($piece_path); ?>" class="puzzle-piece" alt="Pezzo del puzzle" draggable="true">
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</div> </div>
</div> </div>
<?php endif; ?> </div>
</div> <?php endif; ?>
</main>
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const board = document.getElementById('puzzle-board'); const board = document.getElementById('puzzle-board');
const piecesTray = document.getElementById('pieces-tray'); const piecesTray = document.getElementById('pieces-tray');
const pieces = document.querySelectorAll('.puzzle-piece'); const pieces = document.querySelectorAll('.puzzle-piece');
const cols = <?php echo $cols; ?>; const cols = <?php echo $cols; ?>;
const rows = <?php echo $rows; ?>; const rows = <?php echo $rows; ?>;
const puzzleId = <?php echo $puzzle_id; ?>; const puzzleId = <?php echo $puzzle_id; ?>;
let draggedPiece = null; let draggedPiece = null;
let moves = 0; let moves = 0;
let gameStarted = false; let gameStarted = false;
let startTime = 0; let startTime = 0;
let timerInterval = null; let timerInterval = null;
function startTimer() { function startTimer() {
if (gameStarted) return; if (gameStarted) return;
gameStarted = true; gameStarted = true;
startTime = Date.now(); startTime = Date.now();
timerInterval = setInterval(updateTimer, 1000); timerInterval = setInterval(updateTimer, 1000);
} }
function updateTimer() { function updateTimer() {
const seconds = Math.floor((Date.now() - startTime) / 1000); const seconds = Math.floor((Date.now() - startTime) / 1000);
document.getElementById('timer').textContent = `${seconds}s`; document.getElementById('timer').textContent = `${seconds}s`;
} }
function incrementMoves() { function incrementMoves() {
moves++; moves++;
document.getElementById('move-counter').textContent = moves; document.getElementById('move-counter').textContent = moves;
} }
for (let y = 0; y < rows; y++) { for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) { for (let x = 0; x < cols; x++) {
const dropZone = document.createElement('div'); const dropZone = document.createElement('div');
dropZone.classList.add('drop-zone'); dropZone.classList.add('drop-zone');
dropZone.dataset.position = `${y}-${x}`; dropZone.dataset.position = `${y}-${x}`;
board.appendChild(dropZone); board.appendChild(dropZone);
dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('hovered'); }); dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('hovered'); });
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('hovered')); dropZone.addEventListener('dragleave', () => dropZone.classList.remove('hovered'));
dropZone.addEventListener('drop', e => { dropZone.addEventListener('drop', e => {
e.preventDefault(); e.preventDefault();
dropZone.classList.remove('hovered'); dropZone.classList.remove('hovered');
if (draggedPiece && dropZone.children.length === 0) { if (draggedPiece && dropZone.children.length === 0) {
startTimer(); startTimer();
incrementMoves(); incrementMoves();
dropZone.appendChild(draggedPiece); dropZone.appendChild(draggedPiece);
checkWin(); checkWin();
} }
});
}
}
piecesTray.addEventListener('dragover', e => e.preventDefault());
piecesTray.addEventListener('drop', e => {
e.preventDefault();
if (draggedPiece) {
startTimer();
incrementMoves();
piecesTray.appendChild(draggedPiece);
}
});
pieces.forEach(piece => {
const match = piece.src.match(/piece_(\d+)_(\d+)\.jpg$/);
if (match) { piece.dataset.position = `${match[1]}-${match[2]}`; }
piece.addEventListener('dragstart', e => {
draggedPiece = e.target;
setTimeout(() => { e.target.style.opacity = '0.5'; }, 0);
}); });
}
}
piece.addEventListener('dragend', e => { piecesTray.addEventListener('dragover', e => e.preventDefault());
draggedPiece = null; piecesTray.addEventListener('drop', e => {
e.target.style.opacity = '1'; e.preventDefault();
}); if (draggedPiece) {
}); startTimer();
incrementMoves();
function checkWin() { piecesTray.appendChild(draggedPiece);
const dropZones = board.querySelectorAll('.drop-zone');
if ([...dropZones].every(zone =>
zone.children.length > 0 &&
zone.children[0].dataset.position === zone.dataset.position
)) {
clearInterval(timerInterval);
const timeTaken = Math.floor((Date.now() - startTime) / 1000);
const formData = new FormData();
formData.append('action', 'save_score');
formData.append('puzzle_id', puzzleId);
formData.append('time_taken', timeTaken);
formData.append('moves', moves);
fetch('puzzle.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('final-score').textContent = data.score;
document.getElementById('win-message').style.display = 'block';
board.style.borderColor = '#28a745';
} else {
console.error('Failed to save score:', data.error);
alert('Si è verificato un errore durante il salvataggio del punteggio.');
}
});
}
} }
}); });
</script>
</body> pieces.forEach(piece => {
</html> const match = piece.src.match(/piece_(\d+)_(\d+)\.jpg$/);
if (match) { piece.dataset.position = `${match[1]}-${match[2]}`; }
piece.addEventListener('dragstart', e => {
draggedPiece = e.target;
setTimeout(() => { e.target.style.opacity = '0.5'; }, 0);
});
piece.addEventListener('dragend', e => {
draggedPiece = null;
e.target.style.opacity = '1';
});
});
function checkWin() {
const dropZones = board.querySelectorAll('.drop-zone');
if ([...dropZones].every(zone =>
zone.children.length > 0 &&
zone.children[0].dataset.position === zone.dataset.position
)) {
clearInterval(timerInterval);
const timeTaken = Math.floor((Date.now() - startTime) / 1000);
const formData = new FormData();
formData.append('action', 'save_score');
formData.append('puzzle_id', puzzleId);
formData.append('time_taken', timeTaken);
formData.append('moves', moves);
fetch('puzzle.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('final-score').textContent = data.score;
document.getElementById('win-message').style.display = 'block';
board.style.borderColor = 'var(--mavi-orange)';
} else {
console.error('Failed to save score:', data.error);
alert('Si è verificato un errore durante il salvataggio del punteggio.');
}
});
}
}
});
</script>
<?php require_once 'includes/footer.php'; ?>

View File

@ -38,67 +38,55 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
} }
} }
} }
$page_title = 'Registrazione';
require_once 'includes/header.php';
?> ?>
<!DOCTYPE html>
<html lang="it"> <main class="container my-auto">
<head> <div class="row justify-content-center">
<meta charset="UTF-8"> <div class="col-md-6 col-lg-4">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <div class="card p-4 shadow-sm">
<title>Registrazione</title> <h1 class="h3 text-center mb-4">Registrazione</h1>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <?php if ($error): ?>
<style> <div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
body { <?php endif; ?>
display: flex; <?php if ($success): ?>
align-items: center; <div class="alert alert-success"><?php echo htmlspecialchars($success); ?></div>
justify-content: center; <?php endif; ?>
height: 100vh;
background-color: #f8f9fa; <a href="google-auth.php" class="btn btn-danger w-100 mb-3">
} <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-google" viewBox="0 0 16 16">
.card { <path d="M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.25C2.806 7.48 2.5 8.522 2.5 9.5s.306 2.02.812 2.834c.632 1.842 2.405 3.25 4.492 3.25 1.257 0 2.34-.47 3.162-1.224l.064-.064a3.837 3.837 0 0 0 1.15-2.487H8v-2h7.545z"/>
width: 100%; </svg> Registrati con Google
max-width: 400px; </a>
} <div class="d-flex align-items-center my-3">
</style> <hr class="flex-grow-1">
</head> <span class="px-2 text-muted">oppure</span>
<body> <hr class="flex-grow-1">
<div class="card">
<div class="card-body">
<h3 class="card-title text-center">Registrazione</h3>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success"><?php echo $success; ?></div>
<?php endif; ?>
<a href="google-auth.php" class="btn btn-danger w-100 mb-3">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-google" viewBox="0 0 16 16">
<path d="M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.25C2.806 7.48 2.5 8.522 2.5 9.5s.306 2.02.812 2.834c.632 1.842 2.405 3.25 4.492 3.25 1.257 0 2.34-.47 3.162-1.224l.064-.064a3.837 3.837 0 0 0 1.15-2.487H8v-2h7.545z"/>
</svg> Registrati con Google
</a>
<div class="d-flex align-items-center my-3">
<hr class="flex-grow-1">
<span class="px-2 text-muted">oppure</span>
<hr class="flex-grow-1">
</div>
<form method="POST" action="register.php">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div> </div>
<div class="mb-3">
<label for="email" class="form-label">Email</label> <form method="POST" action="register.php">
<input type="email" class="form-control" id="email" name="email" required> <div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Registrati</button>
</form>
<div class="text-center mt-3">
<p class="mb-0">Hai già un account? <a href="login.php">Accedi</a></p>
</div> </div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Registrati</button>
</form>
<div class="text-center mt-3">
<p>Hai già un account? <a href="login.php">Accedi</a></p>
</div> </div>
</div> </div>
</div> </div>
</body> </main>
</html>
<?php require_once 'includes/footer.php'; ?>