diff --git a/extensions/amp-story/1.0/amp-story-open-page-attachment.css b/extensions/amp-story/1.0/amp-story-open-page-attachment.css index ddc14f5375b55..dc10d55cd7f81 100644 --- a/extensions/amp-story/1.0/amp-story-open-page-attachment.css +++ b/extensions/amp-story/1.0/amp-story-open-page-attachment.css @@ -170,14 +170,16 @@ } /** For amp-story-inline-page-attachment-v2 experiment elements. */ -.i-amphtml-story-page-open-attachment { +.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment { --i-amphtml-chip-background-color: rgba(255, 255, 255, 0.5) !important; --i-amphtml-img-background-color: white !important; --i-amphtml-label-text-color: white !important; --i-amphtml-arrow-color: black !important; + --i-amphtml-page-attachment-ui-animation-delay: 1s !important; + --i-amphtml-page-attachment-ui-animation-duration: .6s !important; } -[theme="dark"].i-amphtml-story-page-open-attachment { +[theme="dark"].i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment { --i-amphtml-chip-background-color: rgba(0, 0, 0, 0.5) !important; --i-amphtml-img-background-color: black !important; --i-amphtml-label-text-color: black !important; @@ -197,6 +199,7 @@ pointer-events: none !important; -webkit-touch-callout: default !important; /* Allow long pressing the button to open context menu in iOS */ text-decoration: none !important; + animation: none !important; } .i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment:not([active]) { @@ -204,36 +207,25 @@ visibility: hidden !important; } -/** For amp-story-inline-page-attachment-v2 inline default. */ -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-icon { - animation: none !important; - position: relative !important; +.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-attachment-label { + font-family: 'Roboto', sans-serif !important; + font-size: 16px !important; + font-weight: 700 !important; + letter-spacing: 0.3px; + line-height: 16px !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + max-width: 210px !important; } +/** For amp-story-inline-page-attachment-v2 inline default. */ .i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-label { color: var(--i-amphtml-label-text-color) !important; } -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-icon::after { - animation: none !important; - background: var(--i-amphtml-label-text-color) !important; -} - -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-bar-left, -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-bar-right { - background: var(--i-amphtml-arrow-color) !important; -} - -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-bar-left { - animation: open-attachment-bar-left 0.3s cubic-bezier(0.4, 0, 0.2, 1) both !important; -} - -.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-page-open-attachment-bar-right { - animation: open-attachment-bar-right 0.3s cubic-bezier(0.4, 0, 0.2, 1) both !important; -} - /** For amp-story-inline-page-attachment-v2 inline with images. */ -.i-amphtml-story-inline-page-attachment-chip { +.i-amphtml-amp-story-page-attachment-ui-v2 .i-amphtml-story-inline-page-attachment-chip { background-color: var(--i-amphtml-chip-background-color) !important; display: flex !important; border-radius: 24px !important; @@ -242,12 +234,15 @@ margin-bottom: 12px !important; } +.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment[active] .i-amphtml-story-inline-page-attachment-chip { + animation: tap-scale var(--i-amphtml-page-attachment-ui-animation-duration) var(--i-amphtml-page-attachment-ui-animation-delay) both !important; +} + .i-amphtml-story-inline-page-attachment-chip:only-child { margin-bottom: 20px !important; } -.i-amphtml-story-inline-page-attachment-img, -.i-amphtml-story-inline-page-attachment-arrow { +.i-amphtml-story-inline-page-attachment-img { background-size: contain !important; background-repeat: no-repeat !important; } @@ -263,27 +258,39 @@ } .i-amphtml-story-inline-page-attachment-arrow { + position: relative !important; height: 32px !important; width: 32px !important; + border-radius: 50% !important; + background-color: var(--i-amphtml-img-background-color) !important; +} + +.i-amphtml-story-inline-page-attachment-arrow:not(:only-child) { margin: 8px !important; - background-image: url('data:image/svg+xml;charset=utf-8, ') !important; +} + +.i-amphtml-story-inline-page-attachment-arrow:before { + content: '' !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-image: url('data:image/svg+xml;charset=utf-8,') !important; background-position: center !important; + background-size: auto !important; + background-repeat: no-repeat !important; } -[theme="dark"] .i-amphtml-story-inline-page-attachment-arrow { - background-image: url('data:image/svg+xml;charset=utf-8,') !important; +.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment[active] .i-amphtml-story-inline-page-attachment-arrow:before { + animation: move-up-arrow-in-circle var(--i-amphtml-page-attachment-ui-animation-duration) var(--i-amphtml-page-attachment-ui-animation-delay) both !important; } -.i-amphtml-story-inline-page-attachment-label { - font-family: 'Roboto', sans-serif !important; - font-size: 16px !important; - font-weight: 700 !important; - letter-spacing: 0.25px !important; - line-height: 16px !important; - overflow: hidden !important; - text-overflow: ellipsis !important; - white-space: nowrap !important; - max-width: 210px !important; +[theme="dark"] .i-amphtml-story-inline-page-attachment-arrow:before { + background-image: url('data:image/svg+xml;charset=utf-8,') !important; +} + +.i-amphtml-amp-story-page-attachment-ui-v2:not([href]) .i-amphtml-story-page-attachment-label { margin-bottom: 20px !important; color: var(--i-amphtml-label-text-color) !important; } @@ -306,6 +313,10 @@ background: none !important; } +[href].i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment[active] { + animation: tap-scale var(--i-amphtml-page-attachment-ui-animation-duration) var(--i-amphtml-page-attachment-ui-animation-delay) both !important; +} + .i-amphtml-story-page-open-attachment.i-amphtml-story-page-open-attachment-opening { animation: fade-out 0.3s both !important; } @@ -318,25 +329,50 @@ .i-amphtml-story-outlink-page-attachment-arrow { display: block !important; - height: 32px !important; - width: 32px !important; cursor: pointer !important; - position: relative !important; + margin-bottom: 10px !important; + fill: var(--i-amphtml-outlink-cta-background-color) !important; } -.i-amphtml-story-outlink-page-open-attachment-bar-left, -.i-amphtml-story-outlink-page-open-attachment-bar-right { - background-color: var(--i-amphtml-outlink-cta-background-color) !important; +.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-open-attachment[active] .i-amphtml-story-outlink-page-attachment-arrow { + animation: move-up-arrow var(--i-amphtml-page-attachment-ui-animation-duration) var(--i-amphtml-page-attachment-ui-animation-delay) both !important; } -.i-amphtml-story-outlink-page-open-attachment-bar-left { - left: 6px !important; - animation: open-attachment-bar-left 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; +@keyframes move-up-arrow { + 0%, 100% { + opacity: 1; + transform: translateY(0); + } + 45% { + opacity: 0; + transform: translateY(-7px); + } + 45.01% { + transform: translateY(5px); + } } -.i-amphtml-story-outlink-page-open-attachment-bar-right { - right: 6px !important; - animation: open-attachment-bar-right 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; +@keyframes move-up-arrow-in-circle { + 0%, 100% { + opacity: 1; + transform: translateY(0); + } + 45% { + opacity: 0; + transform: translateY(-4px); + } + 45.01% { + transform: translateY(3px); + } +} + +@keyframes tap-scale { + 0%, 100% { + transform: scale(1); + } + 45% { + transform: scale(.9); + } } .i-amphtml-story-outlink-page-attachment-outlink-chip { @@ -361,16 +397,7 @@ border-radius: 50% !important; } -.i-amphtml-story-outlink-page-attachment-label { - font-family: 'Roboto', sans-serif !important; - font-size: 16px !important; - font-weight: bold !important; - letter-spacing: 0.3px; - line-height: 16px !important; - overflow: hidden !important; - text-overflow: ellipsis !important; - white-space: nowrap !important; - max-width: 210px !important; +[href] .i-amphtml-story-page-attachment-label { padding-inline-start: 6px !important; padding-inline-end: 8px !important; color: var(--i-amphtml-outlink-cta-text-color) !important; diff --git a/extensions/amp-story/1.0/amp-story-open-page-attachment.js b/extensions/amp-story/1.0/amp-story-open-page-attachment.js index 8d92560a25915..b8d8132996123 100644 --- a/extensions/amp-story/1.0/amp-story-open-page-attachment.js +++ b/extensions/amp-story/1.0/amp-story-open-page-attachment.js @@ -37,7 +37,7 @@ const CtaAccentElement = { * @param {!Element} element * @return {!Element} */ -export const buildOpenDefaultAttachmentElement = (element) => +export const buildOldAttachmentElement = (element) => htmlFor(element)` `; /** + * For amp-story-page-attachment-ui-v2. + * No image by default, if images are defined they are appended to the template. * @param {!Element} element * @return {!Element} */ export const buildOpenInlineAttachmentElement = (element) => htmlFor(element)` - -
-
+
+
`; /** + * For amp-story-page-attachment-ui-v2. * @param {!Element} element * @return {!Element} */ const buildOpenOutlinkAttachmentElement = (element) => htmlFor(element)` - - - - - -
-
-
-
`; + + +
+ +
+
`; /** + * For amp-story-page-attachment-ui-v2. * @param {!Element} element * @return {!Element} */ @@ -94,46 +91,30 @@ export const buildOpenAttachmentElementLinkIcon = (element) => /** * Determines which open attachment UI to render. - * @param {!Window} win * @param {!Element} pageEl * @param {!Element} attachmentEl * @return {!Element} */ -export const renderPageAttachmentUI = (win, pageEl, attachmentEl) => { - const openImgAttr = attachmentEl.getAttribute('cta-image'); - const attachmentHref = attachmentEl.getAttribute('href'); - if (isPageAttachmentUiV2ExperimentOn(win) && attachmentHref) { - return renderOutlinkPageAttachmentUI( - win, - pageEl, - attachmentEl, - attachmentHref - ); - } else if (isPageAttachmentUiV2ExperimentOn(win) && openImgAttr) { - return renderPageAttachmentUiWithImages(win, pageEl, attachmentEl); +export const renderPageAttachmentUI = (pageEl, attachmentEl) => { + if (isPageAttachmentUiV2ExperimentOn(pageEl.getAmpDoc().win)) { + if (attachmentEl.getAttribute('href')) { + return renderOutlinkPageAttachmentUI(pageEl, attachmentEl); + } else { + return renderInlinePageAttachmentUi(pageEl, attachmentEl); + } } - return renderDefaultPageAttachmentUI(win, pageEl, attachmentEl); + return renderOldPageAttachmentUI(pageEl, attachmentEl); }; /** * Renders default page attachment UI. - * @param {!Window} win * @param {!Element} pageEl * @param {!Element} attachmentEl * @return {!Element} */ -const renderDefaultPageAttachmentUI = (win, pageEl, attachmentEl) => { - const openAttachmentEl = buildOpenDefaultAttachmentElement(pageEl); - if (isPageAttachmentUiV2ExperimentOn(win)) { - openAttachmentEl.classList.add( - '.i-amphtml-amp-story-page-attachment-ui-v2' - ); - // Setting theme - const theme = attachmentEl.getAttribute('theme'); - if (theme && AttachmentTheme.DARK === theme.toLowerCase()) { - openAttachmentEl.setAttribute('theme', AttachmentTheme.DARK); - } - } +const renderOldPageAttachmentUI = (pageEl, attachmentEl) => { + const openAttachmentEl = buildOldAttachmentElement(pageEl); + // If the attachment is a link, copy href to the element so it can be previewed on hover and long press. const attachmentHref = attachmentEl.getAttribute('href'); if (attachmentHref) { @@ -155,37 +136,28 @@ const renderDefaultPageAttachmentUI = (win, pageEl, attachmentEl) => { textEl.textContent = openLabel; - if (isPageAttachmentUiV2ExperimentOn(win)) { - openAttachmentEl.classList.add('i-amphtml-amp-story-page-attachment-ui-v2'); - } return openAttachmentEl; }; /** * Renders inline page attachment UI. - * @param {!Window} win * @param {!Element} pageEl * @param {!Element} attachmentEl - * @param {!Element} attachmentHref * @return {!Element} */ -const renderOutlinkPageAttachmentUI = ( - win, - pageEl, - attachmentEl, - attachmentHref -) => { +const renderOutlinkPageAttachmentUI = (pageEl, attachmentEl) => { const openAttachmentEl = buildOpenOutlinkAttachmentElement(pageEl); // Copy href to the element so it can be previewed on hover and long press. + const attachmentHref = attachmentEl.getAttribute('href'); if (attachmentHref) { openAttachmentEl.setAttribute('href', attachmentHref); } - // Getting elements + // Get elements. const {chipEl, ctaLabelEl} = htmlRefs(openAttachmentEl); - // Setting theme + // Set theme. let themeAttribute = attachmentEl.getAttribute('theme'); if (themeAttribute) { themeAttribute = themeAttribute.toLowerCase(); @@ -193,10 +165,10 @@ const renderOutlinkPageAttachmentUI = ( openAttachmentEl.setAttribute('theme', themeAttribute); if (themeAttribute === AttachmentTheme.CUSTOM) { - setCustomThemeStyles(win, attachmentEl, openAttachmentEl); + setCustomThemeStyles(attachmentEl, openAttachmentEl); } - // Appending text & aria-label. + // Append text & aria-label. const openLabelAttr = attachmentEl.getAttribute('cta-text') || attachmentEl.getAttribute('data-cta-text'); @@ -211,8 +183,8 @@ const renderOutlinkPageAttachmentUI = ( // Set image. const openImgAttr = attachmentEl.getAttribute('cta-image'); if (openImgAttr && openImgAttr !== 'none') { - const ctaImgEl = win.document.createElement('div'); - ctaImgEl.classList.add('i-amphtml-story-outlink-page-attachment-img'); + const ctaImgEl = htmlFor(chipEl)` +
`; setImportantStyles(ctaImgEl, { 'background-image': 'url(' + openImgAttr + ')', }); @@ -228,21 +200,20 @@ const renderOutlinkPageAttachmentUI = ( /** * Renders inline page attachment UI. - * @param {!Window} win * @param {!Element} pageEl * @param {!Element} attachmentEl * @return {!Element} */ -const renderPageAttachmentUiWithImages = (win, pageEl, attachmentEl) => { +const renderInlinePageAttachmentUi = (pageEl, attachmentEl) => { const openAttachmentEl = buildOpenInlineAttachmentElement(pageEl); - // Setting theme + // Set theme. const theme = attachmentEl.getAttribute('theme'); if (theme && AttachmentTheme.DARK === theme.toLowerCase()) { openAttachmentEl.setAttribute('theme', AttachmentTheme.DARK); } - // Appending text & aria-label. + // Append text & aria-label if defined. const openLabelAttr = attachmentEl.getAttribute('cta-text') || attachmentEl.getAttribute('data-cta-text'); @@ -254,32 +225,31 @@ const renderPageAttachmentUiWithImages = (win, pageEl, attachmentEl) => { openAttachmentEl.setAttribute('aria-label', openLabel); if (openLabel !== 'none') { - const textEl = win.document.createElement('span'); - textEl.classList.add('i-amphtml-story-inline-page-attachment-label'); + const textEl = htmlFor(openAttachmentEl)` + `; textEl.textContent = openLabel; openAttachmentEl.appendChild(textEl); } - // Adding images. - const openImgAttr = attachmentEl.getAttribute('cta-image'); - - const ctaImgEl = openAttachmentEl.querySelector( - '.i-amphtml-story-inline-page-attachment-img' - ); - - setImportantStyles(ctaImgEl, { - 'background-image': 'url(' + openImgAttr + ')', - }); + // Add images if they are defined. + const {chipEl} = htmlRefs(openAttachmentEl); + const makeImgElWithBG = (openImgAttr) => { + const ctaImgEl = htmlFor(chipEl)` +
`; + setImportantStyles(ctaImgEl, { + 'background-image': 'url(' + openImgAttr + ')', + }); + return ctaImgEl; + }; const openImgAttr2 = attachmentEl.getAttribute('cta-image-2'); - if (openImgAttr2) { - const ctaImgEl2 = win.document.createElement('div'); - ctaImgEl2.classList.add('i-amphtml-story-inline-page-attachment-img'); - setImportantStyles(ctaImgEl2, { - 'background-image': 'url(' + openImgAttr2 + ')', - }); - ctaImgEl.parentNode.insertBefore(ctaImgEl2, ctaImgEl.nextSibling); + chipEl.prepend(makeImgElWithBG(openImgAttr2)); + } + + const openImgAttr = attachmentEl.getAttribute('cta-image'); + if (openImgAttr) { + chipEl.prepend(makeImgElWithBG(openImgAttr)); } return openAttachmentEl; @@ -287,11 +257,10 @@ const renderPageAttachmentUiWithImages = (win, pageEl, attachmentEl) => { /** * Sets custom theme attributes. - * @param {!Window} win * @param {!Element} attachmentEl * @param {!Element} openAttachmentEl */ -export const setCustomThemeStyles = (win, attachmentEl, openAttachmentEl) => { +export const setCustomThemeStyles = (attachmentEl, openAttachmentEl) => { const accentColor = attachmentEl.getAttribute('cta-accent-color'); // Calculating contrast color (black or white) needed for outlink CTA UI. @@ -300,7 +269,7 @@ export const setCustomThemeStyles = (win, attachmentEl, openAttachmentEl) => { setImportantStyles(attachmentEl, { 'background-color': attachmentEl.getAttribute('cta-accent-color'), }); - const styles = computedStyle(win, attachmentEl); + const styles = computedStyle(attachmentEl.getAmpDoc().win, attachmentEl); const rgb = getRGBFromCssColorValue(styles['background-color']); contrastColor = getTextColorForRGB(rgb); setImportantStyles(attachmentEl, { diff --git a/extensions/amp-story/1.0/amp-story-page-attachment.css b/extensions/amp-story/1.0/amp-story-page-attachment.css index 3b0bd71a4c2ec..a7d7c4a0c5059 100644 --- a/extensions/amp-story/1.0/amp-story-page-attachment.css +++ b/extensions/amp-story/1.0/amp-story-page-attachment.css @@ -162,7 +162,7 @@ amp-story[desktop] .i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-pa background: none !important; } -.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-attachment-remote.i-amphtml-story-draggable-drawer-open:before { +.i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-attachment-remote.i-amphtml-story-draggable-drawer-open:after { content: "" !important; position: absolute !important; width: 100% !important; @@ -175,7 +175,7 @@ amp-story[desktop] .i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-pa animation: progress-bar-animation both 1s !important; } -[dir="rtl"] .i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-attachment-remote.i-amphtml-story-draggable-drawer-open:before { +[dir="rtl"] .i-amphtml-amp-story-page-attachment-ui-v2.i-amphtml-story-page-attachment-remote.i-amphtml-story-draggable-drawer-open:after { transform-origin: right !important; } diff --git a/extensions/amp-story/1.0/amp-story-page.js b/extensions/amp-story/1.0/amp-story-page.js index fbbb01a1200d4..d2a50424a6073 100644 --- a/extensions/amp-story/1.0/amp-story-page.js +++ b/extensions/amp-story/1.0/amp-story-page.js @@ -1757,7 +1757,6 @@ export class AmpStoryPage extends AMP.BaseElement { if (!this.openAttachmentEl_) { this.openAttachmentEl_ = renderPageAttachmentUI( - this.win, this.element, attachmentEl ); diff --git a/extensions/amp-story/1.0/test/test-amp-story-page.js b/extensions/amp-story/1.0/test/test-amp-story-page.js index 2d4344d4c3735..b2657aa3fb507 100644 --- a/extensions/amp-story/1.0/test/test-amp-story-page.js +++ b/extensions/amp-story/1.0/test/test-amp-story-page.js @@ -673,13 +673,14 @@ describes.realWin('amp-story-page', {amp: {extensions}}, (env) => { expect(openAttachmentEl.getAttribute('target')).to.eql('_top'); }); - it('should build the new default outlink page attachment UI with target="_top" to navigate in top window', async () => { + it('should build the new outlink page attachment UI with target="_top" to navigate in top level browsing context', async () => { toggleExperiment(win, 'amp-story-page-attachment-ui-v2', true); const attachmentEl = win.document.createElement( 'amp-story-page-attachment' ); attachmentEl.setAttribute('layout', 'nodisplay'); + attachmentEl.setAttribute('href', 'google.com'); element.appendChild(attachmentEl); page.buildCallback();