Show playlists instead of the branding hero on the empty home
This commit is contained in:
@@ -1936,6 +1936,52 @@ function renderSidebar() {
|
|||||||
});
|
});
|
||||||
updateQueueBadge();
|
updateQueueBadge();
|
||||||
updateDownloadBadge();
|
updateDownloadBadge();
|
||||||
|
renderHomePlaylists();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The empty player pane (nothing playing yet) shows the branding hero. Once
|
||||||
|
// this device has playlists, they take that space instead — the hero stays as
|
||||||
|
// the fallback so a first-time visitor still gets the landing.
|
||||||
|
// Driven from renderSidebar() so every playlist mutation refreshes both.
|
||||||
|
function renderHomePlaylists() {
|
||||||
|
const wrap = document.getElementById('homePlaylists');
|
||||||
|
const hero = document.querySelector('#playerPlaceholder .hero');
|
||||||
|
const grid = document.getElementById('homePlGrid');
|
||||||
|
if (!wrap || !hero || !grid) return;
|
||||||
|
|
||||||
|
const lists = data.playlists || [];
|
||||||
|
wrap.classList.toggle('hidden', !lists.length);
|
||||||
|
hero.classList.toggle('hidden', !!lists.length);
|
||||||
|
// The hero is centered art; the grid wants the full box, so the placeholder
|
||||||
|
// switches from centering to stretching (and tightens its padding).
|
||||||
|
if (els.placeholder) els.placeholder.classList.toggle('showing-playlists', !!lists.length);
|
||||||
|
if (!lists.length) { grid.innerHTML = ''; return; }
|
||||||
|
|
||||||
|
grid.innerHTML = '';
|
||||||
|
for (const pl of lists) {
|
||||||
|
const count = pl.videos.length;
|
||||||
|
const thumb = (pl.videos.find((v) => v && v.thumbnail) || {}).thumbnail || '';
|
||||||
|
const card = document.createElement('button');
|
||||||
|
card.className = 'home-pl-card';
|
||||||
|
card.type = 'button';
|
||||||
|
card.innerHTML = `
|
||||||
|
<span class="home-pl-thumb">
|
||||||
|
${thumb ? `<img src="${escapeHtml(thumb)}" alt="" loading="lazy" />`
|
||||||
|
: '<span class="home-pl-thumb-fallback">🎵</span>'}
|
||||||
|
<span class="home-pl-play" title="Play all">▶</span>
|
||||||
|
</span>
|
||||||
|
<span class="home-pl-name"></span>
|
||||||
|
<span class="home-pl-count">${count} video${count === 1 ? '' : 's'}</span>`;
|
||||||
|
card.querySelector('.home-pl-name').textContent = pl.name;
|
||||||
|
card.title = pl.name;
|
||||||
|
card.addEventListener('click', () => { view = { type: 'playlist', id: pl.id }; render(); });
|
||||||
|
card.querySelector('.home-pl-play').addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation(); // the ▶ badge plays; the rest of the card opens the list
|
||||||
|
if (count) playFromList(pl.videos, 0, 'playlist:' + pl.id);
|
||||||
|
else toast('That playlist is empty');
|
||||||
|
});
|
||||||
|
grid.appendChild(card);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function currentList() {
|
function currentList() {
|
||||||
@@ -3263,6 +3309,9 @@ function wireUI() {
|
|||||||
$('sidebarProfileCopy').addEventListener('click', copyProfileLink);
|
$('sidebarProfileCopy').addEventListener('click', copyProfileLink);
|
||||||
$('sidebarProfileShare').addEventListener('click', shareProfileLink);
|
$('sidebarProfileShare').addEventListener('click', shareProfileLink);
|
||||||
|
|
||||||
|
// ---- Empty-home playlist grid ----
|
||||||
|
$('homePlNewBtn').addEventListener('click', () => newPlaylist(null));
|
||||||
|
|
||||||
els.searchForm.addEventListener('submit', async (e) => {
|
els.searchForm.addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const q = els.searchInput.value.trim();
|
const q = els.searchInput.value.trim();
|
||||||
|
|||||||
@@ -121,6 +121,14 @@
|
|||||||
<button class="chip" data-q="podcast highlights">podcasts</button>
|
<button class="chip" data-q="podcast highlights">podcasts</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Replaces the hero once this device has playlists (renderHomePlaylists) -->
|
||||||
|
<div id="homePlaylists" class="home-pl hidden">
|
||||||
|
<div class="home-pl-head">
|
||||||
|
<span class="home-pl-title">Your playlists</span>
|
||||||
|
<button id="homePlNewBtn" class="home-pl-new" type="button">+ New</button>
|
||||||
|
</div>
|
||||||
|
<div id="homePlGrid" class="home-pl-grid"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="bufferSpinner" class="spinner hidden"></div>
|
<div id="bufferSpinner" class="spinner hidden"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -363,6 +363,61 @@ body::after {
|
|||||||
animation: heroIn 0.6s var(--ease) both;
|
animation: heroIn 0.6s var(--ease) both;
|
||||||
}
|
}
|
||||||
@keyframes heroIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
|
@keyframes heroIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
|
||||||
|
|
||||||
|
/* Empty home: the playlist grid takes the hero's place once playlists exist */
|
||||||
|
.player-placeholder.showing-playlists { padding: 16px; align-items: stretch; }
|
||||||
|
.home-pl {
|
||||||
|
flex: 1 1 auto; align-self: stretch; min-width: 0; max-height: 100%;
|
||||||
|
display: flex; flex-direction: column; gap: 10px;
|
||||||
|
text-align: left; overflow: hidden;
|
||||||
|
animation: heroIn 0.5s var(--ease) both;
|
||||||
|
}
|
||||||
|
.home-pl-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-shrink: 0; }
|
||||||
|
.home-pl-title { font-family: var(--display); font-size: 17px; font-weight: 700; color: var(--text); }
|
||||||
|
.home-pl-new {
|
||||||
|
padding: 5px 10px; font-size: 12px; cursor: pointer;
|
||||||
|
color: var(--text-2); background: var(--bg-2);
|
||||||
|
border: 1px solid var(--line); border-radius: var(--radius-sm);
|
||||||
|
transition: background 0.16s, color 0.16s, border-color 0.16s;
|
||||||
|
}
|
||||||
|
.home-pl-new:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||||
|
.home-pl-grid {
|
||||||
|
display: grid; grid-template-columns: repeat(auto-fill, minmax(122px, 1fr));
|
||||||
|
gap: 12px; align-content: start;
|
||||||
|
overflow-y: auto; scrollbar-gutter: stable; padding-right: 4px;
|
||||||
|
}
|
||||||
|
.home-pl-card {
|
||||||
|
display: flex; flex-direction: column; gap: 6px;
|
||||||
|
padding: 0; border: 0; background: none; color: inherit;
|
||||||
|
text-align: left; cursor: pointer; min-width: 0;
|
||||||
|
}
|
||||||
|
.home-pl-thumb {
|
||||||
|
position: relative; display: block; aspect-ratio: 16 / 9;
|
||||||
|
border-radius: var(--radius-sm); overflow: hidden;
|
||||||
|
background: var(--bg-3); border: 1px solid var(--line-soft);
|
||||||
|
transition: border-color 0.16s, transform 0.16s var(--ease);
|
||||||
|
}
|
||||||
|
.home-pl-card:hover .home-pl-thumb { border-color: var(--accent); transform: translateY(-2px); }
|
||||||
|
.home-pl-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||||
|
.home-pl-thumb-fallback { position: absolute; inset: 0; display: grid; place-items: center; font-size: 22px; }
|
||||||
|
.home-pl-play {
|
||||||
|
position: absolute; right: 6px; bottom: 6px;
|
||||||
|
width: 26px; height: 26px; display: grid; place-items: center;
|
||||||
|
font-size: 11px; color: #fff; border-radius: 50%;
|
||||||
|
background: rgba(0, 0, 0, 0.62); backdrop-filter: blur(4px);
|
||||||
|
opacity: 0; transition: opacity 0.16s, background 0.16s;
|
||||||
|
}
|
||||||
|
.home-pl-card:hover .home-pl-play, .home-pl-play:focus-visible { opacity: 1; }
|
||||||
|
.home-pl-play:hover { background: var(--accent); }
|
||||||
|
.home-pl-name {
|
||||||
|
font-size: 13px; font-weight: 600; color: var(--text);
|
||||||
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.home-pl-count { font-size: 11px; color: var(--text-dim); }
|
||||||
|
/* Touch devices have no hover — keep the play badge permanently visible */
|
||||||
|
@media (hover: none) {
|
||||||
|
.home-pl-play { opacity: 1; }
|
||||||
|
}
|
||||||
.ph-logo {
|
.ph-logo {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
width: 88px; height: 88px;
|
width: 88px; height: 88px;
|
||||||
@@ -1366,6 +1421,13 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
|
|||||||
.app.sidebar-open .sidebar { transform: translateX(0); }
|
.app.sidebar-open .sidebar { transform: translateX(0); }
|
||||||
|
|
||||||
.app.sidebar-open .sidebar-backdrop { display: block; opacity: 1; }
|
.app.sidebar-open .sidebar-backdrop { display: block; opacity: 1; }
|
||||||
|
|
||||||
|
/* Empty-home playlist grid: the player stage is short on phones, so pack in
|
||||||
|
more, smaller cards rather than one oversized full-width column. */
|
||||||
|
.player-placeholder.showing-playlists { padding: 12px; }
|
||||||
|
.home-pl-grid { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 10px; }
|
||||||
|
.home-pl-title { font-size: 15px; }
|
||||||
|
.home-pl-name { font-size: 12px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Very narrow screens (e.g. 320px) — keep the topbar usable and the drawer
|
/* Very narrow screens (e.g. 320px) — keep the topbar usable and the drawer
|
||||||
|
|||||||
Reference in New Issue
Block a user