Refactor video thumbnail handling and improve overlay positioning for enhanced user experience
This commit is contained in:
		@@ -52,7 +52,9 @@
 | 
			
		||||
			background-color: #444;
 | 
			
		||||
			aspect-ratio: 16/9;
 | 
			
		||||
			width: 20vw;
 | 
			
		||||
			transition: width 0.3s ease, box-shadow 0.3s ease;
 | 
			
		||||
			transition: width 0.3s ease, box-shadow 0.3s ease, left 0.3s ease;
 | 
			
		||||
			transform: translate(-50%, 0);
 | 
			
		||||
			position: fixed;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.video-thumbnail.focussed {
 | 
			
		||||
@@ -104,6 +106,7 @@
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			height: 100%;
 | 
			
		||||
			display: block;
 | 
			
		||||
			position: fixed;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#video-overlay-container #back-button { /* Back button is now inside the container */
 | 
			
		||||
@@ -299,7 +302,7 @@
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        let videoThumbnails = [];
 | 
			
		||||
        let videoInfo = [];
 | 
			
		||||
        let selectedThumbnailIndex = 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -314,12 +317,19 @@
 | 
			
		||||
            let index;
 | 
			
		||||
            if (append) {
 | 
			
		||||
                $("#video-container").append(thumbnail);
 | 
			
		||||
				index = videoThumbnails.length;
 | 
			
		||||
                videoThumbnails.push(thumbnail)
 | 
			
		||||
				index = videoInfo.length;
 | 
			
		||||
                videoInfo.push({
 | 
			
		||||
					thumbnail,
 | 
			
		||||
					data
 | 
			
		||||
                })
 | 
			
		||||
            } else {
 | 
			
		||||
				$("#video-container").prepend(thumbnail);
 | 
			
		||||
				index = 0;
 | 
			
		||||
				videoThumbnails.unshift(thumbnail);
 | 
			
		||||
				videoInfo.unshift({
 | 
			
		||||
					thumbnail,
 | 
			
		||||
					data
 | 
			
		||||
				});
 | 
			
		||||
                selectedThumbnailIndex++;
 | 
			
		||||
			}
 | 
			
		||||
            if (selected) {
 | 
			
		||||
                thumbnail.classList.add("focussed");
 | 
			
		||||
@@ -332,62 +342,35 @@
 | 
			
		||||
         * @param index The index of the thumbnail to select.
 | 
			
		||||
         */
 | 
			
		||||
        function selectThumbnail(index) {
 | 
			
		||||
			if (index < 0 || index >= videoThumbnails.length) return; // Out of bounds check
 | 
			
		||||
			if (selectedThumbnailIndex !== -1 && videoThumbnails[selectedThumbnailIndex]) {
 | 
			
		||||
				videoThumbnails[selectedThumbnailIndex].classList.remove("focussed");
 | 
			
		||||
			if (index < 0 || index >= videoInfo.length) return; // Out of bounds check
 | 
			
		||||
			if (selectedThumbnailIndex !== -1 && videoInfo[selectedThumbnailIndex]) {
 | 
			
		||||
				videoInfo[selectedThumbnailIndex].thumbnail.classList.remove("focussed");
 | 
			
		||||
			}
 | 
			
		||||
			selectedThumbnailIndex = index;
 | 
			
		||||
			videoThumbnails[selectedThumbnailIndex].classList.add("focussed");
 | 
			
		||||
            // $("#video-container")[0].style.position = "relative";
 | 
			
		||||
            // $("#video-container")[0].style.left = (-index * 5) + "vw";
 | 
			
		||||
			videoInfo[selectedThumbnailIndex].thumbnail.classList.add("focussed");
 | 
			
		||||
            for (let i = 0; i < videoInfo.length; i++) {
 | 
			
		||||
				if (i < selectedThumbnailIndex - 1) {
 | 
			
		||||
					videoInfo[i].thumbnail.style.left = "-20%";
 | 
			
		||||
				} else if (i === selectedThumbnailIndex - 1) {
 | 
			
		||||
                    videoInfo[i].thumbnail.style.left = "15%";
 | 
			
		||||
				} else if (i === selectedThumbnailIndex) {
 | 
			
		||||
					videoInfo[i].thumbnail.style.left = "50%";
 | 
			
		||||
				} else if (i === selectedThumbnailIndex + 1) {
 | 
			
		||||
					videoInfo[i].thumbnail.style.left = "85%";
 | 
			
		||||
				} else {
 | 
			
		||||
					videoInfo[i].thumbnail.style.left = "120%";
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$(document).ready(function() {
 | 
			
		||||
			// Initialize global selectors for static elements
 | 
			
		||||
			overlayContainer = $("#video-overlay-container");
 | 
			
		||||
			videoElement = overlayContainer.find(".video-player")[0];
 | 
			
		||||
			backButton = overlayContainer.find("#back-button");
 | 
			
		||||
			customControls = overlayContainer.find("#custom-video-controls");
 | 
			
		||||
			playPauseButton = customControls.find("#custom-play-pause-button");
 | 
			
		||||
			seekBar = customControls.find("#custom-seek-bar");
 | 
			
		||||
 | 
			
		||||
			// Spinner is visible by default (CSS). Video container is hidden (CSS).
 | 
			
		||||
			// Pre-set all thumbnails to a placeholder state
 | 
			
		||||
			$(".video-thumbnail").attr("src", "data:image/svg+xml,%3Csvg xmlns=\\\'http://www.w3.org/2000/svg\\\' width=\\\'100%25\\\' height=\\\'100%25\\\' viewBox=\\\'0 0 16 9\\\'%3E%3C/svg%3E");
 | 
			
		||||
 | 
			
		||||
			$.getJSON("/api/homepage", function(data) {
 | 
			
		||||
                createVideoThumbnailElement(data.currentVideo, true, true);
 | 
			
		||||
                for (let i = 0; i < 10; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    createVideoThumbnailElement(data.nextVideo, false, true);
 | 
			
		||||
                }
 | 
			
		||||
				// currentVideo = data.currentVideo;
 | 
			
		||||
                // nextVideo = data.nextVideo;
 | 
			
		||||
				// $("#current-thumb").attr("src", currentVideo.thumbnail);
 | 
			
		||||
                // $("#next-thumb").attr("src", nextVideo.thumbnail);
 | 
			
		||||
				// Consider populating prev-thumb and next-thumb here if data provides them
 | 
			
		||||
 | 
			
		||||
				hideSpinner();
 | 
			
		||||
                showVideoContainer();
 | 
			
		||||
			}).fail(function(jqXHR, textStatus, errorThrown) {
 | 
			
		||||
                console.error("Failed to load homepage data:", textStatus, errorThrown);
 | 
			
		||||
                hideSpinner();
 | 
			
		||||
                // Display a user-friendly error message
 | 
			
		||||
                if (!$('#init-error-msg').length) { // Prevent multiple error messages
 | 
			
		||||
                    $('body').append('<div id="init-error-msg" style="color:white; text-align:center; padding:20px; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); background-color:rgba(0,0,0,0.8); border-radius:8px; z-index: 10002;">Failed to load content. Please try again later.</div>');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
			// Attach event listeners that can be set up once for static controls
 | 
			
		||||
			if (playPauseButton) playPauseButton.click(handlePlayPauseClick);
 | 
			
		||||
			if (seekBar) seekBar.on('input', handleSeekBarInput);
 | 
			
		||||
			if (backButton) backButton.click(exitVideoPlayback);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			$("#play-button").click(function() {
 | 
			
		||||
				if (currentVideo && currentVideo.url && videoElement && overlayContainer) {
 | 
			
		||||
        /**
 | 
			
		||||
		 * Starts the currently selected video.
 | 
			
		||||
         */
 | 
			
		||||
        function startVideo() {
 | 
			
		||||
			showSpinner();
 | 
			
		||||
 | 
			
		||||
            let currentVideo = videoInfo[selectedThumbnailIndex].data
 | 
			
		||||
 | 
			
		||||
			// Clear previous handlers and set new ones for this specific load attempt
 | 
			
		||||
			videoElement.oncanplaythrough = null;
 | 
			
		||||
			videoElement.onerror = null;
 | 
			
		||||
@@ -435,9 +418,52 @@
 | 
			
		||||
			if (playPauseButton && playPauseButton.length) {
 | 
			
		||||
				playPauseButton.focus();
 | 
			
		||||
			}
 | 
			
		||||
            updatePlayPauseButtonState()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$(document).ready(function() {
 | 
			
		||||
			// Initialize global selectors for static elements
 | 
			
		||||
			overlayContainer = $("#video-overlay-container");
 | 
			
		||||
			videoElement = overlayContainer.find(".video-player")[0];
 | 
			
		||||
			backButton = overlayContainer.find("#back-button");
 | 
			
		||||
			customControls = overlayContainer.find("#custom-video-controls");
 | 
			
		||||
			playPauseButton = customControls.find("#custom-play-pause-button");
 | 
			
		||||
			seekBar = customControls.find("#custom-seek-bar");
 | 
			
		||||
 | 
			
		||||
			// Spinner is visible by default (CSS). Video container is hidden (CSS).
 | 
			
		||||
			// Pre-set all thumbnails to a placeholder state
 | 
			
		||||
			$(".video-thumbnail").attr("src", "data:image/svg+xml,%3Csvg xmlns=\\\'http://www.w3.org/2000/svg\\\' width=\\\'100%25\\\' height=\\\'100%25\\\' viewBox=\\\'0 0 16 9\\\'%3E%3C/svg%3E");
 | 
			
		||||
 | 
			
		||||
			$.getJSON("/api/homepage", function(data) {
 | 
			
		||||
                createVideoThumbnailElement(data.currentVideo, true, true);
 | 
			
		||||
                for (let i = 0; i < 10; i++)
 | 
			
		||||
                    createVideoThumbnailElement(data.nextVideo, false, true);
 | 
			
		||||
                for (let i = 0; i < 10; i++)
 | 
			
		||||
                    createVideoThumbnailElement(data.nextVideo, false, false);
 | 
			
		||||
				// currentVideo = data.currentVideo;
 | 
			
		||||
                // nextVideo = data.nextVideo;
 | 
			
		||||
				// $("#current-thumb").attr("src", currentVideo.thumbnail);
 | 
			
		||||
                // $("#next-thumb").attr("src", nextVideo.thumbnail);
 | 
			
		||||
				// Consider populating prev-thumb and next-thumb here if data provides them
 | 
			
		||||
 | 
			
		||||
				hideSpinner();
 | 
			
		||||
                showVideoContainer();
 | 
			
		||||
                selectThumbnail(selectedThumbnailIndex);
 | 
			
		||||
			}).fail(function(jqXHR, textStatus, errorThrown) {
 | 
			
		||||
                console.error("Failed to load homepage data:", textStatus, errorThrown);
 | 
			
		||||
                hideSpinner();
 | 
			
		||||
                // Display a user-friendly error message
 | 
			
		||||
                if (!$('#init-error-msg').length) { // Prevent multiple error messages
 | 
			
		||||
                    $('body').append('<div id="init-error-msg" style="color:white; text-align:center; padding:20px; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); background-color:rgba(0,0,0,0.8); border-radius:8px; z-index: 10002;">Failed to load content. Please try again later.</div>');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
			// Attach event listeners that can be set up once for static controls
 | 
			
		||||
			if (playPauseButton) playPauseButton.click(handlePlayPauseClick);
 | 
			
		||||
			if (seekBar) seekBar.on('input', handleSeekBarInput);
 | 
			
		||||
			if (backButton) backButton.click(exitVideoPlayback);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // --- Setup Custom Video Controls Events (session-specific for video element) ---
 | 
			
		||||
            $(videoElement).on('play.currentVideo', updatePlayPauseButtonState);
 | 
			
		||||
            $(videoElement).on('pause.currentVideo', updatePlayPauseButtonState);
 | 
			
		||||
@@ -519,16 +545,14 @@
 | 
			
		||||
 | 
			
		||||
                    case 'ArrowRight':
 | 
			
		||||
                    case 39: // ArrowRight
 | 
			
		||||
						nextIndex = Math.min(selectedThumbnailIndex + 1, videoThumbnails.length - 1);
 | 
			
		||||
						nextIndex = Math.min(selectedThumbnailIndex + 1, videoInfo.length - 1);
 | 
			
		||||
						selectThumbnail(nextIndex);
 | 
			
		||||
                        keyHandled = true;
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    case 'Enter':
 | 
			
		||||
                    case 13: // Enter
 | 
			
		||||
						if (currentIndex !== -1) {
 | 
			
		||||
                            activeFocusableSet[currentIndex].click();
 | 
			
		||||
                        }
 | 
			
		||||
						startVideo();
 | 
			
		||||
                        keyHandled = true;
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user