Skip to content

Commit

Permalink
✨[AMP Story Audio Sticker] add default stickers with UI of different …
Browse files Browse the repository at this point in the history
…states (#38824)

* Audio sticker skeleton code: clicking on the element would unmute the story and hide the element

* Remove validator test and spaces in css file

* Add dependency

* Update z-index

* Update extensions/amp-story-audio-sticker/0.1/amp-story-audio-sticker.css

Co-authored-by: Matias Szylkowski <mszylkowski@google.com>

* Cleaning up extension and css code

* fix

* Remove unnecessary CSS and update the example.

* Fix z-index

* Remove validator

* Add the sticker container and tap hint

* Fix whitespace

* lint

* String concat in jsx

* Default stickers and switching between different states

* Remove duplicate buildCallback

* Use CSS to execute animation delay instead. Have a new helper function to get default sticker

* Change default size to small

* Fix lint

* Fix unit test

* refactors

* Move amp-img src setting to buildcallback

* Fixes

* Fix

* Update extensions/amp-story-audio-sticker/0.1/amp-story-audio-sticker.js

Co-authored-by: Matias Szylkowski <mszylkowski@google.com>

* lint

---------

Co-authored-by: Matias Szylkowski <mszylkowski@google.com>
  • Loading branch information
ychsieh and mszylkowski committed May 4, 2023
1 parent 275d6cb commit 519b5f6
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 45 deletions.
77 changes: 70 additions & 7 deletions examples/amp-story/amp-story-audio-sticker.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,7 @@ <h1 class="bold">Key Highlights of AMP Conf 2018</h1>
<p class="byline">By The AMP team</p>
</amp-story-grid-layer>
<amp-story-grid-layer>
<amp-story-audio-sticker>
<amp-img width="100" height="100" layout="responsive" src="https://media.tenor.com/oK5AJr1cvF4AAAAi/high-volume-speaker-symbols.gif">
</amp-story-audio-sticker>
<amp-story-audio-sticker sticker="audio-cloud"></amp-story-audio-sticker>
</amp-story-grid-layer>>
</amp-story-page>

Expand All @@ -149,11 +147,76 @@ <h1 class="bold">Key Highlights of AMP Conf 2018</h1>
<p class="byline">By The AMP team</p>
</amp-story-grid-layer>
<amp-story-grid-layer>
<amp-story-audio-sticker size="small">
<amp-img width="100" height="100" layout="responsive" src="https://media.tenor.com/oK5AJr1cvF4AAAAi/high-volume-speaker-symbols.gif">
</amp-story-audio-sticker>
<amp-story-audio-sticker size="large" sticker="cat-sticker"></amp-story-audio-sticker>
</amp-story-grid-layer>>
</amp-story-page>

<amp-story-page id="page-3" title="Lorem ipsum dolor sit amet">
<amp-story-grid-layer template="fill">
<amp-video autoplay loop
width="400"
height="750"
poster="./img/poster0.png"
layout="fill">
<source src="./video/p1.mp4" type="video/mp4">
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="bottom">
<div class="icon"></div>
<h1 class="bold">Key Highlights of AMP Conf 2018</h1>
<p class="byline">By The AMP team</p>
</amp-story-grid-layer>
<amp-story-grid-layer>
<amp-story-audio-sticker sticker="loud-speaker"></amp-story-audio-sticker>
</amp-story-grid-layer>>
</amp-story-page>
</amp-story>

<amp-story-page id="page-4" title="Lorem ipsum dolor sit amet">
<amp-story-grid-layer template="fill">
<amp-video autoplay loop
width="400"
height="750"
poster="./img/poster0.png"
layout="fill">
<source src="./video/p1.mp4" type="video/mp4">
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="bottom">
<div class="icon"></div>
<h1 class="bold">Key Highlights of AMP Conf 2018</h1>
<p class="byline">By The AMP team</p>
</amp-story-grid-layer>
<amp-story-grid-layer>
<amp-story-audio-sticker size="large" sticker="tape-player"></amp-story-audio-sticker>
</amp-story-grid-layer>>
</amp-story-page>

<amp-story-page id="page-5" title="Lorem ipsum dolor sit amet">
<amp-story-grid-layer template="fill">
<amp-video autoplay loop
width="400"
height="750"
poster="./img/poster0.png"
layout="fill">
<source src="./video/p1.mp4" type="video/mp4">
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="bottom">
<div class="icon"></div>
<h1 class="bold">Key Highlights of AMP Conf 2018</h1>
<p class="byline">By The AMP team</p>
</amp-story-grid-layer>
<amp-story-grid-layer>
<amp-story-audio-sticker>
<amp-story-audio-sticker-pretap>
<amp-img width="100" height="100" layout="responsive" src="https://media.tenor.com/oK5AJr1cvF4AAAAi/high-volume-speaker-symbols.gif"></amp-img>
</amp-story-audio-sticker-pretap>
<amp-story-audio-sticker-posttap>
<amp-img width="100" height="100" layout="responsive" src="https://media.tenor.com/oK5AJr1cvF4AAAAi/high-volume-speaker-symbols.gif"></amp-img>
</amp-story-audio-sticker-posttap>
</amp-story-audio-sticker>
</amp-story-grid-layer>
</amp-story-page>
</amp-story-page>
</body>
</html>
40 changes: 33 additions & 7 deletions extensions/amp-story-audio-sticker/0.1/amp-story-audio-sticker.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
justify-content: center !important;
align-items: center !important;
margin-bottom: 4px !important;
transition: opacity 0.5s ease !important;
}

amp-story:not([muted]) .i-amphtml-amp-story-audio-sticker-tap-hint {
opacity: 0 !important;
}

.i-amphtml-amp-story-audio-sticker-tap-hint span {
Expand All @@ -40,20 +45,41 @@
height: 120px !important;
}

.i-amphtml-amp-story-audio-sticker-container * {
pointer-events: none !important;
}

amp-story-audio-sticker {
position: relative !important;
width: 100% !important;
max-width: 100% !important; /* Set the maximum width of the image to 100% to ensure it fits within the container */
max-height: 100% !important; /* Set the maximum height of the image to 100% to ensure it fits within the container */
margin: auto !important; /* Center the image horizontally and vertically within the container */
}

amp-story-audio-sticker * {
pointer-events: none !important;
}

amp-story[muted] amp-story-audio-sticker {
pointer-events: auto !important;
}

amp-story:not([muted]) .i-amphtml-amp-story-audio-sticker-component {
display: none !important;
/*
Hide the sticker after the story gets unmuted:
1) if the sticker is on the active page, hide it after showing posttap sticker for 4 seconds.
2) if the sticker is not on the active page, hide it immediately since it is in the background.
*/
amp-story:not([muted]) amp-story-page[active] amp-story-audio-sticker {
transition: opacity 0.5s ease 4s !important;
}
amp-story:not([muted]) amp-story-audio-sticker {
opacity: 0 !important;
}

amp-story-audio-sticker > * {
position: absolute !important; /* Child divs should have absolute position to make them stacked */
top: 0 !important;
left: 0 !important;
height: 100% !important;
width: 100% !important;
}

amp-story:not([muted]) amp-story-audio-sticker-pretap, amp-story[muted] amp-story-audio-sticker-posttap {
opacity: 0 !important;
}
133 changes: 127 additions & 6 deletions extensions/amp-story-audio-sticker/0.1/amp-story-audio-sticker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as Preact from '#core/dom/jsx';
import {Layout_Enum} from '#core/dom/layout';
import {scopedQuerySelector} from '#core/dom/query';

import {Services} from '#service';

Expand All @@ -8,14 +9,74 @@ import {Action} from '../../amp-story/1.0/amp-story-store-service';

const TAG = 'amp-story-audio-sticker';

/**
* Sticker pretap tag
* @const {string}
*/
const STICKER_PRETAP_TAG = 'amp-story-audio-sticker-pretap';
/**
* Sticker posttap tag
* @const {string}
*/
const STICKER_POSTTAP_TAG = 'amp-story-audio-sticker-posttap';

/**
* The gstatic URL prefix of the sticker assets.
* @const {string}
*/
const ASSET_URL_PREFIX = 'https://www.gstatic.com/amphtml/stamp/audio-sticker/';

/** @const {!Object}
* List of default stickers.
*/
const DEFAULT_STICKERS = {
'audio-cloud': {
width: '360',
height: '233',
pretapUrl: ASSET_URL_PREFIX + 'audio-cloud-pretap.png',
posttapUrl: ASSET_URL_PREFIX + 'audio-cloud-posttap.png',
},
'cat-sticker': {
width: '282',
height: '226',
pretapUrl: ASSET_URL_PREFIX + 'cat-sticker-pretap.png',
posttapUrl: ASSET_URL_PREFIX + 'cat-sticker-posttap.gif',
},
'loud-speaker': {
width: '380',
height: '380',
pretapUrl: ASSET_URL_PREFIX + 'loud-speaker-pretap.png',
posttapUrl: ASSET_URL_PREFIX + 'loud-speaker-posttap.png',
},
'tape-player': {
width: '260',
height: '220',
pretapUrl: ASSET_URL_PREFIX + 'tape-player-pretap.png',
posttapUrl: ASSET_URL_PREFIX + 'tape-player-posttap.gif',
},
};

/** Fallback default sticker. It would be used if both of below happen:
* 1) no default sticker is specified
* 2) the custom sticker data is not provided completely.
* @const {string}
*/
const FALLBACK_DEFAULT_STICKER = 'cat-sticker';

export class AmpStoryAudioSticker extends AMP.BaseElement {
/** @param {!AmpElement} element */
constructor(element) {
super(element);

/** @private {?../../../extensions/amp-story/1.0/amp-story-store-service.AmpStoryStoreService} */
this.storeService_ = null;
}

/** @override */
buildCallback() {
this.maybeInitializeDefaultSticker_();

// Build sticker component structure.
this.element.parentNode.appendChild(
<div class="i-amphtml-amp-story-audio-sticker-component">
<div class="i-amphtml-amp-story-audio-sticker-tap-hint">
Expand All @@ -24,9 +85,9 @@ export class AmpStoryAudioSticker extends AMP.BaseElement {
<div
class={
'i-amphtml-amp-story-audio-sticker-container' +
(this.element.getAttribute('size') === 'small'
? ' small'
: ' large')
(this.element.getAttribute('size') === 'large'
? ' large'
: ' small')
}
>
{this.element}
Expand All @@ -39,13 +100,73 @@ export class AmpStoryAudioSticker extends AMP.BaseElement {
layoutCallback() {
return Services.storyStoreServiceForOrNull(this.win).then(
(storeService) => {
this.element.addEventListener('click', () =>
storeService.dispatch(Action.TOGGLE_MUTED, false)
);
this.storeService_ = storeService;
this.initializeListeners_();
}
);
}

/** @private */
maybeInitializeDefaultSticker_() {
const defaultSticker = this.getDefaultSticker_();
if (!defaultSticker) {
return;
}

// Remove all existing child elements and add only pretap and posttap elements.
this.element.replaceChildren();
this.element.appendChild(
<amp-story-audio-sticker-pretap>
<amp-img
width={DEFAULT_STICKERS[defaultSticker].width}
height={DEFAULT_STICKERS[defaultSticker].height}
src={DEFAULT_STICKERS[defaultSticker].pretapUrl}
layout="responsive"
></amp-img>
</amp-story-audio-sticker-pretap>
);
this.element.appendChild(
<amp-story-audio-sticker-posttap>
<amp-img
width={DEFAULT_STICKERS[defaultSticker].width}
height={DEFAULT_STICKERS[defaultSticker].height}
src={DEFAULT_STICKERS[defaultSticker].posttapUrl}
layout="responsive"
></amp-img>
</amp-story-audio-sticker-posttap>
);
}

/**
* Return the specified default sticker or null if there's custom sticker provided.
* Return fallback sticker is both default and custom sticker config are not specified at all.
* @private
* @return {string}
*/
getDefaultSticker_() {
if (
scopedQuerySelector(this.element, STICKER_PRETAP_TAG) &&
scopedQuerySelector(this.element, STICKER_POSTTAP_TAG)
) {
return null;
}

const stickerAttr = this.element.getAttribute('sticker');
return DEFAULT_STICKERS[stickerAttr]
? stickerAttr
: FALLBACK_DEFAULT_STICKER;
}

/** @private */
initializeListeners_() {
this.element.addEventListener(
'click',
() => this.storeService_.dispatch(Action.TOGGLE_MUTED, false),
true
);
// TODO: add listeners for click animations.
}

/** @override */
isLayoutSupported(layout) {
return layout == Layout_Enum.CONTAINER;
Expand Down

0 comments on commit 519b5f6

Please sign in to comment.