eweng.space/reviews/index.html
2026-04-01 14:08:32 +02:00

206 lines
6.1 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>reviews — eweng.space</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>☆</text></svg>">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IM+Fell+English:ital@0;1&display=swap" rel="stylesheet">
<style>
body {
font-family: 'IM Fell English', serif;
font-size: 20px;
}
@keyframes colorshift {
0% { color: hsl(0, 60%, 70%); }
25% { color: hsl(90, 60%, 70%); }
50% { color: hsl(180, 60%, 70%); }
75% { color: hsl(270, 60%, 70%); }
100% { color: hsl(360, 60%, 70%); }
}
@keyframes levite {
0% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
100% { transform: translateY(0px); }
}
.fenetre {
max-width: 600px;
border: 1px solid black;
padding: 0.3rem 1.5rem 0 1.5rem;
padding-bottom: 0;
margin-top: 0px;
position: relative;
overflow-wrap: break-word;
}
.fenetre-nom {
margin-bottom: 1px;
margin-left: 2px;
}
.fenetre-contenu {
padding: 0 1rem 1.5rem 1rem;
min-width: 0;
}
.retour {
font-family: 'IM Fell English', serif;
font-size: 20px;
text-decoration: none;
color: inherit;
display: inline-block;
margin-bottom: 1px;
margin-right: 0.4rem;
}
.retour:hover { text-decoration: underline; }
/* ── grille de covers ── */
.grille {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 1rem;
}
.carte {
width: 150px;
cursor: pointer;
transition: transform 0.2s ease, opacity 0.25s ease;
position: relative;
}
.carte img {
width: 150px;
height: 150px;
object-fit: cover;
display: block;
border: 1px solid #111;
}
.carte .placeholder {
width: 150px;
height: 150px;
background: #eee;
border: 1px solid #111;
display: flex;
align-items: center;
justify-content: center;
font-style: italic;
color: #999;
font-size: 0.8rem;
text-align: center;
padding: 0.5rem;
}
.carte .nom {
margin-top: 0.3rem;
font-size: 0.8rem;
line-height: 1.3;
}
.carte .nom .artiste {
font-style: italic;
color: #555;
}
/* hover : assombrir les autres */
.grille.hovering .carte { opacity: 0.15; }
.grille.hovering .carte.actif {
opacity: 1;
transform: scale(1.07);
z-index: 10;
}
.badge-fav {
position: absolute;
top: 4px;
right: 4px;
font-size: 0.7rem;
background: #fff;
border: 1px solid #111;
padding: 1px 4px;
pointer-events: none;
}
</style>
</head>
<body>
<div>
<a href="../index.html" class="retour"></a><span class="fenetre-nom" id="titre-nav">eweng.space &#9734;</span>
</div>
<div class="fenetre">
<div class="fenetre-contenu">
<h1>reviews</h1>
<p>ce que j'écoute, ce que j'en pense.</p>
<div class="grille" id="grille"></div>
</div>
</div>
<script>
function toSlug(titre) {
return titre
.toLowerCase()
.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
.replace(/\s+/g, '-')
.replace(/[^a-z0-9-]/g, '');
}
fetch('data/albums.json')
.then(r => r.json())
.then(albums => {
const grille = document.getElementById('grille');
albums.forEach(album => {
const carte = document.createElement('div');
carte.className = 'carte';
const media = album.cover
? `<img src="${album.cover}" alt="${album.titre}" onerror="this.outerHTML='<div class=\\'placeholder\\'>${album.titre}</div>'">`
: `<div class="placeholder">${album.titre}</div>`;
const fav = album.favoris ? '<span class="badge-fav">♥</span>' : '';
carte.innerHTML = `
${fav}
${media}
<div class="nom">
${album.titre}<br>
<span class="artiste">${album.artiste}</span>
</div>
`;
carte.addEventListener('mouseenter', () => {
grille.classList.add('hovering');
carte.classList.add('actif');
});
carte.addEventListener('mouseleave', () => {
grille.classList.remove('hovering');
carte.classList.remove('actif');
});
carte.addEventListener('click', () => {
window.location.href = `albums/${toSlug(album.titre)}.html`;
});
grille.appendChild(carte);
});
})
.catch(() => {
document.getElementById('grille').textContent = 'impossible de charger les albums.';
});
const el = document.getElementById('titre-nav');
el.innerHTML = el.textContent.split('').map((c, i) => {
if (c === ' ') return ' ';
const delayColor = (i * 0.3).toFixed(1);
const delayLevite = (Math.random() * 4).toFixed(2);
const duree = (3 + Math.random() * 3).toFixed(2);
return `<span style="display:inline-block;animation:colorshift 12s ease-in-out infinite,levite ${duree}s ease-in-out infinite;animation-delay:-${delayColor}s,-${delayLevite}s">${c}</span>`;
}).join('');
</script>
</body>
</html>