diff --git a/README.md b/README.md new file mode 100644 index 0000000..9df0cd9 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# Simple PWA +## Simple Progressive Web App (PWA) template + +### What is this? +Simple PWA is a Progressive Web App template that provides the minimum file structure needed to create a PWA. These files collectively represent a [reliable](https://web.dev/what-are-pwas/#reliable) and [installable](https://web.dev/what-are-pwas/#installable) web application. It's up to you to add functionality to make it [capable](https://web.dev/what-are-pwas/#capable). + +Simple PWA is "offline-first", using a ["cache falling back to the network"](https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker#cache_falling_back_to_the_network) caching strategy, which means any files specified in [`sw.js`](https://github.com/nikkifurls/simple-pwa/blob/master/sw.js#L10-L46) will be cached, and therefore, accessible offline. Non-cached requests (including non-GET requests, as they cannot be cached), will not be accessible offline, and instead, will ping the network or fail if there is no network available. In [`sw.js`](https://github.com/nikkifurls/simple-pwa/blob/master/sw.js), the value of [`cacheName`](https://github.com/nikkifurls/simple-pwa/blob/master/sw.js#L1) should be changed whenever the app is updated in order to force the cache to update from the network. + +- `android-chrome-36x36.png` Favicon, Android Chrome M39+ with 0.75 screen density +- `android-chrome-48x48.png` Favicon, Android Chrome M39+ with 1.0 screen density +- `android-chrome-72x72.png` Favicon, Android Chrome M39+ with 1.5 screen density +- `android-chrome-96x96.png` Favicon, Android Chrome M39+ with 2.0 screen density +- `android-chrome-144x144.png` Favicon, Android Chrome M39+ with 3.0 screen density +- `android-chrome-192x192.png` Favicon, Android Chrome M39+ with 4.0 screen density +- `android-chrome-256x256.png` Favicon, Android Chrome M47+ Splash screen with 1.5 screen density +- `android-chrome-384x384.png` Favicon, Android Chrome M47+ Splash screen with 3.0 screen density +- `android-chrome-512x512.png` Favicon, Android Chrome M47+ Splash screen with 4.0 screen density +- `apple-touch-icon.png` Favicon, Apple default +- `apple-touch-icon-57x57.png` Apple iPhone, Non-retina with iOS6 or prior +- `apple-touch-icon-60x60.png` Apple iPhone, Non-retina with iOS7 +- `apple-touch-icon-72x72.png` Apple iPad, Non-retina with iOS6 or prior +- `apple-touch-icon-76x76.png` Apple iPad, Non-retina with iOS7 +- `apple-touch-icon-114x114.png` Apple iPhone, Retina with iOS6 or prior +- `apple-touch-icon-120x120.png` Apple iPhone, Retina with iOS7 +- `apple-touch-icon-144x144.png` Apple iPad, Retina with iOS6 or prior +- `apple-touch-icon-152x152.png` Apple iPad, Retina with iOS7 +- `apple-touch-icon-180x180.png` Apple iPhone 6 Plus with iOS8 +- `browserconfig.xml` IE11 icon configuration file +- `favicon_config.json` RealFaviconGenerator configuration file +- `favicon.ico` Favicon, IE and fallback for other browsers +- `favicon.png` Favicon generation source image +- `favicon-16x16.png` Favicon, default +- `favicon-32x32.png` Favicon, Safari on Mac OS +- `index.html` Main HTML file +- `logo.png` Logo +- `main.js` Main Javascript file +- `manifest.json` Manifest file +- `maskable_icon.png` Favicon, [maskable](https://web.dev/maskable-icon) +- `mstile-70x70.png` Favicon, Windows 8 / IE11 +- `mstile-144x144.png` Favicon, Windows 8 / IE10 +- `mstile-150x150.png` Favicon, Windows 8 / IE11 +- `mstile-310x150.png` Favicon, Windows 8 / IE11 +- `mstile-310x310.png` Favicon, Windows 8 / IE11 +- `README.md` Readme file +- `robots.txt` Robots file +- `safari-pinned-tab.svg` Favicon, Safari pinned tab +- `share.jpg` Social media sharing +- `sitemap.xml` Sitemap file +- `sw.js` Service worker file +- `style.css` Main CSS file + +### How do I use it? + +1. Clone the repository from [GitHub](https://github.com/nikkifurls/simple-pwa). +2. Create all favicon images using [RealFaviconGenerator](https://realfavicongenerator.net) and replace existing images with generated images. + + If you're able to install the CLI version of **RealFaviconGenerator**, `favicon_config.json` contains all settings to generate these images using the following command from the project's root directory. The `real-favicon` tool generates images from `favicon.png`, so replace `favicon.png` prior to running this command. The resulting `favicon_data.json` and `site.webmanifest` can be discarded: + + `real-favicon generate favicon_config.json favicon_data.json .` + +3. Create new 650x650 maskable icon using [Maskable.app](https://maskable.app) and replace `maskable_icon.png`. +4. Create new black vector icon using [`Manytools' colorize images tool`](http://manytools.org/image/colorize-filter) and replace [`safari-pinned-tab.svg`](https://github.com/nikkifurls/simple-pwa/blob/master/safari-pinned-tab.svg). +5. Create new 1200x630 share image and replace `share.jpg`. +6. Build your PWA by adding HTML, CSS, and Javascript. + +### Can I contribute? + +YES! Contributions are welcome! \ No newline at end of file diff --git a/android-chrome-144x144.png b/android-chrome-144x144.png new file mode 100644 index 0000000..86cecb4 Binary files /dev/null and b/android-chrome-144x144.png differ diff --git a/android-chrome-192x192.png b/android-chrome-192x192.png new file mode 100644 index 0000000..d9ad329 Binary files /dev/null and b/android-chrome-192x192.png differ diff --git a/android-chrome-256x256.png b/android-chrome-256x256.png new file mode 100644 index 0000000..26eae2b Binary files /dev/null and b/android-chrome-256x256.png differ diff --git a/android-chrome-36x36.png b/android-chrome-36x36.png new file mode 100644 index 0000000..85fbd08 Binary files /dev/null and b/android-chrome-36x36.png differ diff --git a/android-chrome-384x384.png b/android-chrome-384x384.png new file mode 100644 index 0000000..5f76eed Binary files /dev/null and b/android-chrome-384x384.png differ diff --git a/android-chrome-48x48.png b/android-chrome-48x48.png new file mode 100644 index 0000000..a8dacba Binary files /dev/null and b/android-chrome-48x48.png differ diff --git a/android-chrome-512x512.png b/android-chrome-512x512.png new file mode 100644 index 0000000..ee12c2b Binary files /dev/null and b/android-chrome-512x512.png differ diff --git a/android-chrome-72x72.png b/android-chrome-72x72.png new file mode 100644 index 0000000..ea95f9f Binary files /dev/null and b/android-chrome-72x72.png differ diff --git a/android-chrome-96x96.png b/android-chrome-96x96.png new file mode 100644 index 0000000..4b854ce Binary files /dev/null and b/android-chrome-96x96.png differ diff --git a/apple-touch-icon-114x114.png b/apple-touch-icon-114x114.png new file mode 100644 index 0000000..3795318 Binary files /dev/null and b/apple-touch-icon-114x114.png differ diff --git a/apple-touch-icon-120x120.png b/apple-touch-icon-120x120.png new file mode 100644 index 0000000..aa0cb21 Binary files /dev/null and b/apple-touch-icon-120x120.png differ diff --git a/apple-touch-icon-144x144.png b/apple-touch-icon-144x144.png new file mode 100644 index 0000000..9f19592 Binary files /dev/null and b/apple-touch-icon-144x144.png differ diff --git a/apple-touch-icon-152x152.png b/apple-touch-icon-152x152.png new file mode 100644 index 0000000..da4450e Binary files /dev/null and b/apple-touch-icon-152x152.png differ diff --git a/apple-touch-icon-180x180.png b/apple-touch-icon-180x180.png new file mode 100644 index 0000000..1e39b0e Binary files /dev/null and b/apple-touch-icon-180x180.png differ diff --git a/apple-touch-icon-57x57.png b/apple-touch-icon-57x57.png new file mode 100644 index 0000000..445e91b Binary files /dev/null and b/apple-touch-icon-57x57.png differ diff --git a/apple-touch-icon-60x60.png b/apple-touch-icon-60x60.png new file mode 100644 index 0000000..e4ffb99 Binary files /dev/null and b/apple-touch-icon-60x60.png differ diff --git a/apple-touch-icon-72x72.png b/apple-touch-icon-72x72.png new file mode 100644 index 0000000..dfcec29 Binary files /dev/null and b/apple-touch-icon-72x72.png differ diff --git a/apple-touch-icon-76x76.png b/apple-touch-icon-76x76.png new file mode 100644 index 0000000..48fd76f Binary files /dev/null and b/apple-touch-icon-76x76.png differ diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000..1e39b0e Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/browserconfig.xml b/browserconfig.xml new file mode 100644 index 0000000..a816a20 --- /dev/null +++ b/browserconfig.xml @@ -0,0 +1,12 @@ + + + + + + + + + #000000 + + + diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 0000000..9b87e6e Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 0000000..ccde164 Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..8280837 Binary files /dev/null and b/favicon.ico differ diff --git a/favicon.png b/favicon.png new file mode 100644 index 0000000..0ec16de Binary files /dev/null and b/favicon.png differ diff --git a/favicon_config.json b/favicon_config.json new file mode 100644 index 0000000..8854756 --- /dev/null +++ b/favicon_config.json @@ -0,0 +1,61 @@ +{ + "masterPicture": "favicon.png", + "iconsPath": "/", + "design": { + "ios": { + "pictureAspect": "backgroundAndMargin", + "backgroundColor": "#000000", + "margin": "18%", + "assets": { + "ios6AndPriorIcons": true, + "ios7AndLaterIcons": true, + "precomposedIcons": false, + "declareOnlyDefaultIcon": true + } + }, + "desktopBrowser": { + "design": "raw" + }, + "windows": { + "pictureAspect": "noChange", + "backgroundColor": "#000000", + "onConflict": "override", + "assets": { + "windows80Ie10Tile": false, + "windows10Ie11EdgeTiles": { + "small": false, + "medium": true, + "big": false, + "rectangle": false + } + } + }, + "androidChrome": { + "pictureAspect": "noChange", + "themeColor": "#000000", + "manifest": { + "display": "standalone", + "orientation": "notSet", + "onConflict": "override", + "declared": true + }, + "assets": { + "legacyIcon": false, + "lowResolutionIcons": true + } + }, + "safariPinnedTab": { + "pictureAspect": "blackAndWhite", + "threshold": 89.21875, + "themeColor": "#000000" + } + }, + "settings": { + "compression": 2, + "scalingAlgorithm": "Mitchell", + "errorOnImageTooSmall": false, + "readmeFile": false, + "htmlCodeFile": false, + "usePathAsIs": false + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..7f946c8 --- /dev/null +++ b/index.html @@ -0,0 +1,234 @@ + + + + + + + Simple PWA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +

Simple Progressive Web App (PWA) template

+
+
+ +
+
+

What is this?

+

Simple PWA is a Progressive Web App template that provides the minimum file structure needed to create a PWA—a reliable and installable web application. It's up to you to build upon it, to make it capable. +

Simple PWA is "offline-first", using a "cache first" caching strategy, which means on load, two asynchronous requests are kicked off—one to the cache, and one to the network. If there's a cached version available, it is used, but the updated version is fetched and stored for the next load. To force the cache to update from the network, change the value of cacheName in sw.js.

+ +

How do I use it?

+
    +
  1. Clone the repository from GitHub.
  2. +
  3. Create all favicon images using RealFaviconGenerator and replace existing images with generated images. +

    If you're able to install the CLI version of RealFaviconGenerator, favicon_config.json contains all settings to generate these images using the following command from the project's root directory. The real-favicon tool generates images from favicon.png, so replace favicon.png prior to running this command. The resulting favicon_data.json and site.webmanifest can be discarded.

    +

    real-favicon generate favicon_config.json favicon_data.json .

    +
  4. +
  5. Create new 650x650 maskable icon using Maskable.app and replace maskable_icon.png.
  6. +
  7. Create new black vector icon using Manytools' colorize images tool and replace safari-pinned-tab.svg.
  8. +
  9. Create new 1200x630 share image and replace share.jpg.
  10. +
  11. Build upon the PWA by adding HTML, CSS, and Javascript.
  12. +
+

Where can I find other PWAs?

+

Looking for inspiration? Check out these PWA directories:

+ +

Can I contribute?

+

Want to help improve this? Contributions are welcome! ➡️ GitHub

+
+
+ + + + + + diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..00b1b5a Binary files /dev/null and b/logo.png differ diff --git a/main.js b/main.js new file mode 100644 index 0000000..e69de29 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..2db5cb9 --- /dev/null +++ b/manifest.json @@ -0,0 +1,62 @@ +{ + "name": "Simple PWA", + "short_name": "Simple PWA", + "display": "standalone", + "start_url": "./?utm_source=pwa_install", + "scope": ".", + "theme_color": "#000", + "background_color": "#000", + "icons":[ + { + "src": "android-chrome-36x36.png", + "sizes": "36x36", + "type": "image/png" + }, + { + "src": "android-chrome-48x48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "android-chrome-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "android-chrome-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "android-chrome-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-256x256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "maskable_icon.png", + "sizes": "650x650", + "type": "image/png", + "purpose": "maskable" + } + ] +} \ No newline at end of file diff --git a/maskable_icon.png b/maskable_icon.png new file mode 100644 index 0000000..dd3828b Binary files /dev/null and b/maskable_icon.png differ diff --git a/mstile-144x144.png b/mstile-144x144.png new file mode 100644 index 0000000..86cecb4 Binary files /dev/null and b/mstile-144x144.png differ diff --git a/mstile-150x150.png b/mstile-150x150.png new file mode 100644 index 0000000..d54af1b Binary files /dev/null and b/mstile-150x150.png differ diff --git a/mstile-310x150.png b/mstile-310x150.png new file mode 100644 index 0000000..bced8a6 Binary files /dev/null and b/mstile-310x150.png differ diff --git a/mstile-310x310.png b/mstile-310x310.png new file mode 100644 index 0000000..d5dfdb9 Binary files /dev/null and b/mstile-310x310.png differ diff --git a/mstile-70x70.png b/mstile-70x70.png new file mode 100644 index 0000000..38fa737 Binary files /dev/null and b/mstile-70x70.png differ diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..6748eb3 --- /dev/null +++ b/robots.txt @@ -0,0 +1,5 @@ +User-agent: * +Disallow: /.git +Allow: / + +Sitemap: https://simplepwa.com/sitemap.xml \ No newline at end of file diff --git a/safari-pinned-tab.svg b/safari-pinned-tab.svg new file mode 100644 index 0000000..fde0bb1 --- /dev/null +++ b/safari-pinned-tab.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/share.jpg b/share.jpg new file mode 100644 index 0000000..82824e7 Binary files /dev/null and b/share.jpg differ diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..87018dd --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,10 @@ + + + + + + https://simplepwa.com/ + 2020-08-22 + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..a444342 --- /dev/null +++ b/style.css @@ -0,0 +1,86 @@ +html, body { + background-color: black; + color: white; + font-family: helvetica, arial, sans-serif; + font-size: 14px; + line-height: 1.5; + margin: 0; + padding: 0; +} + +.container { + margin: 0 auto; + max-width: 768px; + padding: 20px 5%; +} + +section { + background-color: #171717; +} + +h1, h2 { + line-height: 1; + text-transform: uppercase; +} + +h2 { + margin-top: 40px; +} + +h2:first-of-type { + margin-top: 20px; +} + +.logo { + display: block; +} + +img { + height: auto; + max-width: 100%; +} + +.logo img { + width: 500px; +} + +@media all and (max-width: 768px) { + .logo img { + width: 450px; + } +} + +@media all and (max-width: 479px) { + .logo img { + width: 350px; + } +} + +.icon.heart { + color: lightcoral; +} + +a { + color: aquamarine; + font-weight: bold; +} + +a:hover, a:active { + color: mediumaquamarine; +} + +a code { + color: black; +} + +code { + background-color: aquamarine; + color: black; + font-family: monospace; + padding: 1px; + user-select: all; +} + +code.image { + background-color: lightyellow; +} \ No newline at end of file diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..b295042 --- /dev/null +++ b/sw.js @@ -0,0 +1,82 @@ +const cacheName = "cache1"; // Change value to force update + +self.addEventListener("install", event => { + // Kick out the old service worker + self.skipWaiting(); + + event.waitUntil( + caches.open(cacheName).then(cache => { + return cache.addAll([ + "/", + "android-chrome-36x36.png", // Favicon, Android Chrome M39+ with 0.75 screen density + "android-chrome-48x48.png", // Favicon, Android Chrome M39+ with 1.0 screen density + "android-chrome-72x72.png", // Favicon, Android Chrome M39+ with 1.5 screen density + "android-chrome-96x96.png", // Favicon, Android Chrome M39+ with 2.0 screen density + "android-chrome-144x144.png", // Favicon, Android Chrome M39+ with 3.0 screen density + "android-chrome-192x192.png", // Favicon, Android Chrome M39+ with 4.0 screen density + "android-chrome-256x256.png", // Favicon, Android Chrome M47+ Splash screen with 1.5 screen density + "android-chrome-384x384.png", // Favicon, Android Chrome M47+ Splash screen with 3.0 screen density + "android-chrome-512x512.png", // Favicon, Android Chrome M47+ Splash screen with 4.0 screen density + "apple-touch-icon.png", // Favicon, Apple default + "apple-touch-icon-57x57.png", // Apple iPhone, Non-retina with iOS6 or prior + "apple-touch-icon-60x60.png", // Apple iPhone, Non-retina with iOS7 + "apple-touch-icon-72x72.png", // Apple iPad, Non-retina with iOS6 or prior + "apple-touch-icon-76x76.png", // Apple iPad, Non-retina with iOS7 + "apple-touch-icon-114x114.png", // Apple iPhone, Retina with iOS6 or prior + "apple-touch-icon-120x120.png", // Apple iPhone, Retina with iOS7 + "apple-touch-icon-144x144.png", // Apple iPad, Retina with iOS6 or prior + "apple-touch-icon-152x152.png", // Apple iPad, Retina with iOS7 + "apple-touch-icon-180x180.png", // Apple iPhone 6 Plus with iOS8 + "browserconfig.xml", // IE11 icon configuration file + "favicon.ico", // Favicon, IE and fallback for other browsers + "favicon-16x16.png", // Favicon, default + "favicon-32x32.png", // Favicon, Safari on Mac OS + "index.html", // Main HTML file + "logo.png", // Logo + "main.js", // Main Javascript file + "manifest.json", // Manifest file + "maskable_icon.png", // Favicon, maskable https://web.dev/maskable-icon + "mstile-70x70.png", // Favicon, Windows 8 / IE11 + "mstile-144x144.png", // Favicon, Windows 8 / IE10 + "mstile-150x150.png", // Favicon, Windows 8 / IE11 + "mstile-310x150.png", // Favicon, Windows 8 / IE11 + "mstile-310x310.png", // Favicon, Windows 8 / IE11 + "safari-pinned-tab.svg", // Favicon, Safari pinned tab + "share.jpg", // Social media sharing + "style.css", // Main CSS file + ]); + }) + ); +}); + +self.addEventListener("activate", event => { + // Delete any non-current cache + event.waitUntil( + caches.keys().then(keys => { + Promise.all( + keys.map(key => { + if (![cacheName].includes(key)) { + return caches.delete(key); + } + }) + ) + }) + ); +}); + +// Offline-first, cache-first strategy +// Kick off two asynchronous requests, one to the cache and one to the network +// If there's a cached version available, use it, but fetch an update for next time. +// Gets data on screen as quickly as possible, then updates once the network has returned the latest data. +self.addEventListener("fetch", event => { + event.respondWith( + caches.open(cacheName).then(cache => { + return cache.match(event.request).then(response => { + return response || fetch(event.request).then(networkResponse => { + cache.put(event.request, networkResponse.clone()); + return networkResponse; + }); + }) + }) + ); +}); \ No newline at end of file