From 2d71a136210487da3e01fbfd7c015ad58b415a3d Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 25 Nov 2025 19:50:36 -0800 Subject: [PATCH] Add advanced gallery features: lazy loading, sorting, and loading animations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implement lazy loading for video thumbnails using Intersection Observer - Only load thumbnails when they enter viewport (50px margin) - Smooth fade-in transition when thumbnails load - Significantly reduces initial page load time - Add shimmer loading animation for thumbnail containers - Gradient shimmer effect while videos are loading - Automatic removal once content loads - Professional loading state feedback - Add video sorting functionality - Sort by: Newest/Oldest, Name (A-Z/Z-A), Size (Largest/Smallest) - Client-side sorting for instant results - Maintains lazy loading when re-rendering sorted videos - Improve error handling - Graceful fallback with placeholder icon for failed thumbnails - Better UX when videos fail to load Performance improvements especially noticeable with large video collections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- worker/video-server-enhanced.js | 201 +++++++++++++++++++++++++++++--- 1 file changed, 182 insertions(+), 19 deletions(-) diff --git a/worker/video-server-enhanced.js b/worker/video-server-enhanced.js index 56d0d81..45ef644 100644 --- a/worker/video-server-enhanced.js +++ b/worker/video-server-enhanced.js @@ -610,6 +610,30 @@ async function handlePublicGallery(bucket, kv, corsHeaders) { header { text-align: center; margin-bottom: 40px; padding: 20px; } h1 { font-size: 2.5rem; margin-bottom: 10px; } .subtitle { color: #aaa; font-size: 1.1rem; } + .controls { + display: flex; + justify-content: center; + gap: 15px; + margin-top: 20px; + flex-wrap: wrap; + } + .sort-select { + padding: 10px 20px; + background: #1a1a1a; + border: 1px solid #3a3a3a; + border-radius: 6px; + color: white; + font-size: 0.95rem; + cursor: pointer; + transition: border-color 0.2s; + } + .sort-select:hover { + border-color: #3ea6ff; + } + .sort-select:focus { + outline: none; + border-color: #3ea6ff; + } .video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); @@ -631,15 +655,30 @@ async function handlePublicGallery(bucket, kv, corsHeaders) { position: relative; width: 100%; aspect-ratio: 16/9; - background: #000; + background: linear-gradient(90deg, #1a1a1a 0%, #2a2a2a 50%, #1a1a1a 100%); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; cursor: pointer; overflow: hidden; } + @keyframes shimmer { + 0% { background-position: -200% 0; } + 100% { background-position: 200% 0; } + } + .video-thumbnail.loaded { + animation: none; + background: #000; + } .video-thumbnail video { width: 100%; height: 100%; object-fit: cover; pointer-events: none; + opacity: 0; + transition: opacity 0.3s; + } + .video-thumbnail video.loaded { + opacity: 1; } .play-overlay { position: absolute; @@ -706,11 +745,33 @@ async function handlePublicGallery(bucket, kv, corsHeaders) {

🎥 Video Gallery

${shareableVideos.length} video${shareableVideos.length === 1 ? '' : 's'} available

+ ${shareableVideos.length > 0 ? ` +
+ +
+ ` : ''}
-
+
${emptyState}