-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ [Bento] Implement
bento-app-banner
(#37127)
* feature(bento-add-banner): initial template generation * feature(bento-add-banner): created simple storybook * feature(bento-add-banner): copied CSS from classic * feature(bento-add-banner): added many "stubs" for standalone services * feature(bento-add-banner): ported IOS and Android app logic * feature(bento-add-banner): added platform-aware logic, and dismiss button storage * feature(bento-add-banner): added UI unit tests * feature(bento-add-banner): added IOS tests * feature(bento-add-banner): moved sources into `component` folder * feature(bento-add-banner): added unit tests for Android * feature(bento-add-banner): mapped the `dismiss-button-aria-label` attribute * feature(bento-add-banner): added minor notes to the stories * feature(bento-add-banner): added unit tests for amp-app-banner * feature(bento-add-banner): updated validator * feature(bento-add-banner): extracted services to common location * feature(bento-add-banner): added README for services * feature(bento-add-banner): updated type defs * feature(bento-add-banner): updated formatting * feature(bento-add-banner): lint fix * feature(bento-add-banner): lint ignores * feature(bento-add-banner): lint fixes * feature(bento-add-banner): type fixes * feature(bento-add-banner): updated z-index file * feature(bento-add-banner): updated validator template * feature(bento-add-banner): simplified code with `Array.find` * feature(bento-add-banner): parse meta content using `Array.reduce` * feature(bento-add-banner): added more tests for android * feature(bento-add-banner): added more tests for ios * feature(bento-add-banner): improved tests for BentoAppBanner * feature(bento-add-banner): added tests for Dismiss logic * feature(bento-add-banner): added more iOS tests * feature(bento-add-banner): tiny lint fix * feature(bento-add-banner): improved tests for web-component mode, and fixed the button[open-button] check * feature(bento-add-banner): removed unnecessary `waitFor` * feature(bento-add-banner): lint fix * feature(bento-add-banner): added whitespace in tests * feature(bento-add-banner): ensure tests are not dependent on timers * feature(bento-add-banner): removed obsolete `latestVersion` * feature(bento-add-banner): use `Object.fromEntries` as suggested * feature(bento-add-banner): removed unused CSS * feature(bento-add-banner): use `WindowInterface.getTop` to improve unit tests * feature(bento-add-banner): extracted querySelectorInSlot to core * feature(bento-add-banner): removed useless services, use object-syntax instead of classes, fixed fetchJson * feature(bento-add-banner): renamed services to utils * feature(bento-add-banner): removed redundant win variable * feature(bento-add-banner): extracted parsing logic into separate function for readability * feature(bento-add-banner): renamed file to `docInfo` * feature(bento-add-banner): improved safety of accessing localStorage * feature(bento-add-banner): ensure proper default value is returned * feature(bento-add-banner): removed unnecessary async * feature(bento-add-banner): ensure localStorage still works if `key` changes * feature(bento-add-banner): flip ternary for readability * feature(bento-add-banner): added `self` for fetch * feature(bento-add-banner): updated generated z-index file * feature(bento-app-banner): ensure XHR rejects invalid status codes * feature(bento-app-banner): removed dependencies on `/src/url` * feature(bento-app-banner): lint sample code * feature(bento-app-banner): minor code improvements * feature(bento-app-banner): minor code improvements * feature(bento-app-banner): minor code improvements * feature(bento-app-banner): allow localStorage from custom hook * feature(bento-app-banner): include optional `init` param for requests * feature(bento-app-banner): improved logging * feature(bento-app-banner): only expose `logger[info|warn|error]` * feature(bento-app-banner): warn when localStorage.setItem fails * feature(bento-app-banner): ensure logger can be stubbed and tested * feature(bento-app-banner): moved `INVALID_PROTOCOLS` to proper location * feature(bento-app-banner): ensure logger is globally disabled * feature(bento-app-banner): ensure component inherits from AmpPreactBaseElement * Update src/preact/utils/docInfo.js Co-authored-by: Justin Ridgewell <justin@ridgewell.name> Co-authored-by: scottrippey <scott.william.rippey@gmail.com> Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
- Loading branch information
1 parent
119808c
commit 95d5886
Showing
35 changed files
with
1,630 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
amp-app-banner { | ||
position: fixed !important; | ||
bottom: 0 !important; | ||
left: 0; | ||
width: 100%; | ||
max-height: 100px !important; | ||
box-sizing: border-box; | ||
background: #fff; | ||
z-index: 13; | ||
box-shadow: 0 0 5px 0 rgba(0,0,0, 0.2) !important; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import {isExperimentOn} from '#experiments'; | ||
|
||
import {AmpPreactBaseElement, setSuperClass} from '#preact/amp-base-element'; | ||
|
||
import {userAssert} from '#utils/log'; | ||
|
||
import {BaseElement} from './base-element'; | ||
|
||
import {CSS} from '../../../build/amp-app-banner-1.0.css'; | ||
|
||
/** @const {string} */ | ||
const TAG = 'amp-app-banner'; | ||
|
||
class AmpAppBanner extends setSuperClass(BaseElement, AmpPreactBaseElement) { | ||
/** @override */ | ||
isLayoutSupported(layout) { | ||
userAssert( | ||
isExperimentOn(this.win, 'bento') || | ||
isExperimentOn(this.win, 'bento-app-banner'), | ||
'expected global "bento" or specific "bento-app-banner" experiment to be enabled' | ||
); | ||
return super.isLayoutSupported(layout); | ||
} | ||
} | ||
|
||
AMP.extension(TAG, '1.0', (AMP) => { | ||
AMP.registerElement(TAG, AmpAppBanner, CSS); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import {PreactBaseElement} from '#preact/base-element'; | ||
|
||
import {BentoAppBanner} from './component/component'; | ||
import {CSS as COMPONENT_CSS} from './component/component.jss'; | ||
|
||
export class BaseElement extends PreactBaseElement {} | ||
|
||
/** @override */ | ||
BaseElement['Component'] = BentoAppBanner; | ||
|
||
/** @override */ | ||
BaseElement['props'] = { | ||
'children': {passthrough: true}, | ||
'dismissButtonAriaLabel': {attr: 'dismiss-button-aria-label'}, | ||
'id': {attr: 'id'}, | ||
}; | ||
|
||
/** @override */ | ||
BaseElement['layoutSizeDefined'] = true; | ||
|
||
/** @override */ | ||
BaseElement['usesShadowDom'] = true; | ||
|
||
/** @override */ | ||
BaseElement['shadowCss'] = COMPONENT_CSS; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import {WindowInterface} from '#core/window/interface'; | ||
|
||
import {logger} from '#preact/logger'; | ||
import {docInfo} from '#preact/utils/docInfo'; | ||
import {platformUtils} from '#preact/utils/platform'; | ||
import {urlUtils} from '#preact/utils/url'; | ||
import {xhrUtils} from '#preact/utils/xhr'; | ||
|
||
import {openWindowDialog} from '../../../../src/open-window-dialog'; | ||
|
||
const OPEN_LINK_TIMEOUT = 1500; | ||
|
||
/** | ||
* @return {{openOrInstall: function(): void, promise: Promise<Response>}|null} | ||
*/ | ||
export function getAndroidAppInfo() { | ||
// We want to fallback to browser builtin mechanism when possible. | ||
const canShowBuiltinBanner = | ||
platformUtils.isAndroid() && platformUtils.isChrome(); | ||
|
||
if (canShowBuiltinBanner) { | ||
logger.info( | ||
'BENTO-APP-BANNER', | ||
'Not rendering bento-app-banner:', | ||
'Browser supports builtin banners.' | ||
); | ||
return null; | ||
} | ||
|
||
const manifestLink = self.document.head.querySelector( | ||
'link[rel=manifest],link[rel=origin-manifest]' | ||
); | ||
|
||
const missingDataSources = !manifestLink; | ||
if (missingDataSources) { | ||
return null; | ||
} | ||
|
||
const manifestHref = manifestLink.getAttribute('href'); | ||
|
||
urlUtils.assertHttpsUrl(manifestHref, undefined, 'manifest href'); | ||
|
||
const promise = xhrUtils.fetchJson(manifestHref).then(parseManifest); | ||
return { | ||
promise, | ||
openOrInstall: () => { | ||
return promise.then((manifest) => { | ||
if (!manifest) { | ||
return; | ||
} | ||
const {installAppUrl, openInAppUrl} = manifest; | ||
setTimeout(() => { | ||
WindowInterface.getTop(window).location.assign(installAppUrl); | ||
}, OPEN_LINK_TIMEOUT); | ||
openWindowDialog(window, openInAppUrl, '_top'); | ||
}); | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* @param {object} manifestJson | ||
* @return {{installAppUrl: string, openInAppUrl: string}|null} | ||
*/ | ||
function parseManifest(manifestJson) { | ||
const apps = manifestJson['related_applications']; | ||
if (!apps) { | ||
logger.error( | ||
'BENTO-APP-BANNER', | ||
'Invalid manifest:', | ||
'related_applications is missing from manifest.json file' | ||
); | ||
return null; | ||
} | ||
|
||
const playApp = apps.find((a) => a['platform'] === 'play'); | ||
if (!playApp) { | ||
logger.error( | ||
'BENTO-APP-BANNER', | ||
'Invalid manifest:', | ||
'Could not find a platform=play app in manifest' | ||
); | ||
return null; | ||
} | ||
|
||
const installAppUrl = `https://play.google.com/store/apps/details?id=${playApp['id']}`; | ||
const openInAppUrl = getAndroidIntentForUrl(playApp['id']); | ||
return {installAppUrl, openInAppUrl}; | ||
} | ||
|
||
/** | ||
* @param {string} appId | ||
* @return {string} | ||
*/ | ||
function getAndroidIntentForUrl(appId) { | ||
const parsedUrl = urlUtils.parse(docInfo.canonicalUrl); | ||
const cleanProtocol = parsedUrl.protocol.replace(':', ''); | ||
const {host, pathname} = parsedUrl; | ||
|
||
return `android-app://${appId}/${cleanProtocol}/${host}${pathname}`; | ||
} |
Oops, something went wrong.