From 8807607cc95f5abc445005c130b0ecb0109989ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 30 Jun 2021 16:47:23 +0300 Subject: [PATCH 01/13] Admin PWA --- docs/manifest.json | 6 ++++++ lib/load.php | 1 + lib/manifest.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/pwa.php | 27 +++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 lib/manifest.php create mode 100644 lib/pwa.php diff --git a/docs/manifest.json b/docs/manifest.json index ef37c643699f25..002369b17e1ae0 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1493,6 +1493,12 @@ "markdown_source": "../packages/e2e-tests/README.md", "parent": "packages" }, + { + "title": "@wordpress/edit-dashboard", + "slug": "packages-edit-dashboard", + "markdown_source": "../packages/edit-dashboard/README.md", + "parent": "packages" + }, { "title": "@wordpress/edit-navigation", "slug": "packages-edit-navigation", diff --git a/lib/load.php b/lib/load.php index f81e7f3e8621cb..d6cf4449b2168b 100644 --- a/lib/load.php +++ b/lib/load.php @@ -118,6 +118,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/navigation-page.php'; require __DIR__ . '/experiments-page.php'; require __DIR__ . '/global-styles.php'; +require __DIR__ . '/pwa.php'; require __DIR__ . '/block-supports/generated-classname.php'; require __DIR__ . '/block-supports/elements.php'; diff --git a/lib/manifest.php b/lib/manifest.php new file mode 100644 index 00000000000000..0a9792aabb4412 --- /dev/null +++ b/lib/manifest.php @@ -0,0 +1,45 @@ +colors; +$admin_bar_color = $colors[0]; +$body_background = '#f1f1f1'; + +$icon_sizes = array( 32, 180, 192, 270, 512 ); + +// Ideally we have the WordPress logo as the default app logo in the sizes +// below. +$icons = array(); + +if ( has_site_icon() ) { + $type = wp_check_filetype( get_site_icon_url() ); + + foreach ( $icon_sizes as $size ) { + $icons[] = array( + 'src' => get_site_icon_url( $size ), + 'sizes' => $size . 'x' . $size, + 'type' => $type['type'], + ); + } +} + +wp_send_json( + array( + 'name' => get_bloginfo( 'name' ), + 'icons' => $icons, + 'background_color' => $body_background, + 'theme_color' => $admin_bar_color, + 'display' => 'standalone', + 'orientation' => 'portrait', + 'start_url' => admin_url(), + // Open front-end, login page, and any external URLs in a browser modal. + 'scope' => admin_url(), + ) +); diff --git a/lib/pwa.php b/lib/pwa.php new file mode 100644 index 00000000000000..2706e9f02c3e07 --- /dev/null +++ b/lib/pwa.php @@ -0,0 +1,27 @@ +'; + } +); + +add_filter( + 'load-index.php', + function() { + if ( ! isset( $_GET['manifest'] ) ) { + return; + } + + require_once __DIR__ . '/manifest.php'; + exit; + } +); From 53e0e2e89868364cacf794d6494676cb9d7e90b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 30 Jun 2021 17:03:12 +0300 Subject: [PATCH 02/13] Remove accidental change --- docs/manifest.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/manifest.json b/docs/manifest.json index 002369b17e1ae0..ef37c643699f25 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1493,12 +1493,6 @@ "markdown_source": "../packages/e2e-tests/README.md", "parent": "packages" }, - { - "title": "@wordpress/edit-dashboard", - "slug": "packages-edit-dashboard", - "markdown_source": "../packages/edit-dashboard/README.md", - "parent": "packages" - }, { "title": "@wordpress/edit-navigation", "slug": "packages-edit-navigation", From 0c9b67b6558782d042253a5463d8e983ed141800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 30 Jun 2021 22:20:14 +0300 Subject: [PATCH 03/13] Fix loading in Chrome --- lib/pwa.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pwa.php b/lib/pwa.php index 2706e9f02c3e07..09640066cff9e1 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -9,8 +9,8 @@ 'admin_head', function() { // Move to the wp-admin folder when merging with core. - $manifest_url = admin_url() . '/?manifest'; - echo ''; + $manifest_url = admin_url( '?manifest' ); + echo ''; } ); From deb33fe4e0ad7d036cda4a564955371aa35751d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Thu, 1 Jul 2021 19:39:00 +0300 Subject: [PATCH 04/13] Add service worker (needed for Chrome) --- lib/pwa.php | 23 +++++++++++++++++++++++ lib/service-worker.js | 5 +++++ 2 files changed, 28 insertions(+) create mode 100644 lib/service-worker.js diff --git a/lib/pwa.php b/lib/pwa.php index 09640066cff9e1..211be6070b7155 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -10,7 +10,17 @@ function() { // Move to the wp-admin folder when merging with core. $manifest_url = admin_url( '?manifest' ); + // Must be at the admin root so the scope is correct. Move to the + // wp-admin folder when merging with core. + $service_worker_url = admin_url( '?service-worker' ); echo ''; + echo ''; } ); @@ -25,3 +35,16 @@ function() { exit; } ); + +add_filter( + 'load-index.php', + function() { + if ( ! isset( $_GET['service-worker'] ) ) { + return; + } + + header( 'Content-Type: text/javascript' ); + echo file_get_contents( __DIR__ . '/service-worker.js' ); + exit; + } +); diff --git a/lib/service-worker.js b/lib/service-worker.js new file mode 100644 index 00000000000000..640de0b42bd5b3 --- /dev/null +++ b/lib/service-worker.js @@ -0,0 +1,5 @@ +/* global addEventListener, fetch */ + +addEventListener( 'fetch', function ( event ) { + event.respondWith( fetch( event.request ) ); +} ); From c6af99ac5932c4f3b2c8ab818c85c0dedc95bf04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Thu, 1 Jul 2021 21:18:52 +0300 Subject: [PATCH 05/13] Fix Chrome PWA --- lib/manifest.php | 45 ----------------------------------------- lib/pwa.php | 47 +++++++++++++++++++++++++++++-------------- lib/service-worker.js | 15 +++++++++++--- 3 files changed, 44 insertions(+), 63 deletions(-) delete mode 100644 lib/manifest.php diff --git a/lib/manifest.php b/lib/manifest.php deleted file mode 100644 index 0a9792aabb4412..00000000000000 --- a/lib/manifest.php +++ /dev/null @@ -1,45 +0,0 @@ -colors; -$admin_bar_color = $colors[0]; -$body_background = '#f1f1f1'; - -$icon_sizes = array( 32, 180, 192, 270, 512 ); - -// Ideally we have the WordPress logo as the default app logo in the sizes -// below. -$icons = array(); - -if ( has_site_icon() ) { - $type = wp_check_filetype( get_site_icon_url() ); - - foreach ( $icon_sizes as $size ) { - $icons[] = array( - 'src' => get_site_icon_url( $size ), - 'sizes' => $size . 'x' . $size, - 'type' => $type['type'], - ); - } -} - -wp_send_json( - array( - 'name' => get_bloginfo( 'name' ), - 'icons' => $icons, - 'background_color' => $body_background, - 'theme_color' => $admin_bar_color, - 'display' => 'standalone', - 'orientation' => 'portrait', - 'start_url' => admin_url(), - // Open front-end, login page, and any external URLs in a browser modal. - 'scope' => admin_url(), - ) -); diff --git a/lib/pwa.php b/lib/pwa.php index 211be6070b7155..cd1dbe5266f531 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -8,12 +8,41 @@ add_filter( 'admin_head', function() { - // Move to the wp-admin folder when merging with core. - $manifest_url = admin_url( '?manifest' ); + $icon_sizes = array( 32, 180, 192, 270, 512 ); + + // Ideally we have the WordPress logo as the default app logo in the sizes + // below. + $icons = array(); + + if ( has_site_icon() ) { + $type = wp_check_filetype( get_site_icon_url() ); + + foreach ( $icon_sizes as $size ) { + $icons[] = array( + 'src' => get_site_icon_url( $size ), + 'sizes' => $size . 'x' . $size, + 'type' => $type['type'], + ); + } + } + + $manifest = wp_json_encode( + array( + 'name' => get_bloginfo( 'name' ), + 'icons' => $icons, + 'display' => 'standalone', + 'orientation' => 'portrait', + 'start_url' => admin_url(), + // Open front-end, login page, and any external URLs in a browser modal. + 'scope' => admin_url(), + ) + ); + // Must be at the admin root so the scope is correct. Move to the // wp-admin folder when merging with core. $service_worker_url = admin_url( '?service-worker' ); - echo ''; + + echo ''; echo ''; + echo ""; } ); From f6f274e1e2700c865c39ef0fab11a7cafd7ae2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Fri, 2 Jul 2021 18:37:18 +0300 Subject: [PATCH 07/13] clean up --- lib/pwa-load.js | 42 +++++++++++++++++++++++++----------------- lib/pwa.php | 48 ++++-------------------------------------------- 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index b0d2a5190d8963..1b0b8e09423f36 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -1,7 +1,5 @@ /* global scriptVars */ -const win = window; - function addManifest( manifest ) { const link = document.createElement( 'link' ); link.rel = 'manifest'; @@ -32,7 +30,7 @@ function createIcon( svgElement, size, backgroundColor ) { context.fillStyle = backgroundColor; context.fillRect( 0, 0, canvas.width, canvas.height ); - const blob = new win.Blob( [ svgElement.outerHTML ], { + const blob = new window.Blob( [ svgElement.outerHTML ], { type: 'image/svg+xml', } ); const url = URL.createObjectURL( blob ); @@ -54,16 +52,35 @@ function createIcon( svgElement, size, backgroundColor ) { } ); } -if ( 'serviceWorker' in win.navigator ) { - win.addEventListener( 'load', function () { - const { serviceWorkerUrl, logo, manifest } = scriptVars; +if ( 'serviceWorker' in window.navigator ) { + // eslint-disable-next-line @wordpress/no-global-event-listener + window.addEventListener( 'load', function () { + const { serviceWorkerUrl, logo, siteTitle, adminUrl } = scriptVars; + const manifest = { + name: siteTitle, + display: 'standalone', + orientation: 'portrait', + start_url: adminUrl, + // Open front-end, login page, and any external URLs in a browser + // modal. + scope: adminUrl, + icons: [], + }; - win.navigator.serviceWorker.register( serviceWorkerUrl ); + window.navigator.serviceWorker.register( serviceWorkerUrl ); const adminBar = document.getElementById( 'wpadminbar' ); const { backgroundColor } = window.getComputedStyle( adminBar ); const svgElement = createSvgElement( logo ); + function addToManifest( base64data ) { + manifest.icons.push( { + src: base64data, + sizes: '192x192', + type: 'image/png', + } ); + } + createIcon( svgElement, 180, backgroundColor ).then( ( base64data ) => { const iconLink = document.createElement( 'link' ); iconLink.rel = 'apple-touch-icon'; @@ -73,18 +90,9 @@ if ( 'serviceWorker' in win.navigator ) { iconLink, document.head.firstElementChild ); + addToManifest( base64data ); } ); - manifest.icons = []; - - function addToManifest( base64data ) { - manifest.icons.push( { - src: base64data, - sizes: '192x192', - type: 'image/png', - } ); - } - Promise.all( [ createIcon( svgElement, 192, backgroundColor ).then( addToManifest diff --git a/lib/pwa.php b/lib/pwa.php index 38158f8e58d7b5..9c3b850b1c69c8 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -8,49 +8,6 @@ add_filter( 'admin_head', function() { - $icon_sizes = array( 180, 192, 512 ); - - $icons = array( - array( - 'src' => 'https://s1.wp.com/i/favicons/apple-touch-icon-180x180.png', - 'sizes' => '180x180', - 'type' => 'image/png', - ), - // Android/Chrome. - array( - 'src' => 'https://wordpress.com/calypso/images/manifest/icon-192x192.png', - 'sizes' => '192x192', - 'type' => 'image/png', - ), - array( - 'src' => 'https://wordpress.com/calypso/images/manifest/icon-512x512.png', - 'sizes' => '512x512', - 'type' => 'image/png', - ), - ); - - if ( false ) { - $type = wp_check_filetype( get_site_icon_url() ); - - foreach ( $icon_sizes as $size ) { - $icons[] = array( - 'src' => get_site_icon_url( $size ), - 'sizes' => $size . 'x' . $size, - 'type' => $type['type'], - ); - } - } - - $manifest = array( - 'name' => get_bloginfo( 'name' ), - // 'icons' => $icons, - 'display' => 'standalone', - 'orientation' => 'portrait', - 'start_url' => admin_url(), - // Open front-end, login page, and any external URLs in a browser modal. - 'scope' => admin_url(), - ); - $script = file_get_contents( __DIR__ . '/pwa-load.js' ); $script_vars = wp_json_encode( array( @@ -58,7 +15,8 @@ function() { // wp-admin folder when merging with core. 'serviceWorkerUrl' => admin_url( '?service-worker' ), 'logo' => file_get_contents( ABSPATH . 'wp-admin/images/wordpress-logo-white.svg' ), - 'manifest' => $manifest, + 'siteTitle' => get_bloginfo( 'name' ), + 'adminUrl' => admin_url(), ) ); @@ -74,6 +32,8 @@ function() { } header( 'Content-Type: text/javascript' ); + // Must be at the admin root so the scope is correct. Move to the + // wp-admin folder when merging with core. echo file_get_contents( __DIR__ . '/service-worker.js' ); exit; } From 8d6c0a785c9296f99d46bd653558cb2526cc73d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Fri, 2 Jul 2021 21:03:58 +0300 Subject: [PATCH 08/13] Clean up --- lib/pwa-load.js | 171 +++++++++++++++++++++++++++++++----------------- lib/pwa.php | 9 +-- 2 files changed, 114 insertions(+), 66 deletions(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index 1b0b8e09423f36..23f4a655039927 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -7,6 +7,14 @@ function addManifest( manifest ) { document.head.appendChild( link ); } +function addAppleTouchIcon( size, base64data ) { + const iconLink = document.createElement( 'link' ); + iconLink.rel = 'apple-touch-icon'; + iconLink.href = base64data; + iconLink.sizes = '180x180'; + document.head.insertBefore( iconLink, document.head.firstElementChild ); +} + function createSvgElement( html ) { const doc = document.implementation.createHTMLDocument( '' ); doc.body.innerHTML = html; @@ -15,36 +23,64 @@ function createSvgElement( html ) { return svgElement; } -function createIcon( svgElement, size, backgroundColor ) { +function createIcon( { svgElement, size, color, backgroundColor, circle } ) { return new Promise( ( resolve ) => { - // https://w3c.github.io/manifest/#icon-masks - const padding = size / 8; - const logoSize = padding * 6; const canvas = document.createElement( 'canvas' ); const context = canvas.getContext( '2d' ); + // Leave 1/8th padding around the logo. + const padding = size / 8; + // Which leaves 3/4ths of space for the icon. + const logoSize = padding * 6; + + // Resize the SVG logo. svgElement.setAttribute( 'width', logoSize ); svgElement.setAttribute( 'height', logoSize ); + + // Color in the background. + svgElement.querySelectorAll( 'path' ).forEach( ( path ) => { + path.setAttribute( 'fill', backgroundColor ); + } ); + + // Resize the canvas. canvas.width = size; canvas.height = size; - context.fillStyle = backgroundColor; - context.fillRect( 0, 0, canvas.width, canvas.height ); - const blob = new window.Blob( [ svgElement.outerHTML ], { + // If we're not drawing a circle, set the background color. + if ( ! circle ) { + context.fillStyle = backgroundColor; + context.fillRect( 0, 0, canvas.width, canvas.height ); + } + + // Fill in the letter (W) and circle around it. + context.fillStyle = color; + context.beginPath(); + context.arc( size / 2, size / 2, logoSize / 2 - 1, 0, 2 * Math.PI ); + context.closePath(); + context.fill(); + + // Create a URL for the SVG to load in an image element. + const svgBlob = new window.Blob( [ svgElement.outerHTML ], { type: 'image/svg+xml', } ); - const url = URL.createObjectURL( blob ); + const url = URL.createObjectURL( svgBlob ); const image = document.createElement( 'img' ); + image.src = url; image.width = logoSize; image.height = logoSize; image.onload = () => { + // Once the image is loaded, draw it onto the canvas. context.drawImage( image, padding, padding ); - canvas.toBlob( ( bb ) => { - // URL.revokeObjectURL( url ); + // Export it to a blob. + canvas.toBlob( ( imageBlob ) => { + // We no longer need the SVG blob url. + URL.revokeObjectURL( url ); + // Unfortunately blob URLs don't seem to work, so we have to use + // base64 encoded data URLs. const reader = new window.FileReader(); - reader.readAsDataURL( bb ); - reader.onloadend = function () { + reader.readAsDataURL( imageBlob ); + reader.onloadend = () => { resolve( reader.result ); }; } ); @@ -52,56 +88,71 @@ function createIcon( svgElement, size, backgroundColor ) { } ); } -if ( 'serviceWorker' in window.navigator ) { - // eslint-disable-next-line @wordpress/no-global-event-listener - window.addEventListener( 'load', function () { - const { serviceWorkerUrl, logo, siteTitle, adminUrl } = scriptVars; - const manifest = { - name: siteTitle, - display: 'standalone', - orientation: 'portrait', - start_url: adminUrl, - // Open front-end, login page, and any external URLs in a browser - // modal. - scope: adminUrl, - icons: [], - }; +if ( ! ( 'serviceWorker' in window.navigator ) ) { + return; +} - window.navigator.serviceWorker.register( serviceWorkerUrl ); +// eslint-disable-next-line @wordpress/no-global-event-listener +window.addEventListener( 'load', () => { + const { logo, siteTitle, adminUrl } = scriptVars; + const manifest = { + name: siteTitle, + display: 'standalone', + orientation: 'portrait', + start_url: adminUrl, + // Open front-end, login page, and any external URLs in a browser + // modal. + scope: adminUrl, + icons: [], + }; - const adminBar = document.getElementById( 'wpadminbar' ); - const { backgroundColor } = window.getComputedStyle( adminBar ); - const svgElement = createSvgElement( logo ); + const adminBar = document.getElementById( 'wpadminbar' ); + const { color, backgroundColor } = window.getComputedStyle( adminBar ); + const svgElement = createSvgElement( logo ); - function addToManifest( base64data ) { - manifest.icons.push( { - src: base64data, - sizes: '192x192', - type: 'image/png', - } ); - } - - createIcon( svgElement, 180, backgroundColor ).then( ( base64data ) => { - const iconLink = document.createElement( 'link' ); - iconLink.rel = 'apple-touch-icon'; - iconLink.href = base64data; - iconLink.sizes = '180x180'; - document.head.insertBefore( - iconLink, - document.head.firstElementChild - ); - addToManifest( base64data ); - } ); + Promise.all( [ + // The "normal" icon should be round. This is used for Chrome + // Desktop PWAs. To do: check which sizes are really needed. + ...[ 180, 192, 512 ].map( ( size ) => + createIcon( { + svgElement, + size: 180, + color, + backgroundColor, + circle: true, + } ).then( ( base64data ) => { + manifest.icons.push( { + src: base64data, + sizes: size + 'x' + size, + type: 'image/png', + purpose: 'any', + } ); + } ) + ), + // The maskable icon should have its background filled. This is used + // for iOS. To do: check which sizes are really needed. + ...[ 180, 192, 512 ].map( ( size ) => + createIcon( { + svgElement, + size: 180, + color, + backgroundColor, + } ).then( ( base64data ) => { + manifest.icons.push( { + src: base64data, + sizes: size + 'x' + size, + type: 'image/png', + purpose: 'maskable', + } ); - Promise.all( [ - createIcon( svgElement, 192, backgroundColor ).then( - addToManifest - ), - createIcon( svgElement, 512, backgroundColor ).then( - addToManifest - ), - ] ).then( () => { - addManifest( manifest ); - } ); + // iOS doesn't seem to look at the manifest. + if ( size === 180 ) { + addAppleTouchIcon( size, base64data ); + } + } ) + ), + ] ).then( () => { + addManifest( manifest ); + window.navigator.serviceWorker.register( adminUrl + '?service-worker' ); } ); -} +} ); diff --git a/lib/pwa.php b/lib/pwa.php index 9c3b850b1c69c8..73cdaf892da257 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -11,12 +11,9 @@ function() { $script = file_get_contents( __DIR__ . '/pwa-load.js' ); $script_vars = wp_json_encode( array( - // Must be at the admin root so the scope is correct. Move to the - // wp-admin folder when merging with core. - 'serviceWorkerUrl' => admin_url( '?service-worker' ), - 'logo' => file_get_contents( ABSPATH . 'wp-admin/images/wordpress-logo-white.svg' ), - 'siteTitle' => get_bloginfo( 'name' ), - 'adminUrl' => admin_url(), + 'logo' => file_get_contents( ABSPATH . 'wp-admin/images/wordpress-logo-white.svg' ), + 'siteTitle' => get_bloginfo( 'name' ), + 'adminUrl' => admin_url(), ) ); From fb80dc1d7f7cf45d3c870a364354c9458bc1da58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Fri, 2 Jul 2021 21:18:52 +0300 Subject: [PATCH 09/13] Fix spaces in Chrome --- lib/pwa-load.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index 23f4a655039927..3fdd26fbad7897 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -96,7 +96,8 @@ if ( ! ( 'serviceWorker' in window.navigator ) ) { window.addEventListener( 'load', () => { const { logo, siteTitle, adminUrl } = scriptVars; const manifest = { - name: siteTitle, + // Replace spaces with non breaking spaces. Chrome collapses them. + name: siteTitle.replace( / /g, ' ' ), display: 'standalone', orientation: 'portrait', start_url: adminUrl, From 19cb71afc9c33e102720a8f392db93120fd439c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Sat, 3 Jul 2021 12:05:39 +0300 Subject: [PATCH 10/13] Try to prioritise maskable icon --- lib/pwa-load.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index 3fdd26fbad7897..bba09fe7ec1be2 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -112,44 +112,44 @@ window.addEventListener( 'load', () => { const svgElement = createSvgElement( logo ); Promise.all( [ - // The "normal" icon should be round. This is used for Chrome - // Desktop PWAs. To do: check which sizes are really needed. + // The maskable icon should have its background filled. This is used + // for iOS. To do: check which sizes are really needed. ...[ 180, 192, 512 ].map( ( size ) => createIcon( { svgElement, size: 180, color, backgroundColor, - circle: true, } ).then( ( base64data ) => { manifest.icons.push( { src: base64data, sizes: size + 'x' + size, type: 'image/png', - purpose: 'any', + purpose: 'maskable', } ); + + // iOS doesn't seem to look at the manifest. + if ( size === 180 ) { + addAppleTouchIcon( size, base64data ); + } } ) ), - // The maskable icon should have its background filled. This is used - // for iOS. To do: check which sizes are really needed. + // The "normal" icon should be round. This is used for Chrome + // Desktop PWAs. To do: check which sizes are really needed. ...[ 180, 192, 512 ].map( ( size ) => createIcon( { svgElement, size: 180, color, backgroundColor, + circle: true, } ).then( ( base64data ) => { manifest.icons.push( { src: base64data, sizes: size + 'x' + size, type: 'image/png', - purpose: 'maskable', + purpose: 'any', } ); - - // iOS doesn't seem to look at the manifest. - if ( size === 180 ) { - addAppleTouchIcon( size, base64data ); - } } ) ), ] ).then( () => { From 3a9e14e8f9e496a04554dad81c14d0964679d8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Sat, 3 Jul 2021 14:45:52 +0300 Subject: [PATCH 11/13] Try 'maskable any' --- lib/pwa-load.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index bba09fe7ec1be2..28439cb458cd0e 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -125,7 +125,7 @@ window.addEventListener( 'load', () => { src: base64data, sizes: size + 'x' + size, type: 'image/png', - purpose: 'maskable', + purpose: 'maskable any', } ); // iOS doesn't seem to look at the manifest. From a112140eee1612d26932c223f3db6d4cfc30f24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Sat, 3 Jul 2021 14:58:55 +0300 Subject: [PATCH 12/13] Fix sizes --- lib/pwa-load.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pwa-load.js b/lib/pwa-load.js index 28439cb458cd0e..75340163f0022c 100644 --- a/lib/pwa-load.js +++ b/lib/pwa-load.js @@ -117,7 +117,7 @@ window.addEventListener( 'load', () => { ...[ 180, 192, 512 ].map( ( size ) => createIcon( { svgElement, - size: 180, + size, color, backgroundColor, } ).then( ( base64data ) => { @@ -125,7 +125,7 @@ window.addEventListener( 'load', () => { src: base64data, sizes: size + 'x' + size, type: 'image/png', - purpose: 'maskable any', + purpose: 'maskable', } ); // iOS doesn't seem to look at the manifest. @@ -139,7 +139,7 @@ window.addEventListener( 'load', () => { ...[ 180, 192, 512 ].map( ( size ) => createIcon( { svgElement, - size: 180, + size, color, backgroundColor, circle: true, From 5018965d264dad23e9333e4ee2e9fe580dd492d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Mon, 5 Jul 2021 13:26:59 +0300 Subject: [PATCH 13/13] Move script to package --- .github/CODEOWNERS | 5 +++ docs/manifest.json | 6 ++++ lib/pwa.php | 15 ++++----- package-lock.json | 6 ++++ package.json | 1 + packages/admin-manifest/.npmrc | 1 + packages/admin-manifest/CHANGELOG.md | 0 packages/admin-manifest/README.md | 3 ++ packages/admin-manifest/package.json | 33 +++++++++++++++++++ .../admin-manifest/src/index.js | 12 +++---- 10 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 packages/admin-manifest/.npmrc create mode 100644 packages/admin-manifest/CHANGELOG.md create mode 100644 packages/admin-manifest/README.md create mode 100644 packages/admin-manifest/package.json rename lib/pwa-load.js => packages/admin-manifest/src/index.js (97%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7d74d423b42530..cd63087b8124cb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -127,6 +127,11 @@ /lib/class-wp-theme-json-resolver-gutenberg.php @timothybjabocs @spacedmonkey @nosolosw /phpunit/class-wp-theme-json-test.php @nosolosw +# Web App +/packages/admin-manifest @ellatrix +/lib/pwa.php @ellatrix +/lib/service-worker.js @ellatrix + # Native (Unowned) *.native.js @ghost *.android.js @ghost diff --git a/docs/manifest.json b/docs/manifest.json index ef37c643699f25..ede0e009f199fe 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1301,6 +1301,12 @@ "markdown_source": "../packages/a11y/README.md", "parent": "packages" }, + { + "title": "@wordpress/admin-manifest", + "slug": "packages-admin-manifest", + "markdown_source": "../packages/admin-manifest/README.md", + "parent": "packages" + }, { "title": "@wordpress/annotations", "slug": "packages-annotations", diff --git a/lib/pwa.php b/lib/pwa.php index 73cdaf892da257..4e3c86bee7ecc2 100644 --- a/lib/pwa.php +++ b/lib/pwa.php @@ -8,16 +8,13 @@ add_filter( 'admin_head', function() { - $script = file_get_contents( __DIR__ . '/pwa-load.js' ); - $script_vars = wp_json_encode( - array( - 'logo' => file_get_contents( ABSPATH . 'wp-admin/images/wordpress-logo-white.svg' ), - 'siteTitle' => get_bloginfo( 'name' ), - 'adminUrl' => admin_url(), - ) + $l10n = array( + 'logo' => file_get_contents( ABSPATH . 'wp-admin/images/wordpress-logo-white.svg' ), + 'siteTitle' => get_bloginfo( 'name' ), + 'adminUrl' => admin_url(), ); - - echo ""; + wp_enqueue_script( 'wp-admin-manifest' ); + wp_localize_script( 'wp-admin-manifest', 'wpAdminManifestL10n', $l10n ); } ); diff --git a/package-lock.json b/package-lock.json index ca2d654ff162ae..8a685b0f36d410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13703,6 +13703,12 @@ "@wordpress/i18n": "file:packages/i18n" } }, + "@wordpress/admin-manifest": { + "version": "file:packages/admin-manifest", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, "@wordpress/annotations": { "version": "file:packages/annotations", "requires": { diff --git a/package.json b/package.json index 4546293f5555aa..e94da91a3047a4 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@wordpress/a11y": "file:packages/a11y", + "@wordpress/admin-manifest": "file:packages/admin-manifest", "@wordpress/annotations": "file:packages/annotations", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/autop": "file:packages/autop", diff --git a/packages/admin-manifest/.npmrc b/packages/admin-manifest/.npmrc new file mode 100644 index 00000000000000..43c97e719a5a82 --- /dev/null +++ b/packages/admin-manifest/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/admin-manifest/CHANGELOG.md b/packages/admin-manifest/CHANGELOG.md new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/packages/admin-manifest/README.md b/packages/admin-manifest/README.md new file mode 100644 index 00000000000000..6b6ac3021fe303 --- /dev/null +++ b/packages/admin-manifest/README.md @@ -0,0 +1,3 @@ +# Admin Manifest + +Dynamically creates a Web App [manifest](https://w3c.github.io/manifest/) and registers the service worker for the admin. diff --git a/packages/admin-manifest/package.json b/packages/admin-manifest/package.json new file mode 100644 index 00000000000000..1282dc528c0325 --- /dev/null +++ b/packages/admin-manifest/package.json @@ -0,0 +1,33 @@ +{ + "name": "@wordpress/admin-manifest", + "version": "1.0.0", + "description": "Dynamically creates a Web App manifest and registers the service worker for the admin.", + "author": "The WordPress Contributors", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress", + "gutenberg", + "manifest" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/admin-manifest/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git", + "directory": "packages/admin-manifest" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "engines": { + "node": ">=12" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "react-native": "src/index", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/lib/pwa-load.js b/packages/admin-manifest/src/index.js similarity index 97% rename from lib/pwa-load.js rename to packages/admin-manifest/src/index.js index 75340163f0022c..5b2deb55f9ea1f 100644 --- a/lib/pwa-load.js +++ b/packages/admin-manifest/src/index.js @@ -1,5 +1,3 @@ -/* global scriptVars */ - function addManifest( manifest ) { const link = document.createElement( 'link' ); link.rel = 'manifest'; @@ -88,13 +86,13 @@ function createIcon( { svgElement, size, color, backgroundColor, circle } ) { } ); } -if ( ! ( 'serviceWorker' in window.navigator ) ) { - return; -} - // eslint-disable-next-line @wordpress/no-global-event-listener window.addEventListener( 'load', () => { - const { logo, siteTitle, adminUrl } = scriptVars; + if ( ! ( 'serviceWorker' in window.navigator ) ) { + return; + } + + const { logo, siteTitle, adminUrl } = window.wpAdminManifestL10n; const manifest = { // Replace spaces with non breaking spaces. Chrome collapses them. name: siteTitle.replace( / /g, ' ' ),