diff --git a/blocks/embed/embed.css b/blocks/embed/embed.css index 595e007..4c1c6d2 100644 --- a/blocks/embed/embed.css +++ b/blocks/embed/embed.css @@ -1,64 +1,62 @@ -/* -* Copyright 2021 Adobe. All rights reserved. -* This file is licensed to you under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. You may obtain a copy -* of the License at http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software distributed under -* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS -* OF ANY KIND, either express or implied. See the License for the specific language -* governing permissions and limitations under the License. -*/ - -main .embed { - max-height: 600px; +.embed { width: unset; text-align: center; max-width: 800px; - margin: 0 auto 64px; -} - -main .embed img { - max-width: 100%; -} - -main .embed > div > div p a { - visibility: hidden; - word-break: break-word; -} - -main .embed.embed-instagram { - max-width: fit-content; -} - -main .embed.embed-instagram iframe.instagram-media { - border: 1px solid var(--color-gray-200); - background: white; - border-radius: 4px; - height: 462px; - width: 320px; -} - -@media (min-width: 600px) { - main .embed.embed-instagram { - max-height: unset; - } - - main .embed.embed-instagram iframe.instagram-media { - width: 550px; - height: 758px; - } + margin: 32px auto; } -main .embed.embed-twitter { - max-height: unset; +.embed > div { + display: flex; + justify-content: center; } -main .embed.embed-tiktok { - max-height: unset; -} - -main .embed.embed-twitter .twitter-tweet-rendered { +.embed.embed-twitter .twitter-tweet-rendered { margin-left: auto; margin-right: auto; } + +.embed .embed-placeholder { + width: 100%; + aspect-ratio: 16 / 9; + position: relative; +} + +.embed .embed-placeholder > * { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + inset: 0; +} + +.embed .embed-placeholder picture img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.embed .embed-placeholder-play button { + box-sizing: border-box; + position: relative; + display: block; + transform: scale(3); + width: 22px; + height: 22px; + border: 2px solid; + border-radius: 20px; + padding: 0; +} + +.embed .embed-placeholder-play button::before { + 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; +} diff --git a/blocks/embed/embed.js b/blocks/embed/embed.js index 3481c1b..cc15dfa 100644 --- a/blocks/embed/embed.js +++ b/blocks/embed/embed.js @@ -1,4 +1,8 @@ -import { buildFigure } from '../../scripts/scripts.js'; +/* + * Embed Block + * Show videos and social posts directly on your page + * https://www.hlx.live/developer/block-collection/embed + */ const loadScript = (url, callback, type) => { const head = document.querySelector('head'); @@ -7,8 +11,8 @@ const loadScript = (url, callback, type) => { if (type) { script.setAttribute('type', type); } - head.append(script); script.onload = callback; + head.append(script); return script; }; @@ -18,40 +22,26 @@ const getDefaultEmbed = (url) => `
- -
`; - return embedHTML; -}; - -const embedInstagram = (url) => { - const endingSlash = url.pathname.endsWith('/') ? '' : '/'; - const location = window.location.href.endsWith('.html') ? window.location.href : `${window.location.href}.html`; - const src = `${url.origin}${url.pathname}${endingSlash}embed/?cr=1&v=13&wp=1316&rd=${location}`; - const embedHTML = `
- +
`; return embedHTML; }; -const embedVimeo = (url) => { - let src = url.href; - if (!src.includes('player.vimeo.com')) { - const video = url.pathname.split('/')[1]; - src = `https://player.vimeo.com/video/${video}?app_id=122963`; - } - +const embedVimeo = (url, autoplay) => { + const [, video] = url.pathname.split('/'); + const suffix = autoplay ? '?muted=1&autoplay=1' : ''; const embedHTML = `
- @@ -59,173 +49,65 @@ const embedVimeo = (url) => { return embedHTML; }; -const embedSpark = (url) => { - let embedURL = url; - if (!url.pathname.endsWith('/embed.html') && !url.pathname.endsWith('/embed')) { - embedURL = new URL(`${url.href}${url.pathname.endsWith('/') ? '' : '/'}embed.html`); - } - - return getDefaultEmbed(embedURL); -}; - const embedTwitter = (url) => { - const embedHTML = `
`; + const embedHTML = `
`; loadScript('https://platform.twitter.com/widgets.js'); return embedHTML; }; -const embedTiktok = (url) => { - const resultHtml = document.createElement('div'); - resultHtml.setAttribute('id', 'tiktok'); - - const tiktokBuild = async (fetchUrl) => { - const response = await fetch(fetchUrl); - response.json().then((data) => { - const tiktok = document.getElementById('tiktok'); - tiktok.outerHTML = data.html; - loadScript('https://www.tiktok.com/embed.js'); - }); - }; - tiktokBuild(`https://www.tiktok.com/oembed?url=${url}`); - - return resultHtml.outerHTML; -}; - -const embedSlideShare = (url) => { - const resultHtml = document.createElement('div'); - resultHtml.setAttribute('id', 'slideShare'); - - const slideShareBuild = async () => { - const response = await fetch(url); - const body = await response.text(); - const el = document.createElement('div'); - el.innerHTML = body; - const slideShowInfo = el.querySelector('.slideshow-info meta[itemprop="embedURL"]'); - if (slideShowInfo) { - const embedUrl = el.querySelector('.slideshow-info meta[itemprop="embedURL"]').content; - const slideShare = document.getElementById('slideShare'); - slideShare.outerHTML = `
- -
`; - } - }; - if (url.href.includes('embed_code')) { - resultHtml.innerHTML = `
- -
`; - } else { - slideShareBuild(url); - } - - return resultHtml.outerHTML; -}; - -const EMBEDS_CONFIG = { - youtube: { - type: 'youtube', - embed: embedYoutube, - }, - 'adobe-tv': { - type: 'adobe-tv', - embed: getDefaultEmbed, - }, - 'adobe-spark': { - type: 'adobe-spark', - embed: embedSpark, - }, - instagram: { - type: 'instagram', - embed: embedInstagram, - }, - vimeo: { - type: 'vimeo', - embed: embedVimeo, - }, - twitter: { - type: 'twitter', - embed: embedTwitter, - }, - tiktok: { - type: 'tiktok', - embed: embedTiktok, - }, - slideshare: { - type: 'slideshare', - embed: embedSlideShare, - }, -}; - -const loadEmbed = (block) => { - if (block.classList.contains('is-loaded')) { +const loadEmbed = (block, link, autoplay) => { + if (block.classList.contains('embed-is-loaded')) { return; } - const figure = buildFigure(block.firstElementChild.firstElementChild); - const a = figure.querySelector('a'); - - if (a) { - const url = new URL(a.href.replace(/\/$/, '')); - const hostnameArr = url.hostname.split('.'); - - // trimed domain name (ex, www.google.com -> google) - const simpleDomain = hostnameArr[hostnameArr.length - 2]; - - // getting config - let config = EMBEDS_CONFIG[simpleDomain]; - - // for different config for same domain: - if (url.hostname.includes('adobe')) { - if (url.hostname.includes('spark.adobe.com')) { - config = EMBEDS_CONFIG['adobe-spark']; - } else { - config = EMBEDS_CONFIG['adobe-tv']; - } - } else if (url.hostname.includes('youtu')) { - config = EMBEDS_CONFIG.youtube; - } - - // loading embed function for given config and url. - if (config) { - a.outerHTML = config.embed(url); - block.classList = `block embed embed-${config.type}`; - } else { - a.outerHTML = getDefaultEmbed(url); - block.classList = `block embed embed-${simpleDomain}`; - } - block.innerHTML = figure.outerHTML; - block.classList.add('is-loaded'); - } -}; - -const intersectHandler = (entries) => { - const entry = entries[0]; - if (entry.isIntersecting) { - if (entry.intersectionRatio >= 0.25) { - const block = entry.target; - loadEmbed(block); - } + const EMBEDS_CONFIG = [ + { + match: ['youtube', 'youtu.be'], + embed: embedYoutube, + }, + { + match: ['vimeo'], + embed: embedVimeo, + }, + { + match: ['twitter'], + embed: embedTwitter, + }, + ]; + + const config = EMBEDS_CONFIG.find((e) => e.match.some((match) => link.includes(match))); + const url = new URL(link); + if (config) { + block.innerHTML = config.embed(url, autoplay); + block.classList = `block embed embed-${config.match[0]}`; } else { - // if ((entry.intersectionRatio === 0.0) && (adBox.dataset.totalViewTime >= 60000)) { - // Error handler placeholder - // } + block.innerHTML = getDefaultEmbed(url); + block.classList = 'block embed'; } + block.classList.add('embed-is-loaded'); }; export default function decorate(block) { - const run = () => { - const options = { - root: null, - rootMargin: '0px', - threshold: [0.0, 0.25], - }; - - const observer = new IntersectionObserver(intersectHandler, options); - observer.observe(block); - }; - - if (document.readyState === 'complete') { - run(); + const placeholder = block.querySelector('picture'); + const link = block.querySelector('a').href; + block.textContent = ''; + + if (placeholder) { + const wrapper = document.createElement('div'); + wrapper.className = 'embed-placeholder'; + wrapper.innerHTML = '
'; + wrapper.prepend(placeholder); + wrapper.addEventListener('click', () => { + loadEmbed(block, link, true); + }); + block.append(wrapper); } else { - window.addEventListener('load', run); + const observer = new IntersectionObserver((entries) => { + if (entries.some((e) => e.isIntersecting)) { + observer.disconnect(); + loadEmbed(block, link); + } + }); + observer.observe(block); } }