From 9f88869e666a9c1f2f1f3f560d7420849f103ff1 Mon Sep 17 00:00:00 2001 From: wildone Date: Fri, 9 Aug 2024 17:10:49 +1000 Subject: [PATCH] update video component. --- blocks/video/video.css | 47 ++++++++------- blocks/video/video.js | 116 +++++++++++++++++++++++++++----------- component-definition.json | 2 +- 3 files changed, 108 insertions(+), 57 deletions(-) diff --git a/blocks/video/video.css b/blocks/video/video.css index da92042..023cfc9 100644 --- a/blocks/video/video.css +++ b/blocks/video/video.css @@ -1,11 +1,10 @@ .video { - width: unset; text-align: center; - max-width: 800px; - margin: 32px auto; + max-width: 900px; + margin: 24px auto; } -.video.lazy-loading { +.video[data-embed-loaded='false']:not(.placeholder) { /* reserve an approximate space to avoid extensive layout shifts */ aspect-ratio: 16 / 9; } @@ -19,12 +18,6 @@ max-width: 100%; } -.video video[data-loading] { - /* reserve an approximate space to avoid extensive layout shifts */ - width: 100%; - aspect-ratio: 16 / 9; -} - .video .video-placeholder { width: 100%; aspect-ratio: 16 / 9; @@ -39,6 +32,13 @@ inset: 0; } +.video[data-embed-loaded='true'] .video-placeholder, +.video[data-embed-loaded='false'] .video-placeholder + * { + visibility: hidden; + height: 0; + width: 0; +} + .video .video-placeholder picture img { width: 100%; height: 100%; @@ -46,27 +46,26 @@ } .video .video-placeholder-play button { - box-sizing: border-box; position: relative; display: block; - transform: scale(3); - width: 22px; - height: 22px; - border: 2px solid; - border-radius: 20px; + width: 44px; + height: 44px; + border-radius: 50%; + outline: 2px solid; padding: 0; } .video .video-placeholder-play button::before { - content: ""; + content: ''; display: block; box-sizing: border-box; position: absolute; width: 0; - height: 10px; - border-top: 5px solid transparent; - border-bottom: 5px solid transparent; - border-left: 6px solid; - top: 4px; - left: 7px; -} + height: 24px; + border-top: 12px solid transparent; + border-bottom: 12px solid transparent; + border-left: 18px solid; + top: 50%; + left: calc(50% + 2px); + transform: translate(-50%, -50%); +} \ No newline at end of file diff --git a/blocks/video/video.js b/blocks/video/video.js index debe365..ab65ccc 100644 --- a/blocks/video/video.js +++ b/blocks/video/video.js @@ -4,37 +4,69 @@ * https://www.hlx.live/developer/block-collection/video */ -function embedYoutube(url, autoplay) { +const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + +function embedYoutube(url, autoplay, background) { const usp = new URLSearchParams(url.search); - const suffix = autoplay ? '&muted=1&autoplay=1' : ''; + let suffix = ''; + if (background || autoplay) { + const suffixParams = { + autoplay: autoplay ? '1' : '0', + mute: background ? '1' : '0', + controls: background ? '0' : '1', + disablekb: background ? '1' : '0', + loop: background ? '1' : '0', + playsinline: background ? '1' : '0', + }; + suffix = `&${Object.entries(suffixParams).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')}`; + } let vid = usp.get('v') ? encodeURIComponent(usp.get('v')) : ''; const embed = url.pathname; if (url.origin.includes('youtu.be')) { [, vid] = url.pathname.split('/'); } - return `
-
`; + return temp.children.item(0); } -function embedVimeo(url, autoplay) { +function embedVimeo(url, autoplay, background) { const [, video] = url.pathname.split('/'); - const suffix = autoplay ? '?muted=1&autoplay=1' : ''; - return `
-
`; + return temp.children.item(0); } -function getVideoElement(source, autoplay) { +function getVideoElement(source, autoplay, background) { const video = document.createElement('video'); video.setAttribute('controls', ''); - video.dataset.loading = 'true'; - video.addEventListener('loadedmetadata', () => delete video.dataset.loading); if (autoplay) video.setAttribute('autoplay', ''); + if (background) { + video.setAttribute('loop', ''); + video.setAttribute('playsinline', ''); + video.removeAttribute('controls'); + video.addEventListener('canplay', () => { + video.muted = true; + if (autoplay) video.play(); + }); + } const sourceEl = document.createElement('source'); sourceEl.setAttribute('src', source); @@ -44,49 +76,69 @@ function getVideoElement(source, autoplay) { return video; } -const loadVideoEmbed = (block, link, autoplay) => { - if (block.dataset.embedIsLoaded) { +const loadVideoEmbed = (block, link, autoplay, background) => { + if (block.dataset.embedLoaded === 'true') { return; } const url = new URL(link); const isYoutube = link.includes('youtube') || link.includes('youtu.be'); const isVimeo = link.includes('vimeo'); - const isMp4 = link.includes('.mp4'); if (isYoutube) { - block.innerHTML = embedYoutube(url, autoplay); + const embedWrapper = embedYoutube(url, autoplay, background); + block.append(embedWrapper); + embedWrapper.querySelector('iframe').addEventListener('load', () => { + block.dataset.embedLoaded = true; + }); } else if (isVimeo) { - block.innerHTML = embedVimeo(url, autoplay); - } else if (isMp4) { - block.textContent = ''; - block.append(getVideoElement(link, autoplay)); + const embedWrapper = embedVimeo(url, autoplay, background); + block.append(embedWrapper); + embedWrapper.querySelector('iframe').addEventListener('load', () => { + block.dataset.embedLoaded = true; + }); + } else { + const videoEl = getVideoElement(link, autoplay, background); + block.append(videoEl); + videoEl.addEventListener('canplay', () => { + block.dataset.embedLoaded = true; + }); } - - block.dataset.embedIsLoaded = true; }; export default async function decorate(block) { + console.log('decorating video block'); const placeholder = block.querySelector('picture'); const link = block.querySelector('a').href; block.textContent = ''; + block.dataset.embedLoaded = false; + const autoplay = block.classList.contains('autoplay'); if (placeholder) { + block.classList.add('placeholder'); const wrapper = document.createElement('div'); wrapper.className = 'video-placeholder'; - wrapper.innerHTML = '
'; - wrapper.prepend(placeholder); - wrapper.addEventListener('click', () => { - loadVideoEmbed(block, link, true); - }); + wrapper.append(placeholder); + + if (!autoplay) { + wrapper.insertAdjacentHTML( + 'beforeend', + '
', + ); + wrapper.addEventListener('click', () => { + wrapper.remove(); + loadVideoEmbed(block, link, true, false); + }); + } block.append(wrapper); - } else { - block.classList.add('lazy-loading'); + } + + if (!placeholder || autoplay) { const observer = new IntersectionObserver((entries) => { if (entries.some((e) => e.isIntersecting)) { observer.disconnect(); - loadVideoEmbed(block, link, false); - block.classList.remove('lazy-loading'); + const playOnLoad = autoplay && !prefersReducedMotion.matches; + loadVideoEmbed(block, link, playOnLoad, autoplay); } }); observer.observe(block); diff --git a/component-definition.json b/component-definition.json index 0e646c6..13bd113 100644 --- a/component-definition.json +++ b/component-definition.json @@ -191,7 +191,7 @@ "page": { "resourceType": "core/franklin/components/block/v1/block", "template": { - "name": "video", + "name": "Video", "model": "video" } }