load more button and other device support

This commit is contained in:
Simon
2026-02-08 15:54:55 +00:00
parent f71d8e3ee1
commit 5a2021580d
3 changed files with 137 additions and 1 deletions

View File

@@ -112,6 +112,7 @@ async function loadVideos() {
try { try {
isLoading = true; isLoading = true;
updateLoadMoreState();
const response = await fetch('/api/videos', { const response = await fetch('/api/videos', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -128,6 +129,7 @@ async function loadVideos() {
console.error("Failed to load videos:", err); console.error("Failed to load videos:", err);
} finally { } finally {
isLoading = false; isLoading = false;
updateLoadMoreState();
} }
} }
@@ -179,6 +181,13 @@ async function initApp() {
observer.observe(sentinel); observer.observe(sentinel);
} }
const loadMoreBtn = document.getElementById('load-more-btn');
if (loadMoreBtn) {
loadMoreBtn.onclick = () => {
loadVideos();
};
}
await loadVideos(); await loadVideos();
} }
@@ -263,6 +272,7 @@ function handleSearch(value) {
renderedVideoIds.clear(); renderedVideoIds.clear();
const grid = document.getElementById('video-grid'); const grid = document.getElementById('video-grid');
if (grid) grid.innerHTML = ""; if (grid) grid.innerHTML = "";
updateLoadMoreState();
loadVideos(); loadVideos();
} }
@@ -371,6 +381,7 @@ function resetAndReload() {
renderedVideoIds.clear(); renderedVideoIds.clear();
const grid = document.getElementById('video-grid'); const grid = document.getElementById('video-grid');
if (grid) grid.innerHTML = ""; if (grid) grid.innerHTML = "";
updateLoadMoreState();
loadVideos(); loadVideos();
} }
@@ -384,6 +395,13 @@ function ensureViewportFilled() {
} }
} }
function updateLoadMoreState() {
const loadMoreBtn = document.getElementById('load-more-btn');
if (!loadMoreBtn) return;
loadMoreBtn.disabled = isLoading || !hasNextPage;
loadMoreBtn.style.display = hasNextPage ? 'flex' : 'none';
}
function renderMenu() { function renderMenu() {
const session = getSession(); const session = getSession();
const serverEntries = getServerEntries(); const serverEntries = getServerEntries();

View File

@@ -81,11 +81,14 @@
<main id="video-grid" class="grid-container"></main> <main id="video-grid" class="grid-container"></main>
<div id="sentinel"></div> <div id="sentinel"></div>
<button id="load-more-btn" class="load-more-btn" title="Load More">
<img class="icon-svg" src="https://cdn.jsdelivr.net/npm/heroicons@2.0.13/24/outline/chevron-down.svg" alt="Load More">
</button>
<div id="video-modal" class="modal"> <div id="video-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="close" onclick="closePlayer()">&times;</span> <span class="close" onclick="closePlayer()">&times;</span>
<video id="player" controls autoplay></video> <video id="player" controls autoplay playsinline webkit-playsinline></video>
</div> </div>
</div> </div>

View File

@@ -122,6 +122,11 @@ body.theme-light {
color: var(--accent); color: var(--accent);
} }
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
/* CDN-served icon images (Heroicons) */ /* CDN-served icon images (Heroicons) */
.icon-svg { .icon-svg {
width: 24px; width: 24px;
@@ -450,6 +455,34 @@ body.theme-light .setting-item select option {
display: block; display: block;
} }
.load-more-btn {
position: sticky;
left: 50%;
transform: translateX(-50%);
margin: 16px auto 32px auto;
width: 52px;
height: 52px;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--bg-secondary);
color: var(--text-primary);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
z-index: 10;
}
.load-more-btn:hover {
background: var(--bg-tertiary);
}
.load-more-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Grid Container */ /* Grid Container */
.grid-container { .grid-container {
display: grid; display: grid;
@@ -465,6 +498,88 @@ body.theme-light .setting-item select option {
gap: 12px; gap: 12px;
padding: 16px; padding: 16px;
} }
.top-bar {
flex-wrap: wrap;
height: auto;
padding: 12px 16px;
}
.search-container {
order: 3;
width: 100%;
max-width: 100%;
}
.actions {
order: 2;
width: 100%;
justify-content: flex-end;
}
}
@media (max-width: 480px) {
.logo {
font-size: 18px;
}
.icon-btn {
width: 44px;
height: 44px;
}
}
@media (min-width: 1600px) {
body {
font-size: 16px;
}
.top-bar {
height: 72px;
padding: 0 36px;
}
.grid-container {
gap: 24px;
padding: 32px 48px;
}
.video-card h4 {
font-size: 16px;
}
.video-card p {
font-size: 13px;
}
}
@media (min-width: 1920px) {
.grid-container {
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
}
@media (pointer: coarse) {
.icon-btn {
width: 52px;
height: 52px;
}
.btn-secondary {
padding: 10px 14px;
}
.setting-item select,
.input-row input {
padding: 10px 14px;
}
}
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
animation: none !important;
}
} }
/* Video Card */ /* Video Card */