fix: filter homepage recent sections by hidden status

This commit is contained in:
Trevor Mears
2026-01-18 17:06:26 -08:00
parent b890d30253
commit f9fefa3947
9 changed files with 224 additions and 32 deletions
+75 -9
View File
@@ -980,7 +980,8 @@ video::cue {
.epg-grid {
height: calc(100vh - var(--navbar-height) - 60px);
overflow: auto;
overflow: hidden;
overflow-y: auto;
padding: var(--space-md);
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
@@ -1887,6 +1888,7 @@ kbd {
--sidebar-width: 320px;
--space-lg: 16px;
--space-xl: 24px;
--epg-sidebar-width: 180px;
}
/* Navigation - Hide text labels, show only icons */
@@ -1900,7 +1902,8 @@ kbd {
gap: 0;
}
.navbar-menu span:not(.nav-icon) {
/* Hide nav link text on mobile, but keep Now Playing visible */
.navbar-menu .nav-link span:not(.nav-icon) {
display: none;
}
@@ -2039,7 +2042,11 @@ kbd {
}
.epg-channel-info {
width: 180px;
width: var(--epg-sidebar-width);
}
.epg-time-header {
margin-left: var(--epg-sidebar-width);
}
.epg-time-slot {
@@ -4314,7 +4321,7 @@ kbd {
align-items: center;
gap: 8px;
padding: 6px 14px;
margin-right: 16px;
margin-right: var(--space-md);
background: linear-gradient(135deg, var(--color-accent) 0%, #8b5cf6 100%);
border-radius: var(--radius-full);
color: white;
@@ -4360,13 +4367,16 @@ kbd {
}
}
/* Mobile responsive */
/* Mobile responsive - show in dropdown menu */
@media (max-width: 768px) {
.now-playing-indicator {
max-width: 140px;
padding: 5px 10px;
font-size: 12px;
margin-right: 8px;
width: calc(100% - 32px);
max-width: none;
margin: 0 16px var(--space-sm) 16px;
padding: 10px 16px;
font-size: 13px;
border-radius: var(--radius-md);
justify-content: center;
}
}
@@ -4406,7 +4416,63 @@ kbd {
color: var(--color-text-bright);
}
/* Scroll Wrapper with Navigation Arrows */
.scroll-wrapper {
position: relative;
}
.scroll-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 10;
width: 40px;
height: 40px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.7);
border: 1px solid rgba(255, 255, 255, 0.1);
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition-fast);
backdrop-filter: blur(8px);
}
.scroll-arrow:hover {
background: rgba(0, 0, 0, 0.9);
border-color: var(--color-accent);
transform: translateY(-50%) scale(1.1);
}
.scroll-arrow svg {
width: 24px;
height: 24px;
}
.scroll-arrow.scroll-left {
left: -8px;
}
.scroll-arrow.scroll-right {
right: -8px;
}
.scroll-arrow.hidden {
opacity: 0;
pointer-events: none;
}
/* Hide arrows on touch devices (they can swipe) */
@media (hover: none) {
.scroll-arrow {
display: none;
}
}
.horizontal-scroll {
display: flex;
gap: 20px;
overflow-x: auto;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+5 -5
View File
@@ -38,12 +38,12 @@
<span></span>
<span></span>
</button>
<!-- Now Playing indicator for movies/series -->
<a href="#" class="now-playing-indicator hidden" id="now-playing-indicator" data-page="watch">
<span class="now-playing-icon">▶</span>
<span class="now-playing-text" id="now-playing-text">Now Playing</span>
</a>
<div class="navbar-menu" id="navbar-menu">
<!-- Now Playing indicator for movies/series -->
<a href="#" class="now-playing-indicator hidden" id="now-playing-indicator" data-page="watch">
<span class="now-playing-icon">▶</span>
<span class="now-playing-text" id="now-playing-text">Now Playing</span>
</a>
<a href="#" class="nav-link active" data-page="home">
<span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
class="icon">
+16 -2
View File
@@ -439,7 +439,7 @@ class EpgGuide {
</div>
`).join('')}
</div>
<div class="epg-scroll-container" style="overflow-y: auto; max-height: calc(100vh - 200px);">
<div class="epg-scroll-container" style="overflow: auto; max-height: calc(100vh - 200px);">
<div class="epg-spacer" style="height: ${totalHeight}px; position: relative;">
<div class="epg-channel-rows" style="position: absolute; top: 0; left: 0; right: 0;"></div>
</div>
@@ -461,11 +461,25 @@ class EpgGuide {
if (this._scrollHandler) {
this.scrollContainer?.removeEventListener('scroll', this._scrollHandler);
}
if (this._hScrollHandler) {
this.scrollContainer?.removeEventListener('scroll', this._hScrollHandler);
}
// Set up scroll handler for virtual scrolling
// Get reference to time header for horizontal scroll sync
this.timeHeader = this.container.querySelector('.epg-time-header');
// Set up scroll handler for virtual scrolling (debounced for performance)
this._scrollHandler = this.debounce(() => this.updateVisibleRows(), 16); // ~60fps
this.scrollContainer.addEventListener('scroll', this._scrollHandler);
// Set up horizontal scroll sync (instant, not debounced)
this._hScrollHandler = () => {
if (this.timeHeader && this.scrollContainer) {
this.timeHeader.style.transform = `translateX(-${this.scrollContainer.scrollLeft}px)`;
}
};
this.scrollContainer.addEventListener('scroll', this._hScrollHandler);
// Initial render of visible rows
this.updateVisibleRows();
+3
View File
@@ -1251,6 +1251,9 @@ class VideoPlayer {
* Stop playback
*/
stop() {
// Stop any running transcode session first
this.stopTranscodeSession();
if (this.hls) {
this.hls.destroy();
this.hls = null;
+105 -11
View File
@@ -35,8 +35,16 @@ class HomePage {
<div class="section-header">
<h2>Favorite Channels</h2>
</div>
<div class="horizontal-scroll channel-tiles" id="favorite-channels-list">
<div class="loading-state">Loading favorites...</div>
<div class="scroll-wrapper">
<button class="scroll-arrow scroll-left" aria-label="Scroll left">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
</button>
<div class="horizontal-scroll channel-tiles" id="favorite-channels-list">
<div class="loading-state">Loading favorites...</div>
</div>
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
</section>
@@ -44,8 +52,16 @@ class HomePage {
<div class="section-header">
<h2>Continue Watching</h2>
</div>
<div class="horizontal-scroll" id="continue-watching-list">
<div class="loading-state">Loading history...</div>
<div class="scroll-wrapper">
<button class="scroll-arrow scroll-left" aria-label="Scroll left">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
</button>
<div class="horizontal-scroll" id="continue-watching-list">
<div class="loading-state">Loading history...</div>
</div>
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
</section>
@@ -53,8 +69,16 @@ class HomePage {
<div class="section-header">
<h2>Recently Added Movies</h2>
</div>
<div class="horizontal-scroll" id="recent-movies-list">
<div class="empty-state">Coming soon</div>
<div class="scroll-wrapper">
<button class="scroll-arrow scroll-left" aria-label="Scroll left">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
</button>
<div class="horizontal-scroll" id="recent-movies-list">
<div class="empty-state">Coming soon</div>
</div>
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
</section>
@@ -62,15 +86,73 @@ class HomePage {
<div class="section-header">
<h2>Recently Added Series</h2>
</div>
<div class="horizontal-scroll" id="recent-series-list">
<div class="empty-state">Coming soon</div>
<div class="scroll-wrapper">
<button class="scroll-arrow scroll-left" aria-label="Scroll left">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
</button>
<div class="horizontal-scroll" id="recent-series-list">
<div class="empty-state">Coming soon</div>
</div>
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
</section>
</div>
`;
this.container = document.getElementById('home-content');
// Attach scroll arrow handlers
this.initScrollArrows();
}
initScrollArrows() {
this.container.querySelectorAll('.scroll-wrapper').forEach(wrapper => {
const scrollContainer = wrapper.querySelector('.horizontal-scroll');
const leftBtn = wrapper.querySelector('.scroll-left');
const rightBtn = wrapper.querySelector('.scroll-right');
if (!scrollContainer || !leftBtn || !rightBtn) return;
const scrollAmount = 300; // pixels to scroll per click
leftBtn.addEventListener('click', () => {
scrollContainer.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
});
rightBtn.addEventListener('click', () => {
scrollContainer.scrollBy({ left: scrollAmount, behavior: 'smooth' });
});
// Update arrow visibility based on scroll position
const updateArrows = () => {
const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;
leftBtn.classList.toggle('hidden', scrollLeft <= 0);
rightBtn.classList.toggle('hidden', scrollLeft + clientWidth >= scrollWidth - 5);
};
// Store reference for later updates
wrapper._updateArrows = updateArrows;
scrollContainer.addEventListener('scroll', updateArrows);
// Initial check after content loads
setTimeout(updateArrows, 100);
});
}
/**
* Re-check scroll arrow visibility for all sections
* Call this after dynamically loading content
*/
updateScrollArrows() {
this.container?.querySelectorAll('.scroll-wrapper').forEach(wrapper => {
if (wrapper._updateArrows) {
wrapper._updateArrows();
}
});
}
async loadDashboardData() {
if (this.isLoading) return;
this.isLoading = true;
@@ -147,6 +229,9 @@ class HomePage {
});
});
// Update scroll arrows after content renders
this.updateScrollArrows();
} catch (err) {
console.error('[Dashboard] Error loading favorite channels:', err);
list.innerHTML = '<div class="empty-state hint">Error loading favorites</div>';
@@ -161,7 +246,7 @@ class HomePage {
return `
<div class="channel-tile" data-channel-id="${channel.id}" data-source-id="${channel.sourceId}">
<div class="tile-logo">
<img src="${logoUrl}" alt="${name}" loading="lazy" onerror="this.src='/img/placeholder.png'">
<img src="${logoUrl}" alt="${name}" loading="lazy" onerror="this.onerror=null;this.src='/img/placeholder.png'">
</div>
<div class="tile-name" title="${name}">${name}</div>
</div>
@@ -223,6 +308,9 @@ class HomePage {
}
});
});
// Update scroll arrows after content renders
this.updateScrollArrows();
}
navigateToSeries(item) {
@@ -268,6 +356,9 @@ class HomePage {
if (item) this.playItem(item);
});
});
// Update scroll arrows after content renders
this.updateScrollArrows();
} catch (err) {
console.error('[Dashboard] Error loading recent movies:', err);
}
@@ -294,6 +385,9 @@ class HomePage {
if (item) this.navigateToSeries(item);
});
});
// Update scroll arrows after content renders
this.updateScrollArrows();
} catch (err) {
console.error('[Dashboard] Error loading recent series:', err);
}
@@ -311,7 +405,7 @@ class HomePage {
return `
<div class="dashboard-card" data-id="${item_id}" data-type="${type}">
<div class="card-image">
<img src="${posterUrl}" alt="${data.title || item.name}" loading="lazy" onerror="this.src='/img/poster-placeholder.jpg'">
<img src="${posterUrl}" alt="${data.title || item.name}" loading="lazy" onerror="this.onerror=null;this.src='/img/poster-placeholder.jpg'">
<div class="progress-bar-container">
<div class="progress-bar" style="width: ${percent}%"></div>
</div>
@@ -336,7 +430,7 @@ class HomePage {
return `
<div class="dashboard-card" data-id="${item_id}" data-type="${type}">
<div class="card-image">
<img src="${posterUrl}" alt="${item.name}" loading="lazy" onerror="this.src='/img/poster-placeholder.jpg'">
<img src="${posterUrl}" alt="${item.name}" loading="lazy" onerror="this.onerror=null;this.src='/img/poster-placeholder.jpg'">
<div class="play-icon-overlay">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
</div>
+9 -2
View File
@@ -888,7 +888,14 @@ class WatchPage {
renderDetails() {
if (!this.content) return;
this.posterEl.src = this.content.poster || '/img/placeholder.png';
const isChannel = this.content.type === 'channel' || !this.content.type; // Default to channel if unknown
const fallback = isChannel ? '/img/placeholder.png' : '/img/poster-placeholder.jpg';
this.posterEl.onerror = () => {
this.posterEl.onerror = null;
this.posterEl.src = fallback;
};
this.posterEl.src = this.content.poster || fallback;
this.posterEl.alt = this.content.title || '';
this.contentTitleEl.textContent = this.content.title || '';
this.yearEl.textContent = this.content.year || '';
@@ -984,7 +991,7 @@ class WatchPage {
<div class="watch-recommended-card" data-id="${movie.stream_id}" data-source="${sourceId}">
<img src="${movie.stream_icon || movie.cover || '/img/placeholder.png'}"
alt="${movie.name}"
onerror="this.src='/img/placeholder.png'" loading="lazy">
onerror="this.onerror=null;this.src='/img/placeholder.png'" loading="lazy">
<p>${movie.name}</p>
</div>
`).join('');