ripasso: fixes

This commit is contained in:
2026-03-01 20:49:28 +01:00
parent a83d57e0f5
commit dd1fb79c7c
4 changed files with 1239 additions and 1 deletions

View File

@@ -0,0 +1,473 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Esercizio 3 — La Biblioteca Online (API)</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Merriweather:wght@700&family=Inter:wght@400;500;600;700&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', 'Segoe UI', sans-serif;
background: linear-gradient(145deg, #fdf8f0 0%, #f5f0e8 40%, #faf5ed 100%);
color: #2d2418;
padding: 24px;
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 880px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(12px);
border-radius: 20px;
padding: 36px;
box-shadow:
0 1px 3px rgba(0,0,0,0.04),
0 8px 32px rgba(139,90,43,0.08);
border: 1px solid rgba(255,255,255,0.6);
}
h1 {
text-align: center;
font-family: 'Merriweather', Georgia, serif;
font-size: 2.2em;
margin-bottom: 6px;
background: linear-gradient(135deg, #8b5a2b, #a0522d);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.sottotitolo {
text-align: center;
color: #94867a;
font-size: 0.9em;
font-weight: 500;
margin-bottom: 10px;
}
.avviso-server {
text-align: center;
background: linear-gradient(135deg, #fef3c7, #fef9c3);
border: 1px solid #fbbf24;
color: #92400e;
padding: 12px 18px;
border-radius: 12px;
font-size: 0.88em;
font-weight: 500;
margin-bottom: 28px;
}
.avviso-server code {
background: rgba(0,0,0,0.08);
padding: 2px 6px;
border-radius: 4px;
}
/* ─── STATISTICHE ─── */
#stats {
display: flex;
justify-content: center;
gap: 16px;
margin-bottom: 28px;
flex-wrap: wrap;
}
.stat-box {
background: linear-gradient(145deg, #fff, #faf5ed);
border: 1px solid #e8ddd0;
border-radius: 14px;
padding: 18px 28px;
text-align: center;
min-width: 140px;
position: relative;
overflow: hidden;
transition: all 0.25s ease;
}
.stat-box::after {
content: '';
position: absolute;
bottom: 0; left: 0; right: 0;
height: 3px;
background: linear-gradient(90deg, #8b5a2b, #cd853f);
opacity: 0;
transition: opacity 0.25s;
}
.stat-box:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(139,90,43,0.1);
}
.stat-box:hover::after { opacity: 1; }
.stat-box .label {
font-size: 0.75em;
color: #94867a;
text-transform: uppercase;
letter-spacing: 0.8px;
font-weight: 600;
}
.stat-box .valore {
font-size: 2em;
font-weight: 700;
color: #8b5a2b;
}
/* ─── LOADING ─── */
#loading {
display: none;
text-align: center;
padding: 30px;
}
#loading.visibile { display: block; }
.spinner {
width: 40px; height: 40px;
border: 4px solid #e8ddd0;
border-top: 4px solid #8b5a2b;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 0 auto 12px;
}
@keyframes spin { to { transform: rotate(360deg); } }
#loading p { color: #94867a; font-size: 0.9em; }
/* ─── SEZIONI ─── */
.sezione {
background: linear-gradient(145deg, #fdf8f0, #faf5ed);
border: 1px solid #e8ddd0;
border-radius: 14px;
padding: 26px;
margin-bottom: 24px;
}
.sezione h2 {
font-size: 1.15em;
margin-bottom: 18px;
color: #8b5a2b;
font-weight: 700;
}
/* ─── FORM ─── */
.form-riga {
display: flex;
gap: 12px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.form-riga input,
.form-riga select {
flex: 1;
min-width: 140px;
padding: 11px 16px;
border: 1.5px solid #e0d5c7;
border-radius: 10px;
font-size: 0.95em;
font-family: inherit;
background: rgba(255,255,255,0.85);
color: #2d2418;
transition: all 0.25s ease;
}
.form-riga input:focus,
.form-riga select:focus {
outline: none;
border-color: #8b5a2b;
box-shadow: 0 0 0 3px rgba(139,90,43,0.1);
background: #fff;
}
.form-riga input::placeholder { color: #b8a898; }
/* ─── BOTTONI ─── */
.bottoni {
display: flex;
gap: 10px;
margin-bottom: 18px;
flex-wrap: wrap;
}
button {
padding: 10px 22px;
border: none;
border-radius: 10px;
font-size: 0.9em;
font-weight: 600;
font-family: inherit;
cursor: pointer;
transition: all 0.25s ease;
}
.btn-primario {
background: linear-gradient(135deg, #8b5a2b, #a0522d);
color: white;
box-shadow: 0 2px 10px rgba(139,90,43,0.25);
}
.btn-primario:hover {
box-shadow: 0 4px 16px rgba(139,90,43,0.35);
transform: translateY(-1px);
}
.btn-secondario {
background: rgba(255,255,255,0.7);
color: #5d4e37;
border: 1.5px solid #e0d5c7;
}
.btn-secondario:hover {
background: #fff;
border-color: #8b5a2b;
transform: translateY(-1px);
}
.btn-danger {
background: #fff5f5;
color: #c53030;
border: 1.5px solid #fcc;
padding: 6px 14px;
font-size: 0.85em;
border-radius: 8px;
}
.btn-danger:hover {
background: #fed7d7;
border-color: #c53030;
}
/* ─── LISTA LIBRI ─── */
#lista-libri {
list-style: none;
padding: 0;
margin-top: 16px;
}
#lista-libri li {
background: #fff;
border: 1px solid #e8ddd0;
border-left: 4px solid #8b5a2b;
border-radius: 0 10px 10px 0;
padding: 14px 18px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease;
}
#lista-libri li:hover {
background: #fdf8f0;
box-shadow: 0 2px 8px rgba(139,90,43,0.08);
transform: translateX(4px);
}
#lista-libri li .info-libro { flex: 1; }
#lista-libri li .titolo-libro {
font-weight: 700;
color: #8b5a2b;
font-size: 1.05em;
}
#lista-libri li .dettagli-libro {
color: #94867a;
font-size: 0.85em;
margin-top: 2px;
}
.letto-badge {
display: inline-block;
padding: 2px 10px;
border-radius: 12px;
font-size: 0.78em;
font-weight: 600;
}
.letto-si { background: #d1fae5; color: #065f46; }
.letto-no { background: #fee2e2; color: #991b1b; }
/* ─── DETTAGLIO ─── */
#dettaglio-libro {
background: #fff;
border: 1px solid #e8ddd0;
border-radius: 12px;
padding: 22px;
margin-top: 16px;
display: none;
}
#dettaglio-libro.visibile {
display: block;
animation: slideIn 0.3s ease;
}
#dettaglio-libro h3 {
color: #8b5a2b;
font-size: 1.2em;
margin-bottom: 8px;
}
#dettaglio-libro .info {
color: #5d4e37;
font-size: 0.95em;
margin-bottom: 4px;
}
/* ─── MESSAGGIO ─── */
#messaggio {
display: none;
padding: 14px 18px;
border-radius: 10px;
margin: 16px 0;
font-weight: 600;
text-align: center;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
.msg-successo {
background: linear-gradient(135deg, #d1fae5, #a7f3d0);
color: #065f46;
border: 1px solid #6ee7b7;
}
.msg-errore {
background: linear-gradient(135deg, #fee2e2, #fecaca);
color: #991b1b;
border: 1px solid #fca5a5;
}
/* ─── EMPTY STATE ─── */
.empty-state {
text-align: center;
padding: 40px 20px;
color: #94867a;
}
.empty-state .emoji { font-size: 3em; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="container">
<h1>📚 La Biblioteca Online</h1>
<p class="sottotitolo">Ripasso API — fetch, async/await, CRUD</p>
<div class="avviso-server">
⚠️ Prima di iniziare, assicurati che il server sia avviato e funzionante.
</div>
<!-- MESSAGGIO -->
<div id="messaggio"></div>
<!-- STATISTICHE -->
<div id="stats">
<div class="stat-box">
<div class="label">Totale Libri</div>
<div class="valore" id="stat-totale">0</div>
</div>
<div class="stat-box">
<div class="label">Già Letti</div>
<div class="valore" id="stat-letti">0</div>
</div>
<div class="stat-box">
<div class="label">Da Leggere</div>
<div class="valore" id="stat-da-leggere">0</div>
</div>
</div>
<!-- LOADING -->
<div id="loading">
<div class="spinner"></div>
<p>Caricamento in corso...</p>
</div>
<!-- SEZIONE 1: CARICA LISTA -->
<div class="sezione" id="sezione-lista">
<h2>📋 Lista Libri</h2>
<div class="bottoni">
<button class="btn-primario" id="btn-carica-tutti">📥 Carica Tutti i Libri</button>
</div>
<ul id="lista-libri">
<div class="empty-state">
<div class="emoji">📚</div>
<p>Clicca "Carica Tutti i Libri" per iniziare</p>
</div>
</ul>
</div>
<!-- SEZIONE 2: DETTAGLIO SINGOLO -->
<div class="sezione" id="sezione-dettaglio">
<h2>🔎 Cerca Libro per ID</h2>
<div class="form-riga">
<input type="number" id="input-id" placeholder="Inserisci ID libro (1-20)" min="1" max="20">
<button class="btn-primario" id="btn-dettaglio">Cerca</button>
</div>
<div id="dettaglio-libro"></div>
</div>
<!-- SEZIONE 3: AGGIUNGI LIBRO -->
<div class="sezione" id="sezione-aggiungi">
<h2> Aggiungi Nuovo Libro</h2>
<div class="form-riga">
<input type="text" id="input-titolo" placeholder="Titolo">
<input type="text" id="input-autore" placeholder="Autore">
</div>
<div class="form-riga">
<select id="select-genere">
<option value="">-- Genere --</option>
<option value="Fantasy">🧙 Fantasy</option>
<option value="Giallo">🔍 Giallo</option>
<option value="Fantascienza">🚀 Fantascienza</option>
<option value="Narrativa">📖 Narrativa</option>
<option value="Horror">👻 Horror</option>
<option value="Romanzo">💕 Romanzo</option>
<option value="Umorismo">😂 Umorismo</option>
</select>
<input type="number" id="input-pagine" placeholder="Numero pagine" min="1">
</div>
<button class="btn-primario" id="btn-aggiungi"> Aggiungi Libro</button>
</div>
<!-- SEZIONE 4: SEGNA COME LETTO -->
<div class="sezione" id="sezione-modifica">
<h2>✏️ Segna come Letto / Non Letto</h2>
<div class="form-riga">
<input type="number" id="input-modifica-id" placeholder="ID del libro" min="1">
<select id="select-letto">
<option value="true">✅ Letto</option>
<option value="false">❌ Non letto</option>
</select>
<button class="btn-primario" id="btn-modifica">Aggiorna</button>
</div>
</div>
<!-- SEZIONE 5: ELIMINA -->
<div class="sezione" id="sezione-elimina">
<h2>🗑️ Elimina Libro</h2>
<div class="form-riga">
<input type="number" id="input-elimina-id" placeholder="ID del libro da eliminare" min="1">
<button class="btn-danger" id="btn-elimina">🗑️ Elimina</button>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>