Gothic Poems of Love & Liberty
A hauntingly beautiful collection of poetry that explores love, freedom, and the shadows of the soul.
A hauntingly beautiful collection of poetry that explores love, freedom, and the shadows of the soul.
In this article, wel will learn how to build a PWA (Progressive Web App) for your website in an easy way.
Progressive web apps are a new way to create native-like experiences on the web. They combine the best of both worlds, providing users with the best of a website and an app.
A Progressive Web App is a webview app that can be installed on your phone or tablet like an app, but it's built with web technologies. This means you can add features like push notifications and offline support without having to build a separate native app.
A Progressive Web App is a website that behaves like an app on the user’s device. It loads quickly, is responsive to different devices, and can be accessed at any time without the need to download anything.
A Progressive Web App offers a better experience than a traditional website for both users and developers. It has features that are usually found in native apps such as push notifications, offline support, and home screen icons. This means that it will load faster, look better on all types of screens, have more functionality than a regular website, and will be available even when the device is offline.
In order to build a Progressive Web App, you will need to add some features to your website. These features include service workers, which allow your site to work offline, and push notifications for when users return to your site. You can also install an Add-to-Home screen prompt on your website that prompts users to add your site or app to their home screen on their mobile device or desktop computer.
This tutorial may be a bit difficult to understand, but if you follow all the steps correctly, you will surely be able to build a PWA for your Blogger Website.
This process requires a Custom Domain with the integration of Cloudflare, and it can't be done on the .blogspot subdomain with this process. With .blogspot you can't set up service worker.
{ "name": "Class With Mason", "short_name": "Class w Mason", "description": "Install Now and Fuel the Creativity", "lang": "en-US", "display": "standalone", "background_color": "#ffffff", "start_url": "https://www.classwithmason.com", "theme_color": "#ffffff", "orientation": "portrait", "dir": "ltr", "prefer_related_applications": false, "icons": [ { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/favicon-32x32.png", "sizes": "32x32", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/apple-icon-72x72.png", "sizes": "72x72", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/favicon-96x96.png", "sizes": "96x96", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/apple-icon-120x120.png", "sizes": "120x120", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/android-icon-144x144.png", "sizes": "144x144", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/apple-icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm@main/android-icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm/an-android-icon-512x512.png", "sizes": "512x512", "type": "image/png" } ], "screenshots": [ { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm/screenshot1%20(1).jpg", "sizes": "1080x1920", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm/screenshot1%20(2).jpg", "sizes": "1080x1920", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm/screenshot1%20(3).jpg", "sizes": "1080x1920", "type": "image/png" }, { "src": "https://cdn.jsdelivr.net/gh/Mushahid7734/icon-cwm/screenshot%20big.png", "sizes": "1280x800", "type": "image/png" } ], "serviceworker": { "src": "https://classwithmason.com/sw.js" } }
const js = ` importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js'); if (workbox) { workbox.core.skipWaiting(); workbox.core.clientsClaim(); workbox.core.setCacheNameDetails({ prefix: 'thn-sw', suffix: 'v22', precache: 'install-time', runtime: 'run-time' }); const FALLBACK_HTML_URL = '/offline.html'; const version = workbox.core.cacheNames.suffix; workbox.precaching.precacheAndRoute([{url: FALLBACK_HTML_URL, revision: null},{url: 'https://cdn.jsdelivr.net/gh/(github username)/repository/manifest.JSON', revision: null},{url: '/favicon.ico', revision: null}]); workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly()); workbox.routing.registerRoute( new RegExp('.(?:css|js|png|gif|jpg|svg|ico)$'), new workbox.strategies.CacheFirst({ cacheName: 'images-js-css-' + version, plugins: [ new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 60 * 24 * 60 * 60, maxEntries:200, purgeOnQuotaError: true }) ], }),'GET' ); workbox.routing.setCatchHandler(({event}) => { switch (event.request.destination) { case 'document': return caches.match(FALLBACK_HTML_URL); break; default: return Response.error(); } }); self.addEventListener('activate', function(event) { event.waitUntil( caches .keys() .then(keys => keys.filter(key => !key.endsWith(version))) .then(keys => Promise.all(keys.map(key => caches.delete(key)))) ); }); } else { console.log('Oops! Workbox did not load'); } ` async function handleRequest(request) { return new Response(js, { headers: { "content-type": "application/javascript;charset=UTF-8", }, }) } addEventListener("fetch", event => { return event.respondWith(handleRequest(event.request)) })
<script>/*<![CDATA[*/ /* Service Worker */ if('serviceWorker' in navigator){window.addEventListener('load',()=>{navigator.serviceWorker.register('https://www.classwithmason.com/sw.js').then(registration=>{console.log('ServiceWorker registeration successful')}).catch(registrationError=>{console.log('ServiceWorker registration failed: ', registrationError)})})}; /*]]>*/</script>
<script async='async' custom-element='amp-install-serviceworker' src='https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js'/>
<amp-install-serviceworker data-iframe-src='/offline.html' layout='nodisplay' src='/sw.js'/>
#dev_blogger{margin:10px;text-align:center;color:#000;background-color:#fff;border:none;padding:10px 20px;cursor:pointer;font-size:14px;border-radius:20px;box-shadow:0 2px 4px rgba(0,0,0,.1);}#dev_blogger:hover{background-color:#f5f5f5;}@media screen and (max-width:767px){#dev_blogger{width:100%;}}
<script>/*<![CDATA[*/ const installButton = document.getElementById("dev_blogger");window.addEventListener("beforeinstallprompt", e => {e.preventDefault();deferredPrompt = e;installButton.hidden = false;installButton.addEventListener("click", installApp);});function installApp() {deferredPrompt.prompt();installButton.disabled = true;deferredPrompt.userChoice.then(choiceResult => {if (choiceResult.outcome === "accepted") {installButton.hidden = true;} else {}installButton.disabled = false;deferredPrompt = null;});}window.addEventListener("appinstalled", evt => {console.log("appinstalled fired", evt);}); /*]]>*/</script>
<b:if cond='!data:view.isError and data:view.url != data:view.url params { amp: "1" }'> <script>/*<![CDATA[*/ const installButton = document.getElementById("dev_blogger");window.addEventListener("beforeinstallprompt", e => {e.preventDefault();deferredPrompt = e;installButton.hidden = false;installButton.addEventListener("click", installApp);});function installApp() {deferredPrompt.prompt();installButton.disabled = true;deferredPrompt.userChoice.then(choiceResult => {if (choiceResult.outcome === "accepted") {installButton.hidden = true;} else {}installButton.disabled = false;deferredPrompt = null;});}window.addEventListener("appinstalled", evt => {console.log("appinstalled fired", evt);}); /*]]>*/</script> </b:if>
<button hidden='' id='dev_blogger'>Install App</button>
const html = `<!DOCTYPE html> <html> <head> <!--[ Meta Tags ]--> <title>Oops, You're Offline!</title> <meta charset='UTF-8'/> <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' name='viewport'/> <meta content='IE=edge' http-equiv='X-UA-Compatible'/> <!--[ Theme Color ]--> <meta content='#2196f3' name='theme-color'/> <meta content='#2196f3' name='msapplication-navbutton-color'/> <meta content='#2196f3' name='apple-mobile-web-app-status-bar-style'/> <meta content='true' name='apple-mobile-web-app-capable'/> <!--[ Favicon ]--> <link href='/main/apple-icon-120x120.png' rel='apple-touch-icon' sizes='120x120'/> <link href='/main/apple-icon-152x152.png' rel='apple-touch-icon' sizes='152x152'/> <link href='/main/favicon-32x32.png' rel='icon' sizes='32x32' type='image/png'/> <link href='/main/favicon-96x96.png' rel='icon' sizes='96x96' type='image/png'/> <link href='/main/favicon-16x16.png' rel='icon' sizes='16x16' type='image/png'/> <link href='/main/favicon.ico' rel='icon' type='image/x-icon'/> <link href='/main/favicon.ico' rel='shortcut icon' type='image/x-icon'/> <!--[ Stylesheet ]--> <style>/*<![CDATA[*/ /* Merriweather - Font */ @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 300; font-display: swap; src: local('Merriweather-LightItalic'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7lXff4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7lXcf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWPf4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR71Wsf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: italic; font-weight: 900; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWPf4jvw.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4l0qyriQwlOrhSvowK_l5-eR7NWMf8.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 300; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l521wRZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l521wRpXA.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52xwNZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52xwNpXA.woff) format('woff')} @font-face{font-family: 'Merriweather'; font-style: normal; font-weight: 900; font-display: swap; src: url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52_wFZWMf6.woff2) format('woff2'), url(https://fonts.gstatic.com/s/merriweather/v22/u-4n0qyriQwlOrhSvowK_l52_wFpXA.woff) format('woff')} /* Content */ body{background:#f1f3f6;color:#1f1f1f;font-family:'Merriweather',serif;font-weight:400;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body:focus{outline:none !important} .mainCont{margin:0 auto;position:fixed;left:0;top:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;padding:15px} .noIntPop{position:relative;overflow:hidden;text-align:center;padding:15px;border-radius:30px;background:#f1f3f6;box-shadow:inset 0 0 15px rgba(55, 84, 170, 0), inset 0 0 20px rgba(255, 255, 255, 0), 7px 7px 15px rgba(55, 84, 170, 0.15), -7px -7px 20px white, inset 0px 0px 4px rgba(255, 255, 255, 0.2)} .circle.t{top:-150px;right:-150px} .circle.b{bottom:-150px;left:-150px} .noIntCont{position:relative;z-index:1} .noIntIcon{padding:30px} .noConHead{font-weight:700;font-size:1.3rem} .noConDesc{font-size:16px;line-height:1.4em;padding-top:20px;font-weight:400;opacity:.8} .cta,.relCont{display:flex;justify-content:center;align-items:center} .relCont{padding:30px} .cta{width:66px;height:66px;background:#f1f3f6;outline:none;border:none;border-radius:690px;box-shadow:inset 0 0 15px rgba(55, 84, 170, 0), inset 0 0 20px rgba(255, 255, 255, 0), 7px 7px 15px rgba(55, 84, 170, 0.15), -7px -7px 20px white, inset 0px 0px 4px rgba(255, 255, 255, 0.2);transition:box-shadow 399ms ease-in-out} .cta:hover{box-shadow:inset 7px 7px 15px rgba(55, 84, 170, 0.15), inset -7px -7px 20px white, 0px 0px 4px rgba(255, 255, 255, 0.2)} .icon{content:'';width:25px;height:25px;display:inline-block} .iconB{content:'';width:50px;height:50px;display:inline-block} .icon.reload{background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239dabc0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='23 4 23 10 17 10'/><path d='M20.49 15a9 9 0 1 1-2.12-9.36L23 10'/></svg>") center / 25px no-repeat} .iconB.wifiOff{background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f1f1f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='1' y1='1' x2='23' y2='23'/><path d='M16.72 11.06A10.94 10.94 0 0 1 19 12.55'/><path d='M5 12.55a10.94 10.94 0 0 1 5.17-2.39'/><path d='M10.71 5.05A16 16 0 0 1 22.58 9'/><path d='M1.42 9a15.91 15.91 0 0 1 4.7-2.88'/><path d='M8.53 16.11a6 6 0 0 1 6.95 0'/><line x1='12' y1='20' x2='12.01' y2='20'/></svg>") center / 50px no-repeat} .circle{position:absolute;z-index:1;width:280px;height:280px;border-radius:50%;background-color:#f1f3f6;box-shadow:inset 8px 8px 12px #d1d9e6, inset -8px -8px 12px #f9f9f9} /*]]>*/</style> </head> <body> <div class='mainCont notranslate'> <div class='noIntPop'> <div class='circle t'></div> <div class='circle b'></div> <div class='noIntCont'> <div class='noIntIcon'> <i class='iconB wifiOff'></i> </div> <div class='noConHead'>Oops, You're Offline!</div> <div class='noConDesc'>It looks like your network connection isn't working right now.</div> <div class='relCont'> <button class='cta' onclick='window.location.reload()'> <i class='icon reload'></i> </button> </div> </div> </div> </div> </body> </html>` async function handleRequest(request) { return new Response(html, { headers: { "content-type": "text/html;charset=UTF-8", }, }) } addEventListener("fetch", event => { return event.respondWith(handleRequest(event.request)) })