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