rediseña panel de playlists: layout vertical en lista

Cambia la grilla de cajas a una lista vertical donde cada playlist
ocupa una fila con imagen/emoji a la izquierda y nombre + descripción
a la derecha. En modo votación, la barra y conteo quedan en el bloque
de info y el botón de voto se desplaza al extremo derecho.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-23 17:43:16 -04:00
parent 0c2b20011b
commit 809f35fc78
3 changed files with 60 additions and 41 deletions
+2 -1
View File
@@ -5,7 +5,8 @@
"Bash(python3 -m venv .venv)", "Bash(python3 -m venv .venv)",
"Bash(.venv/bin/pip install *)", "Bash(.venv/bin/pip install *)",
"Bash(.venv/bin/python *)", "Bash(.venv/bin/python *)",
"Bash(git -C /home/deivid/spotify-cantina status)" "Bash(git -C /home/deivid/spotify-cantina status)",
"Bash(git *)"
] ]
} }
} }
+22 -11
View File
@@ -301,23 +301,28 @@ function renderPlaylists(playlists, isVoting, myVote) {
const btnDisabled = cooldownRemaining > 0 ? 'disabled' : ''; const btnDisabled = cooldownRemaining > 0 ? 'disabled' : '';
return ` return `
<div class="playlist-card voting-card ${isVoted ? 'voted' : ''}"> <div class="playlist-card voting-card ${isVoted ? 'voted' : ''}">
<div class="voting-card-top clickable" onclick='openTracksModal(${JSON.stringify(pl)})'> <div class="playlist-card-clickable clickable" onclick='openTracksModal(${JSON.stringify(pl)})'>
${img} ${img}
<div class="playlist-card-info">
<div class="playlist-card-name">${pl.name}</div> <div class="playlist-card-name">${pl.name}</div>
${pl.description ? `<div class="playlist-card-desc">${pl.description}</div>` : ''} ${pl.description ? `<div class="playlist-card-desc">${pl.description}</div>` : ''}
</div>
<div class="vote-bar-wrap"><div class="vote-bar" style="width:${pct}%"></div></div> <div class="vote-bar-wrap"><div class="vote-bar" style="width:${pct}%"></div></div>
<div class="vote-info"> <div class="vote-info">
<span class="vote-count">${pl.votes} votos</span> <span class="vote-count">${pl.votes} votos</span>
${isVoted ? '<span class="voted-badge">✓ último voto</span>' : ''} ${isVoted ? '<span class="voted-badge">✓ último voto</span>' : ''}
</div> </div>
</div>
</div>
<button class="vote-btn" ${btnDisabled} onclick="castVote(${pl.id})">${btnLabel}</button> <button class="vote-btn" ${btnDisabled} onclick="castVote(${pl.id})">${btnLabel}</button>
</div>`; </div>`;
} else { } else {
return ` return `
<div class="playlist-card clickable" onclick='openTracksModal(${JSON.stringify(pl)})'> <div class="playlist-card clickable" onclick='openTracksModal(${JSON.stringify(pl)})'>
${img} ${img}
<div class="playlist-card-info">
<div class="playlist-card-name">${pl.name}</div> <div class="playlist-card-name">${pl.name}</div>
${pl.description ? `<div class="playlist-card-desc">${pl.description}</div>` : ''}
</div>
</div>`; </div>`;
} }
}).join(''); }).join('');
@@ -429,16 +434,22 @@ setInterval(fetchVotingStatus, 5000);
} }
.voting-card { position: relative; } .voting-card { position: relative; }
.voting-card-top { cursor: pointer; flex: 1; width: 100%; display: flex; flex-direction: column; align-items: center; gap: 0.4rem; } .playlist-card-clickable {
.voting-card-top:hover .playlist-card-name { color: var(--green); } display: flex;
flex-direction: row;
align-items: center;
gap: 0.75rem;
flex: 1;
min-width: 0;
cursor: pointer;
}
.playlist-card-clickable:hover .playlist-card-name { color: var(--green); }
.playlist-card-desc { .playlist-card-desc {
font-size: 0.7rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--text-muted);
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
width: 100%;
text-align: center;
} }
.voting-card.voted { border: 2px solid var(--green); } .voting-card.voted { border: 2px solid var(--green); }
@@ -448,7 +459,7 @@ setInterval(fetchVotingStatus, 5000);
background: #333; background: #333;
border-radius: 2px; border-radius: 2px;
overflow: hidden; overflow: hidden;
margin-top: 2px; margin-top: 4px;
} }
.vote-bar { height: 100%; background: var(--green); border-radius: 2px; transition: width .4s; } .vote-bar { height: 100%; background: var(--green); border-radius: 2px; transition: width .4s; }
@@ -473,9 +484,7 @@ setInterval(fetchVotingStatus, 5000);
} }
.vote-btn { .vote-btn {
width: 100%; padding: .4rem .75rem;
margin-top: 4px;
padding: .35rem 0;
background: var(--green); background: var(--green);
color: #000; color: #000;
font-weight: 700; font-weight: 700;
@@ -484,6 +493,8 @@ setInterval(fetchVotingStatus, 5000);
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
transition: background .15s, opacity .15s; transition: background .15s, opacity .15s;
white-space: nowrap;
flex-shrink: 0;
} }
.vote-btn:hover:not(:disabled) { background: var(--green-dark); } .vote-btn:hover:not(:disabled) { background: var(--green-dark); }
.vote-btn:disabled { .vote-btn:disabled {
+29 -22
View File
@@ -160,54 +160,61 @@ a:hover { text-decoration: underline; }
font-size: 0.875rem; font-size: 0.875rem;
} }
/* Playlists grid */ /* Playlists list */
.playlist-grid { .playlist-grid {
display: grid; display: flex;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); flex-direction: column;
gap: 0.75rem; gap: 0.5rem;
} }
.playlist-card { .playlist-card {
background: var(--surface); background: var(--surface);
border-radius: var(--radius); border-radius: var(--radius);
padding: 0.6rem; padding: 0.75rem;
cursor: pointer; transition: background 0.15s;
transition: background 0.15s, transform 0.1s;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
align-items: center; align-items: center;
gap: 0.4rem; gap: 0.75rem;
text-align: center;
} }
.playlist-card.clickable:hover { background: var(--surface2); transform: scale(1.02); cursor: pointer; } .playlist-card.clickable { cursor: pointer; }
.playlist-card.clickable:active { transform: scale(0.98); } .playlist-card.clickable:hover { background: var(--surface2); }
.playlist-card.clickable:active { background: #333; }
.playlist-thumb { .playlist-thumb {
width: 100%; width: 52px;
aspect-ratio: 1; height: 52px;
object-fit: cover; object-fit: cover;
border-radius: 6px; border-radius: 6px;
flex-shrink: 0;
} }
.playlist-thumb-placeholder { .playlist-thumb-placeholder {
width: 100%; width: 52px;
aspect-ratio: 1; height: 52px;
background: var(--surface2); background: var(--surface2);
border-radius: 6px; border-radius: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 2rem; font-size: 1.8rem;
container-type: inline-size; flex-shrink: 0;
}
.playlist-thumb-emoji { font-size: 1.8rem; }
.playlist-card-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.15rem;
} }
.playlist-thumb-emoji { font-size: 55cqi; }
.playlist-card-name { .playlist-card-name {
font-size: 0.78rem; font-size: 0.9rem;
font-weight: 500; font-weight: 600;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
width: 100%;
} }
/* ── Admin ── */ /* ── Admin ── */