├── .nvmrc ├── src ├── assets │ ├── CNAME │ ├── favicon.ico │ ├── images │ │ ├── pokedex.png │ │ ├── web-flap.png │ │ ├── icon-144x144.png │ │ ├── icon-180x180.png │ │ ├── icon-192x192.png │ │ ├── icon-228x228.png │ │ ├── flipboard.svg │ │ ├── air-horner.svg │ │ ├── inbox-attack.svg │ │ ├── snapdrop.svg │ │ ├── google-io.svg │ │ ├── qrcode.svg │ │ ├── voice-memos.svg │ │ ├── datememe.svg │ │ ├── jalantikus.svg │ │ ├── geo-news.svg │ │ ├── oumy.svg │ │ ├── meatscope.svg │ │ ├── financial-times.svg │ │ ├── poly-mail.svg │ │ ├── dev-opera.svg │ │ ├── reacthn.svg │ │ ├── riorun.svg │ │ ├── prog-beer.svg │ │ ├── selio.svg │ │ ├── soundslice.svg │ │ ├── telegram.svg │ │ ├── washington-post.svg │ │ ├── smaller-pictures.svg │ │ ├── spaces.svg │ │ ├── suggest.svg │ │ ├── wave-pd1.svg │ │ ├── wiki-offline.svg │ │ ├── billings-gazette.svg │ │ ├── 2048-puzzle.svg │ │ ├── expense-manager.svg │ │ ├── emojoy.svg │ │ ├── currency-x.svg │ │ ├── aliexpress.svg │ │ ├── chrome-status.svg │ │ ├── webnfc.svg │ │ ├── get-kana.svg │ │ ├── flipkart.svg │ │ ├── babe.svg │ │ ├── icon.svg │ │ ├── guitar-tuner.svg │ │ ├── session.svg │ │ └── svgomg.svg │ ├── fonts │ │ └── permanent-marker.woff │ ├── script.js │ ├── webmanifest.json │ └── service-worker.js ├── styles │ ├── defaults.scss │ ├── fonts.scss │ ├── screen.scss │ ├── page.scss │ ├── navigation.scss │ ├── reset.scss │ └── list.scss └── index.html ├── .gitignore ├── .travis-github-deploy-key.enc ├── .editorconfig ├── package.json ├── .travis.yml ├── README.md └── gulpfile.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /src/assets/CNAME: -------------------------------------------------------------------------------- 1 | pwa.rocks 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dest 2 | node_modules 3 | -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/favicon.ico -------------------------------------------------------------------------------- /.travis-github-deploy-key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/.travis-github-deploy-key.enc -------------------------------------------------------------------------------- /src/assets/images/pokedex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/pokedex.png -------------------------------------------------------------------------------- /src/assets/images/web-flap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/web-flap.png -------------------------------------------------------------------------------- /src/assets/images/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/icon-144x144.png -------------------------------------------------------------------------------- /src/assets/images/icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/icon-180x180.png -------------------------------------------------------------------------------- /src/assets/images/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/icon-192x192.png -------------------------------------------------------------------------------- /src/assets/images/icon-228x228.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/images/icon-228x228.png -------------------------------------------------------------------------------- /src/assets/fonts/permanent-marker.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YerkoPalma/pwa-list/master/src/assets/fonts/permanent-marker.woff -------------------------------------------------------------------------------- /src/assets/images/flipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/air-horner.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/inbox-attack.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/styles/defaults.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // Defaults 3 | // ------------------------------------------------------------------ 4 | 5 | $mq-breakpoints: ( 6 | palm: 480px, 7 | lap: 768px, 8 | desk: 1024px 9 | ); 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = tab 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [{package.json,.travis.yml}] 12 | indent_size = 2 13 | indent_style = space 14 | -------------------------------------------------------------------------------- /src/styles/fonts.scss: -------------------------------------------------------------------------------- 1 | // Fonts 2 | 3 | @font-face { 4 | font-family: Permanent Marker; 5 | font-style: normal; 6 | font-weight: 400; 7 | src: 8 | local('Permanent Marker'), 9 | local('PermanentMarker'), 10 | url(../fonts/permanent-marker.woff) format('woff'); 11 | } 12 | -------------------------------------------------------------------------------- /src/assets/images/snapdrop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/screen.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // Screen 3 | // ------------------------------------------------------------------ 4 | 5 | @import '../../node_modules/sass-mq/mq'; 6 | 7 | @import 'defaults'; 8 | @import 'fonts'; 9 | @import 'reset'; 10 | @import 'page'; 11 | @import 'navigation'; 12 | @import 'list'; 13 | -------------------------------------------------------------------------------- /src/assets/images/google-io.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/qrcode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var tags = document.querySelectorAll('.js-tag'); 3 | var list = document.querySelector('.js-list'); 4 | var apps = document.querySelectorAll('.js-app'); 5 | 6 | tags[0].checked = true; 7 | 8 | for (var i = 0; i < tags.length; i++) { 9 | tags[i].addEventListener('change', function() { 10 | list.dataset.filter = this.value; 11 | }); 12 | } 13 | 14 | for (var i = 0; i < apps.length; i++) { 15 | list.appendChild(apps[Math.random() * i | 0]); 16 | } 17 | }()); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "test": "gulp build", 5 | "build": "gulp build", 6 | "server": "gulp" 7 | }, 8 | "devDependencies": { 9 | "@alrra/travis-scripts": "^3.0.1", 10 | "autoprefixer": "^6.3.6", 11 | "browser-sync": "^2.13.0", 12 | "gulp": "^3.9.1", 13 | "gulp-beml": "^1.0.0", 14 | "gulp-htmlmin": "^2.0.0", 15 | "gulp-postcss": "^6.1.1", 16 | "gulp-sass": "^2.3.2", 17 | "postcss-csso": "^1.1.2", 18 | "sass-mq": "^3.2.9" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/images/voice-memos.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/datememe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/jalantikus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/geo-news.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/oumy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/styles/page.scss: -------------------------------------------------------------------------------- 1 | // Page 2 | 3 | .page { 4 | 5 | margin: auto; 6 | max-width: 1024px; 7 | 8 | background: #181818; 9 | font-family: Permanent Marker, sans-serif; 10 | 11 | // Header 12 | 13 | &__header { 14 | padding: 30px 0 38px; 15 | background: #383838; 16 | color: #FFF; 17 | text-align: center; 18 | line-height: 1; 19 | font-size: 50px; 20 | } 21 | 22 | // Footer 23 | 24 | &__footer { 25 | padding: 30px 15px 32px; 26 | background: #383838; 27 | color: #FFF; 28 | text-align: center; 29 | line-height: 1; 30 | font-size: 25px; 31 | } 32 | 33 | // Link 34 | 35 | &__link { 36 | color: #5AC1F2; 37 | text-decoration: none; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/assets/images/meatscope.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/financial-times.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/navigation.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // Navigation 3 | // ------------------------------------------------------------------ 4 | 5 | .navigation { 6 | 7 | padding: 12px 0; 8 | max-width: 100%; 9 | display: flex; 10 | flex-wrap: wrap; 11 | justify-content: center; 12 | background: #222; 13 | 14 | // Elements 15 | &__tag { 16 | position: absolute; 17 | clip: rect(0 0 0 0); 18 | } 19 | &__label { 20 | margin: 4px; 21 | padding: 6px 10px 7px; 22 | border-radius: 20px; 23 | background: #383838; 24 | color: #FFF; 25 | font: 14px/1 Helvetica, sans-serif; 26 | } 27 | 28 | // Action 29 | &__tag:focus + &__label { 30 | box-shadow: 0 0 0 4px #5AC1F2; 31 | } 32 | &__tag:checked + &__label { 33 | background: #FFF; 34 | color: #000; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/assets/images/poly-mail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/dev-opera.svg: -------------------------------------------------------------------------------- 1 | Opera Logo -------------------------------------------------------------------------------- /src/assets/images/reacthn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/webmanifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "PWA List", 3 | "name": "Progressive Web Apps", 4 | "display": "standalone", 5 | "icons": [ 6 | { 7 | "src": "favicon.ico", 8 | "sizes": "32x32 16x16", 9 | "type": "image/vnd.microsoft.icon" 10 | }, 11 | { 12 | "src": "images/icon-144x144.png", 13 | "sizes": "144x144", 14 | "type": "image/png" 15 | }, 16 | { 17 | "src": "images/icon-180x180.png", 18 | "sizes": "180x180", 19 | "type": "image/png" 20 | }, 21 | { 22 | "src": "images/icon-192x192.png", 23 | "sizes": "192x192", 24 | "type": "image/png" 25 | }, 26 | { 27 | "src": "images/icon-228x228.png", 28 | "sizes": "228x228", 29 | "type": "image/png" 30 | }, 31 | { 32 | "src": "images/icon.svg", 33 | "sizes": "any", 34 | "type": "image/svg" 35 | } 36 | ], 37 | "start_url": ".", 38 | "theme_color": "#5ac1f2", 39 | "background_color": "#383838" 40 | } 41 | -------------------------------------------------------------------------------- /src/assets/images/riorun.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/prog-beer.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/selio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/soundslice.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/telegram.svg: -------------------------------------------------------------------------------- 1 | telegram -------------------------------------------------------------------------------- /src/assets/images/washington-post.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/smaller-pictures.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/spaces.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | secure: LKh9LZrsrUaZ42Rp5A+PqL7xYvQqDb1Ikg7Xoii9Zk5FYCDTZLFXyoRd5R1eHo+Kska1nXLFyxMwPxyrOaZWsXkEor0uhki82RdcmMZp/JhgGY5f2y9/Qk5ldKMrcr7LhNZhMkS4FYnYcHKcKsKPbz3SknL5UITcTy1fImm8gwxRf0mGKvqYYqVou82eMAqf6p/IRzmpbwshLLgHlbT5yKdLogfT6xSyjypjZrZ2d2ZVxo+xtiMOOJGRWn6ojAyvToMaAUqoyZ3ZRB5L75dzDADyYGV/Yy6M1S2TS5XcJzPPcFVI1IFRa3jmJlUpd33LxpuSm9hJKkY2WrYsd5c4WVqZm/cenGiktRozu31mJUDM05L/rXQAp3ayZQiImzmgUImERDX4qYd4B1ZT3OjSZaKV9F/JkPfnohMU7ilbTNL62/RQKyY2+pQbVWXSApPadTReoQilVjOrQdJxVMztVjYdTwwaKzMG18ahfmT6fDv00lTo++JhszGkNeCr7ukF0exsj5/m/PijnZaD0Xa4L+R3GcPnHEFSXIdKgvci7c/25erlExQbD1LwSfrcjA0rvY5asSAMlEuLAY6vnL17RcgyIZKQVWOhYagPhXFNZH8h05V2rRI3PinjVjYFKx+TRbARaC1TXSSAoi96hdlnI3FRrmXzYISy3iqgiG5LzCo= 4 | after_success: 5 | - $(npm bin)/set-up-ssh --key "${encrypted_f8a826b60c9b_key}" 6 | --iv "${encrypted_f8a826b60c9b_iv}" 7 | --path-encrypted-key .travis-github-deploy-key.enc 8 | - $(npm bin)/update-branch --commands 'npm run build && touch dest/.nojekyll' 9 | --commit-message "Update gh-pages @ ${TRAVIS_COMMIT}" 10 | --directory 'dest' 11 | --distribution-branch 'gh-pages' 12 | --source-branch 'master' 13 | language: node_js 14 | git: 15 | depth: 1 16 | -------------------------------------------------------------------------------- /src/assets/images/suggest.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/wave-pd1.svg: -------------------------------------------------------------------------------- 1 | wavepad 2 | -------------------------------------------------------------------------------- /src/assets/images/wiki-offline.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/billings-gazette.svg: -------------------------------------------------------------------------------- 1 | bg-logo -------------------------------------------------------------------------------- /src/styles/reset.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // Reset 3 | // ------------------------------------------------------------------ 4 | 5 | // Sizing 6 | 7 | *, *:before, *:after { 8 | box-sizing: border-box; 9 | } 10 | 11 | // Reset 12 | 13 | html, body, div, span, applet, object, iframe, 14 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 15 | a, abbr, acronym, address, big, cite, code, 16 | del, dfn, em, img, ins, kbd, q, s, samp, 17 | small, strike, strong, sub, sup, tt, var, 18 | b, u, i, center, 19 | dl, dt, dd, ol, ul, li, 20 | fieldset, form, label, legend, 21 | table, caption, tbody, tfoot, thead, tr, th, td, 22 | article, aside, canvas, details, embed, 23 | figure, figcaption, footer, header, hgroup, 24 | menu, nav, output, ruby, section, summary, 25 | time, mark, audio, video { 26 | margin: 0; 27 | padding: 0; 28 | border: 0; 29 | font-size: 100%; 30 | font: inherit; 31 | vertical-align: baseline; 32 | } 33 | article, aside, details, figcaption, figure, 34 | footer, header, hgroup, main, menu, nav, section, summary { 35 | display: block; 36 | } 37 | html { 38 | -webkit-text-size-adjust: 100%; 39 | -ms-text-size-adjust: 100%; 40 | } 41 | body { 42 | line-height: 1; 43 | } 44 | ol, ul { 45 | list-style: none; 46 | } 47 | blockquote, q { 48 | quotes: none; 49 | } 50 | blockquote::before, 51 | blockquote::after, 52 | q::before, q::after { 53 | content: ''; 54 | content: none; 55 | } 56 | table { 57 | border-collapse: collapse; 58 | border-spacing: 0; 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # List of Progressive Web Apps [![Build status](https://travis-ci.org/operasoftware/pwa-list.svg)](https://travis-ci.org/operasoftware/pwa-list) 2 | 3 | What is a progressive web app? See the “[Progressive Web Apps](https://developer.chrome.com/devsummit/sessions/progressiveapps)” talk by [Alex Russell](https://github.com/slightlyoff) and [Andreas Bovens](https://github.com/andreasbovens). 4 | 5 | ## Development 6 | 7 | - Clone repository locally `git clone git@github.com:operasoftware/pwa-list.git` 8 | - Install all dependencies `cd pwa-list && npm install` 9 | - Start local server `npm run server` 10 | 11 | ## Contributing 12 | 13 | We’re happy to feature other nice-looking progressive web apps in the list. They should: 14 | 15 | - Be served over HTTPS 16 | - Have a manifest with a `short_name` and `name`, `start_url`, and a PNG icon of at least 144×144 pixels 17 | - Have a service worker (making sure that the `start_url` functions offline) 18 | 19 | This combination of features will trigger the web app install banner in [Opera](https://dev.opera.com/blog/web-app-install-banners/) and [Chrome](https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android) (to trigger it on the first visit, we recommend enabling _Bypass user engagement checks_ option in `chrome:flags` or `opera:flags`), unless the site is intercepting `onbeforeinstallprompt`. In the latter case, the banner is triggered at a custom point in time, defined by the site’s own logic. 20 | 21 | We welcome all submissions, but actual inclusion in the list is up to the discretion of the Opera Dev Relations team. If we find your web app not fitting (e.g. for content or other reasons), we won’t feature it. 22 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const beml = require('gulp-beml'); 3 | const csso = require('postcss-csso'); 4 | const gulp = require('gulp'); 5 | const htmlmin = require('gulp-htmlmin'); 6 | const postcss = require('gulp-postcss'); 7 | const sass = require('gulp-sass'); 8 | const sync = require('browser-sync').create(); 9 | 10 | gulp.task('styles', () => { 11 | return gulp.src('src/styles/screen.scss') 12 | .pipe(sass().on('error', sass.logError)) 13 | .pipe(postcss([ 14 | autoprefixer, 15 | csso 16 | ])) 17 | .pipe(gulp.dest('dest')) 18 | .pipe(sync.stream()); 19 | }); 20 | 21 | gulp.task('html', () => { 22 | return gulp.src('src/index.html') 23 | .pipe(beml({ 24 | elemPrefix: '__', 25 | modPrefix: '--' })) 26 | .pipe(htmlmin({ 27 | removeComments: true, 28 | collapseWhitespace: true 29 | })) 30 | .pipe(gulp.dest('dest')) 31 | .pipe(sync.stream()); 32 | }); 33 | 34 | gulp.task('copy', () => { 35 | return gulp.src('src/assets/**', { dot: true }) 36 | .pipe(gulp.dest('dest')) 37 | .pipe(sync.stream({ once: true })); 38 | }); 39 | 40 | gulp.task('server', () => { 41 | sync.init({ 42 | notify: false, 43 | server: { 44 | baseDir: 'dest' 45 | }, 46 | rewriteRules: [{ 47 | match: /location\.href = 'https:\/\/pwa\.rocks\/';/, 48 | replace: '// Redirect removed during development.' 49 | }] 50 | }); 51 | }); 52 | 53 | gulp.task('watch', () => { 54 | gulp.watch('src/styles/*.scss', ['styles']); 55 | gulp.watch('src/index.html', ['html']); 56 | gulp.watch('src/assets/**', ['copy']); 57 | }); 58 | 59 | gulp.task('build', [ 60 | 'styles', 61 | 'html', 62 | 'copy' 63 | ]); 64 | 65 | gulp.task('default', [ 66 | 'build', 67 | 'server', 68 | 'watch' 69 | ]); 70 | -------------------------------------------------------------------------------- /src/assets/images/2048-puzzle.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/expense-manager.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/emojoy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/currency-x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/aliexpress.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/chrome-status.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/webnfc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/get-kana.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/flipkart.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/service-worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PREFIX = 'devopera'; 4 | const HASH = '9f9099b9'; // TODO: calculate when running `gulp`. 5 | const OFFLINE_CACHE = `${PREFIX}-${HASH}`; 6 | const OFFLINE_URL = '/'; 7 | 8 | self.addEventListener('install', function(event) { 9 | event.waitUntil( 10 | caches.open(OFFLINE_CACHE).then(function(cache) { 11 | return cache.addAll([ 12 | OFFLINE_URL, 13 | 14 | '/styles/screen.css', 15 | '/fonts/permanent-marker.woff', 16 | '/favicon.ico', 17 | '/images/icon-228x228.png', 18 | 19 | '/images/2048-puzzle.svg', 20 | '/images/air-horner.svg', 21 | '/images/aliexpress.svg', 22 | '/images/babe.svg', 23 | '/images/billings-gazette.svg', 24 | '/images/currency-x.svg', 25 | '/images/chrome-status.svg', 26 | '/images/datememe.svg', 27 | '/images/dev-opera.svg', 28 | '/images/emojoy.svg', 29 | '/images/expense-manager.svg', 30 | '/images/financial-times.svg', 31 | '/images/firefox.svg', 32 | '/images/flipboard.svg', 33 | '/images/flipkart.svg', 34 | '/images/geo-news.svg', 35 | '/images/get-kana.svg', 36 | '/images/google-io.svg', 37 | '/images/guitar-tuner.svg', 38 | '/images/inbox-attack.svg', 39 | '/images/jalantikus.svg', 40 | '/images/meatscope.svg', 41 | '/images/oumy.svg', 42 | '/images/pokedex.png', 43 | '/images/poly-mail.svg', 44 | '/images/prog-beer.svg', 45 | '/images/qrcode.svg', 46 | '/images/reacthn.svg', 47 | '/images/riorun.svg', 48 | '/images/selio.svg', 49 | '/images/session.svg', 50 | '/images/smaller-pictures.svg', 51 | '/images/snapdrop.svg', 52 | '/images/soundslice.svg', 53 | '/images/spaces.svg', 54 | '/images/suggest.svg', 55 | '/images/svgomg.svg', 56 | '/images/telegram.svg', 57 | '/images/voice-memos.svg', 58 | '/images/financial-times.svg', 59 | '/images/washington-post.svg', 60 | '/images/wave-pd1.svg', 61 | '/images/web-flap.png', 62 | '/images/webnfc.svg', 63 | '/images/billings-gazette.svg', 64 | '/images/wiki-offline.svg' 65 | 66 | ]); 67 | }) 68 | ); 69 | }); 70 | 71 | self.addEventListener('activate', function(event) { 72 | // Delete old asset caches. 73 | event.waitUntil( 74 | caches.keys().then(function(keys) { 75 | return Promise.all( 76 | keys.map(function(key) { 77 | if ( 78 | key != OFFLINE_CACHE && 79 | key.startsWith(`${PREFIX}-`) 80 | ) { 81 | return caches.delete(key); 82 | } 83 | }) 84 | ); 85 | }) 86 | ); 87 | }); 88 | 89 | self.addEventListener('fetch', function(event) { 90 | if (event.request.mode == 'navigate') { 91 | console.log('Handling fetch event for', event.request.url); 92 | console.log(event.request); 93 | event.respondWith( 94 | fetch(event.request).catch(function(exception) { 95 | // The `catch` is only triggered if `fetch()` throws an exception, 96 | // which most likely happens due to the server being unreachable. 97 | console.error( 98 | 'Fetch failed; returning offline page instead.', 99 | exception 100 | ); 101 | return caches.open(OFFLINE_CACHE).then(function(cache) { 102 | return cache.match(OFFLINE_URL); 103 | }); 104 | }) 105 | ); 106 | } else { 107 | // It’s not a request for an HTML document, but rather for a CSS or SVG 108 | // file or whatever… 109 | event.respondWith( 110 | caches.match(event.request).then(function(response) { 111 | return response || fetch(event.request); 112 | }) 113 | ); 114 | } 115 | 116 | }); 117 | -------------------------------------------------------------------------------- /src/assets/images/babe.svg: -------------------------------------------------------------------------------- 1 | babe -------------------------------------------------------------------------------- /src/assets/images/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/images/guitar-tuner.svg: -------------------------------------------------------------------------------- 1 | tuner -------------------------------------------------------------------------------- /src/assets/images/session.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/list.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // List 3 | // ------------------------------------------------------------------ 4 | 5 | .list { 6 | 7 | display: flex; 8 | flex-wrap: wrap; 9 | 10 | // Filter 11 | 12 | &__app { 13 | display: none; 14 | } 15 | 16 | } 17 | 18 | [data-filter=all] [data-tags], 19 | [data-filter=business] [data-tags~=business], 20 | [data-filter=demo] [data-tags~=demo], 21 | [data-filter=event] [data-tags~=event], 22 | [data-filter=game] [data-tags~=game], 23 | [data-filter=news] [data-tags~=news], 24 | [data-filter=other] [data-tags~=other], 25 | [data-filter=reference] [data-tags~=reference], 26 | [data-filter=shopping] [data-tags~=shopping], 27 | [data-filter=social] [data-tags~=social], 28 | [data-filter=tool] [data-tags~=tool] { 29 | display: block; 30 | } 31 | 32 | // Title 33 | 34 | .list__title { 35 | position: absolute; 36 | right: 0; 37 | bottom: 0; 38 | left: 0; 39 | overflow: hidden; 40 | height: 0; 41 | background: rgba(#000, 0.4); 42 | color: #FFF; 43 | vertical-align: middle; 44 | text-align: center; 45 | line-height: 37px; 46 | font-size: 25px; 47 | transition: height 0.2s linear; 48 | } 49 | 50 | // App 51 | 52 | .list__app { 53 | 54 | position: relative; 55 | width: 100%; 56 | 57 | @include mq($from: palm) { 58 | width: 50%; 59 | } 60 | @include mq($from: lap) { 61 | width: 33.33%; 62 | } 63 | 64 | } 65 | 66 | // Link 67 | 68 | .list__link { 69 | 70 | display: block; 71 | padding-bottom: 62.5%; 72 | 73 | &:focus { 74 | outline: none; 75 | } 76 | 77 | } 78 | 79 | // Apps 80 | 81 | .list__link { 82 | 83 | &--2048-puzzle { 84 | background: #EDC500 url(../images/2048-puzzle.svg) 50% 50% / 65% auto no-repeat; 85 | } 86 | &--air-horner { 87 | background: #1194F6 url(../images/air-horner.svg) 50% 50% / 46% auto no-repeat; 88 | } 89 | &--aliexpress { 90 | background: #F73F16 url(../images/aliexpress.svg) 50% 55% / 50% auto no-repeat; 91 | } 92 | &--babe { 93 | background: #F90 url(../images/babe.svg) 50% 50% / auto 80% no-repeat; 94 | } 95 | &--billings-gazette { 96 | background: #FFD200 url(../images/billings-gazette.svg) 50% 50% / auto 75% no-repeat; 97 | } 98 | &--currency-x { 99 | background: #3D82F7 url(../images/currency-x.svg) 100% 100% / auto 82% no-repeat; 100 | } 101 | &--chrome-status { 102 | background: #FFF url(../images/chrome-status.svg) 50% 50% / auto 70% no-repeat; 103 | } 104 | &--datememe { 105 | background: #0275D8 url(../images/datememe.svg) 50% 50% / 50% auto no-repeat; 106 | } 107 | &--dev-opera { 108 | background: #FFF url(../images/dev-opera.svg) 50% 50% / 45% auto no-repeat; 109 | } 110 | &--emojoy { 111 | background: #E1BEE7 url(../images/emojoy.svg) 50% 50% / 45% auto no-repeat; 112 | } 113 | &--expense-manager { 114 | background: #33383A url(../images/expense-manager.svg) 50% 45% / 55% auto no-repeat; 115 | } 116 | &--financial-times { 117 | background: #fff1e0 url(../images/financial-times.svg) 50% 50% / 50% auto no-repeat; 118 | } 119 | &--firefox { 120 | background: #005DA5 url(../images/firefox.svg) 50% 60% / auto 75% no-repeat; 121 | } 122 | &--flipboard { 123 | background: #CD0000 url(../images/flipboard.svg) 50% 50% / 38% auto no-repeat; 124 | } 125 | &--flipkart { 126 | background: #007AD8 url(../images/flipkart.svg) 50% 50% / 38% auto no-repeat; 127 | } 128 | &--geo-news { 129 | background: #093777 url(../images/geo-news.svg) 50% 50% / auto 60% no-repeat; 130 | } 131 | &--get-kana { 132 | background: #7C7171 url(../images/get-kana.svg) 50% 50% / 50% auto no-repeat; 133 | } 134 | &--google-io { 135 | background: #77909D url(../images/google-io.svg) 50% 50% / 50% auto no-repeat; 136 | } 137 | &--guitar-tuner { 138 | background: #36474F url(../images/guitar-tuner.svg) 50% 50% / 46% auto no-repeat; 139 | } 140 | &--jalantikus { 141 | background: #0E161C url(../images/jalantikus.svg) 50% 50% / auto 65% no-repeat; 142 | } 143 | &--inbox-attack { 144 | background: #CBDEA8 url(../images/inbox-attack.svg) 50% 50% / 55% auto no-repeat; 145 | } 146 | &--meatscope { 147 | background: #03A9F4 url(../images/meatscope.svg) 50% 50% / 46% auto no-repeat; 148 | } 149 | &--oumy { 150 | background: #F3FAFD url(../images/oumy.svg) 50% 50% / 45% auto no-repeat; 151 | } 152 | &--pokedex { 153 | image-rendering: pixelated; 154 | background: 155 | url(../images/pokedex.png) 50% 50% / 50% auto no-repeat, 156 | linear-gradient(to right, #78C850 50%, #A040A0 50%) 157 | #78C850; 158 | } 159 | &--poly-mail { 160 | background: #E8372D url(../images/poly-mail.svg) 50% 50% / 50% auto no-repeat; 161 | } 162 | &--prog-beer { 163 | background: #FFE400 url(../images/prog-beer.svg) 50% 50% / auto 70% no-repeat; 164 | } 165 | &--reacthn { 166 | background: #00D8FF url(../images/reacthn.svg) 50% 50% / 42% auto no-repeat; 167 | } 168 | &--riorun { 169 | background: #1C92C8 url(../images/riorun.svg) 50% 50% / 80% auto no-repeat; 170 | } 171 | &--qrcode { 172 | background: #5F7D8C url(../images/qrcode.svg) 50% 50% / 40% auto no-repeat; 173 | } 174 | &--smaller-pictures { 175 | background: #212121 url(../images/smaller-pictures.svg) 50% 50% / 46% auto no-repeat; 176 | } 177 | &--snapdrop { 178 | background: #FAFAFA url(../images/snapdrop.svg) 50% 50% / 46% auto no-repeat; 179 | } 180 | &--soundslice { 181 | background: #60506F url(../images/soundslice.svg) 50% 50% / 45% auto no-repeat; 182 | } 183 | &--spaces { 184 | background: #ECEFF1 url(../images/spaces.svg) 50% 50% / 45% auto no-repeat; 185 | } 186 | &--svgomg { 187 | background: 188 | url(../images/svgomg.svg) 50% 50% / 50% auto no-repeat, 189 | linear-gradient(45deg, #E6E6E6 25%, transparent 25%, transparent 75%, #E6E6E6 75%, #E6E6E6) 0 0 / 20px 20px, 190 | linear-gradient(45deg, #E6E6E6 25%, transparent 25%, transparent 75%, #E6E6E6 75%, #E6E6E6) 10px 10px / 20px 20px, 191 | #F2F2F2; 192 | } 193 | &--telegram { 194 | background: #E7EBF0 url(../images/telegram.svg) 50% 50% / 46% auto no-repeat; 195 | } 196 | &--selio { 197 | background: 198 | url(../images/selio.svg) 50% 50% / auto 75% no-repeat, 199 | linear-gradient(to bottom, #DF1C1E, #A00F1D) 200 | #A00F1D; 201 | } 202 | &--session { 203 | position: relative; 204 | background: 205 | url(../images/session.svg) 52% 50% / 70% auto no-repeat, 206 | linear-gradient(#EB2, #DA1) 207 | #DDAF49; 208 | &::before { 209 | position: absolute; 210 | top: 10px; 211 | right: 10px; 212 | bottom: 10px; 213 | left: 10px; 214 | border: 1px dashed #C93; 215 | box-shadow: 216 | 10px 10px 0 #E5B219, 217 | -10px 10px 0 #E5B219, 218 | -10px -10px 0 #E5B219, 219 | 10px -10px 0 #E5B219; 220 | content: ''; 221 | } 222 | } 223 | &--voice-memos { 224 | background: #673AB7 url(../images/voice-memos.svg) 50% 50% / auto 80% no-repeat; 225 | } 226 | &--financial-times { 227 | background: #fff1e0 url(../images/financial-times.svg) 50% 50% / 50% auto no-repeat; 228 | } 229 | &--washington-post { 230 | background: #000 url(../images/washington-post.svg) 50% 50% / 50% auto no-repeat; 231 | } 232 | &--wave-pd1 { 233 | background: #191622 url(../images/wave-pd1.svg) 50% 50% / auto 70% no-repeat; 234 | } 235 | &--wiki-offline { 236 | background: 237 | url(../images/wiki-offline.svg) 50% 50% / 55% auto no-repeat, 238 | linear-gradient(to bottom, #FEFFFC, #DFE1DE) 239 | #EEF0ED; 240 | } 241 | &--web-flap { 242 | image-rendering: pixelated; 243 | background: 244 | url(../images/web-flap.png) 50% 50% / 50% auto no-repeat, 245 | #6CC851; 246 | } 247 | &--webnfc { 248 | background: #FFC107 url(../images/webnfc.svg) 50% 50% / auto 75% no-repeat; 249 | } 250 | 251 | } 252 | 253 | // Action 254 | 255 | .list { 256 | 257 | &__link:hover &__title, 258 | &__link:focus &__title { 259 | height: 40px; 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A selection of Progressive Web Apps 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |

Progressive Web Apps

18 |
19 | 43 | 260 | 263 | 272 | 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /src/assets/images/svgomg.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------