From 1fd7b9f9cf7b8c891a7795c06061f1fa4ae11c3c Mon Sep 17 00:00:00 2001 From: Leopere Date: Sun, 9 Mar 2025 17:09:33 -0400 Subject: [PATCH] Add Chrome-specific video fallback with play button and lightbox --- .../static/css/chrome-video-fallback.css | 98 +++++++++++++++++++ .../public/static/css/custom-video.css | 35 +++++++ .../public/static/js/chrome-video-fallback.js | 93 ++++++++++++++++++ .../static/js/chrome-video-fallback.min.js | 1 + .../public/static/js/videojs-player.js | 45 +++++++++ .../public/static/js/videojs-player.min.js | 1 + .../chocolate/layouts/partials/head.html | 11 ++- 7 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 docker/showerloop/public/static/css/chrome-video-fallback.css create mode 100644 docker/showerloop/public/static/css/custom-video.css create mode 100644 docker/showerloop/public/static/js/chrome-video-fallback.js create mode 100644 docker/showerloop/public/static/js/chrome-video-fallback.min.js create mode 100644 docker/showerloop/public/static/js/videojs-player.js create mode 100644 docker/showerloop/public/static/js/videojs-player.min.js diff --git a/docker/showerloop/public/static/css/chrome-video-fallback.css b/docker/showerloop/public/static/css/chrome-video-fallback.css new file mode 100644 index 0000000..010d5f2 --- /dev/null +++ b/docker/showerloop/public/static/css/chrome-video-fallback.css @@ -0,0 +1,98 @@ +/* Chrome-specific video fallback styles */ + +/* Poster image styling */ +.chrome-poster-image { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + z-index: 1; + border-radius: 4px; +} + +/* Play button overlay */ +.chrome-play-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + z-index: 2; +} + +.chrome-play-button { + width: 68px; + height: 48px; + transition: transform 0.2s; + filter: drop-shadow(0 0 5px rgba(0,0,0,0.5)); +} + +.chrome-play-overlay:hover .chrome-play-button { + transform: scale(1.1); +} + +/* Video lightbox */ +.video-lightbox { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.85); + display: flex; + justify-content: center; + align-items: center; + z-index: 9999; +} + +.video-lightbox-content { + position: relative; + width: 90%; + max-width: 960px; +} + +.video-lightbox video { + width: 100%; + max-height: 90vh; + border-radius: 4px; +} + +.close-lightbox { + position: absolute; + top: -40px; + right: 0; + background: none; + border: none; + color: white; + font-size: 30px; + cursor: pointer; + z-index: 10; + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; +} + +.close-lightbox:hover { + color: #f00; +} + +/* Mobile optimizations */ +@media (max-width: 768px) { + .video-lightbox-content { + width: 95%; + } + + .close-lightbox { + top: -35px; + right: 0; + } +} \ No newline at end of file diff --git a/docker/showerloop/public/static/css/custom-video.css b/docker/showerloop/public/static/css/custom-video.css new file mode 100644 index 0000000..b1b8310 --- /dev/null +++ b/docker/showerloop/public/static/css/custom-video.css @@ -0,0 +1,35 @@ +/* Custom VideoJS styling */ +.video-container { + position: relative; + width: 100%; + /* Add some bottom padding to ensure controls are visible */ + margin-bottom: 10px; +} + +/* Ensure the video-js player is properly contained */ +.video-js { + width: 100%; + height: auto; + /* Ensure controls are within the container */ + position: relative; +} + +/* Fix control bar positioning */ +.video-js .vjs-control-bar { + /* Ensure the control bar stays within the player's dimensions */ + bottom: 0; + width: 100%; +} + +/* Additional responsive adjustments */ +@media (max-width: 768px) { + .video-js { + /* Ensure the video fits on smaller screens */ + max-height: 300px; + } + + .video-container { + /* More bottom space on mobile */ + margin-bottom: 15px; + } +} \ No newline at end of file diff --git a/docker/showerloop/public/static/js/chrome-video-fallback.js b/docker/showerloop/public/static/js/chrome-video-fallback.js new file mode 100644 index 0000000..3aa750b --- /dev/null +++ b/docker/showerloop/public/static/js/chrome-video-fallback.js @@ -0,0 +1,93 @@ +/** + * Chrome-specific video fallback + * Since Chrome has issues with VideoJS/HLS, this script provides a fallback + * that replaces video players with play buttons that open videos in a new page. + */ +document.addEventListener('DOMContentLoaded', function() { + // Only run this script for Chrome browsers + const isChrome = /Chrome/.test(navigator.userAgent) && !/Edge/.test(navigator.userAgent) && !/OPR/.test(navigator.userAgent); + + if (!isChrome) { + return; // Exit if not Chrome + } + + // Videos to handle with IDs and their mp4 sources + const videoMappings = { + 'video-hero': '/static/videos/video1.mp4', + 'video2': '/static/videos/video2.mp4', + 'video3': '/static/videos/video3.mp4' + }; + + // Process each video + Object.keys(videoMappings).forEach(function(videoId) { + const videoElement = document.getElementById(videoId); + if (!videoElement) return; + + const videoContainer = videoElement.closest('.video-container'); + if (!videoContainer) return; + + // Get poster image + const posterUrl = videoElement.getAttribute('poster'); + + // Create play button overlay + const playButtonOverlay = document.createElement('div'); + playButtonOverlay.className = 'chrome-play-overlay'; + playButtonOverlay.innerHTML = ` +
+ + + + +
+ `; + + // Style the container for positioning + videoContainer.style.position = 'relative'; + + // Create a poster image as background + if (posterUrl) { + const posterImage = document.createElement('div'); + posterImage.className = 'chrome-poster-image'; + posterImage.style.backgroundImage = `url(${posterUrl})`; + videoContainer.appendChild(posterImage); + } + + // Add click event to open the video in a new page/overlay + playButtonOverlay.addEventListener('click', function() { + // Create the lightbox overlay + const lightbox = document.createElement('div'); + lightbox.className = 'video-lightbox'; + lightbox.innerHTML = ` +
+ + +
+ `; + + // Add the lightbox to the body + document.body.appendChild(lightbox); + + // Add close functionality + const closeButton = lightbox.querySelector('.close-lightbox'); + closeButton.addEventListener('click', function() { + document.body.removeChild(lightbox); + }); + + // Close when clicking outside the video + lightbox.addEventListener('click', function(e) { + if (e.target === lightbox) { + document.body.removeChild(lightbox); + } + }); + }); + + // Hide the original video element + videoElement.style.display = 'none'; + + // Add the play button to the container + videoContainer.appendChild(playButtonOverlay); + }); +}); \ No newline at end of file diff --git a/docker/showerloop/public/static/js/chrome-video-fallback.min.js b/docker/showerloop/public/static/js/chrome-video-fallback.min.js new file mode 100644 index 0000000..4ddfc41 --- /dev/null +++ b/docker/showerloop/public/static/js/chrome-video-fallback.min.js @@ -0,0 +1 @@ +document.addEventListener("DOMContentLoaded",function(){const e=/Chrome/.test(navigator.userAgent)&&!/Edge/.test(navigator.userAgent)&&!/OPR/.test(navigator.userAgent);if(!e)return;const t={"video-hero":"/static/videos/video1.mp4",video2:"/static/videos/video2.mp4",video3:"/static/videos/video3.mp4"};Object.keys(t).forEach(function(e){const o=document.getElementById(e);if(!o)return;const n=o.closest(".video-container");if(!n)return;const i=o.getAttribute("poster"),r=document.createElement("div");if(r.className="chrome-play-overlay",r.innerHTML='\n
\n \n \n \n \n
\n ',n.style.position="relative",i){const e=document.createElement("div");e.className="chrome-poster-image",e.style.backgroundImage=`url(${i})`,n.appendChild(e)}r.addEventListener("click",function(){const o=document.createElement("div");o.className="video-lightbox",o.innerHTML=`\n
\n \n \n
\n `,document.body.appendChild(o);const n=o.querySelector(".close-lightbox");n.addEventListener("click",function(){document.body.removeChild(o)}),o.addEventListener("click",function(e){e.target===o&&document.body.removeChild(o)})}),o.style.display="none",n.appendChild(r)})}); \ No newline at end of file diff --git a/docker/showerloop/public/static/js/videojs-player.js b/docker/showerloop/public/static/js/videojs-player.js new file mode 100644 index 0000000..7c77186 --- /dev/null +++ b/docker/showerloop/public/static/js/videojs-player.js @@ -0,0 +1,45 @@ +/** + * VideoJS Player initialization + * This script initializes VideoJS for all video elements, handling both + * videos with data-setup attribute and regular videos. + */ +document.addEventListener('DOMContentLoaded', function() { + // First, initialize all videos with the data-setup attribute + // VideoJS will automatically process these + + // Then find any remaining videos (without video-js class) that need to be initialized + const regularVideos = document.querySelectorAll('video:not(.video-js)'); + + if (regularVideos.length) { + regularVideos.forEach(function(video) { + // Ensure the video has an ID + const id = video.id || 'video-' + Math.floor(Math.random() * 1000000); + video.id = id; + + // Add VideoJS class + video.classList.add('video-js'); + video.classList.add('vjs-big-play-centered'); + + // Initialize with default options + videojs(id, { + controls: true, + autoplay: false, + preload: 'auto' + }); + }); + } + + // Additional check to ensure all video.video-js elements are initialized + // This helps with videos that have the class but weren't auto-initialized + const videojsElements = document.querySelectorAll('video.video-js'); + videojsElements.forEach(function(videoElement) { + const id = videoElement.id; + if (id) { + // Check if this element already has a VideoJS instance + if (!videojs.getPlayers()[id]) { + // Initialize VideoJS for this element + videojs(id); + } + } + }); +}); \ No newline at end of file diff --git a/docker/showerloop/public/static/js/videojs-player.min.js b/docker/showerloop/public/static/js/videojs-player.min.js new file mode 100644 index 0000000..7c7ca56 --- /dev/null +++ b/docker/showerloop/public/static/js/videojs-player.min.js @@ -0,0 +1 @@ +document.addEventListener("DOMContentLoaded",function(){const e=document.querySelectorAll("video:not(.video-js)");e.length&&e.forEach(function(e){const t=e.id||"video-"+Math.floor(1e6*Math.random());e.id=t,e.classList.add("video-js"),e.classList.add("vjs-big-play-centered"),videojs(t,{controls:!0,autoplay:!1,preload:"auto"})});const t=document.querySelectorAll("video.video-js");t.forEach(function(e){const t=e.id;t&&!videojs.getPlayers()[t]&&videojs(t)})}); \ No newline at end of file diff --git a/docker/showerloop/public/themes/chocolate/layouts/partials/head.html b/docker/showerloop/public/themes/chocolate/layouts/partials/head.html index 48ba4cd..570b15b 100644 --- a/docker/showerloop/public/themes/chocolate/layouts/partials/head.html +++ b/docker/showerloop/public/themes/chocolate/layouts/partials/head.html @@ -163,7 +163,12 @@ - - - + + + + + + + +