├── step1
├── favicon.ico
├── images
│ ├── fog.png
│ ├── rain.png
│ ├── snow.png
│ ├── wind.png
│ ├── clear.png
│ ├── cloudy.png
│ ├── sleet.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── thunderstorm.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── index.html
├── scripts
│ ├── app.js
│ └── push-client.js
└── styles
│ └── inline.css
├── step2
├── favicon.ico
├── images
│ ├── fog.png
│ ├── rain.png
│ ├── snow.png
│ ├── wind.png
│ ├── clear.png
│ ├── cloudy.png
│ ├── sleet.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── thunderstorm.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── index.html
├── scripts
│ ├── app.js
│ └── push-client.js
└── styles
│ └── inline.css
├── step3
├── favicon.ico
├── images
│ ├── fog.png
│ ├── rain.png
│ ├── snow.png
│ ├── wind.png
│ ├── clear.png
│ ├── cloudy.png
│ ├── sleet.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── thunderstorm.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── index.html
├── service-worker.js
├── scripts
│ ├── app.js
│ └── push-client.js
└── styles
│ └── inline.css
├── step4
├── favicon.ico
├── images
│ ├── fog.png
│ ├── rain.png
│ ├── snow.png
│ ├── wind.png
│ ├── clear.png
│ ├── cloudy.png
│ ├── sleet.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── thunderstorm.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── index.html
├── service-worker.js
├── scripts
│ ├── app.js
│ └── push-client.js
└── styles
│ └── inline.css
├── step5
├── favicon.ico
├── images
│ ├── fog.png
│ ├── rain.png
│ ├── snow.png
│ ├── wind.png
│ ├── clear.png
│ ├── cloudy.png
│ ├── sleet.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── thunderstorm.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── manifest.json
├── index.html
├── service-worker.js
├── scripts
│ ├── app.js
│ └── push-client.js
└── styles
│ └── inline.css
├── README.md
├── step6-complete
├── favicon.ico
├── images
│ ├── clear.png
│ ├── fog.png
│ ├── rain.png
│ ├── sleet.png
│ ├── snow.png
│ ├── wind.png
│ ├── cloudy.png
│ ├── thunderstorm.png
│ ├── cloudy_s_sunny.png
│ ├── partly-cloudy.png
│ ├── icons
│ │ ├── icon-32x32.png
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ └── icon-256x256.png
│ ├── scattered-showers.png
│ ├── cloudy-scattered-showers.png
│ ├── ic_notifications_black_24px.svg
│ └── ic_notifications_white_24px.svg
├── manifest.json
├── index.html
├── service-worker.js
├── scripts
│ └── app.js
└── styles
│ └── inline.css
├── package.json
├── .gitignore
└── server.js
/step1/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/favicon.ico
--------------------------------------------------------------------------------
/step2/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/favicon.ico
--------------------------------------------------------------------------------
/step3/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/favicon.ico
--------------------------------------------------------------------------------
/step4/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/favicon.ico
--------------------------------------------------------------------------------
/step5/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/favicon.ico
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mobile Web Summit Workshop
2 |
3 | Instructions for the workshop - https://goo.gl/hlMfS2
4 |
--------------------------------------------------------------------------------
/step1/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/fog.png
--------------------------------------------------------------------------------
/step1/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/rain.png
--------------------------------------------------------------------------------
/step1/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/snow.png
--------------------------------------------------------------------------------
/step1/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/wind.png
--------------------------------------------------------------------------------
/step2/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/fog.png
--------------------------------------------------------------------------------
/step2/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/rain.png
--------------------------------------------------------------------------------
/step2/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/snow.png
--------------------------------------------------------------------------------
/step2/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/wind.png
--------------------------------------------------------------------------------
/step3/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/fog.png
--------------------------------------------------------------------------------
/step3/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/rain.png
--------------------------------------------------------------------------------
/step3/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/snow.png
--------------------------------------------------------------------------------
/step3/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/wind.png
--------------------------------------------------------------------------------
/step4/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/fog.png
--------------------------------------------------------------------------------
/step4/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/rain.png
--------------------------------------------------------------------------------
/step4/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/snow.png
--------------------------------------------------------------------------------
/step4/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/wind.png
--------------------------------------------------------------------------------
/step5/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/fog.png
--------------------------------------------------------------------------------
/step5/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/rain.png
--------------------------------------------------------------------------------
/step5/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/snow.png
--------------------------------------------------------------------------------
/step5/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/wind.png
--------------------------------------------------------------------------------
/step1/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/clear.png
--------------------------------------------------------------------------------
/step1/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/cloudy.png
--------------------------------------------------------------------------------
/step1/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/sleet.png
--------------------------------------------------------------------------------
/step2/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/clear.png
--------------------------------------------------------------------------------
/step2/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/cloudy.png
--------------------------------------------------------------------------------
/step2/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/sleet.png
--------------------------------------------------------------------------------
/step3/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/clear.png
--------------------------------------------------------------------------------
/step3/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/cloudy.png
--------------------------------------------------------------------------------
/step3/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/sleet.png
--------------------------------------------------------------------------------
/step4/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/clear.png
--------------------------------------------------------------------------------
/step4/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/cloudy.png
--------------------------------------------------------------------------------
/step4/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/sleet.png
--------------------------------------------------------------------------------
/step5/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/clear.png
--------------------------------------------------------------------------------
/step5/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/cloudy.png
--------------------------------------------------------------------------------
/step5/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/sleet.png
--------------------------------------------------------------------------------
/step6-complete/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/favicon.ico
--------------------------------------------------------------------------------
/step1/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step1/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step1/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/thunderstorm.png
--------------------------------------------------------------------------------
/step2/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step2/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step2/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/thunderstorm.png
--------------------------------------------------------------------------------
/step3/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step3/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step3/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/thunderstorm.png
--------------------------------------------------------------------------------
/step4/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step4/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step4/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/thunderstorm.png
--------------------------------------------------------------------------------
/step5/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step5/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step5/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/thunderstorm.png
--------------------------------------------------------------------------------
/step6-complete/images/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/clear.png
--------------------------------------------------------------------------------
/step6-complete/images/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/fog.png
--------------------------------------------------------------------------------
/step6-complete/images/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/rain.png
--------------------------------------------------------------------------------
/step6-complete/images/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/sleet.png
--------------------------------------------------------------------------------
/step6-complete/images/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/snow.png
--------------------------------------------------------------------------------
/step6-complete/images/wind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/wind.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step6-complete/images/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/cloudy.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step1/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step1/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/scattered-showers.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step2/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step2/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/scattered-showers.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step3/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step3/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/scattered-showers.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step4/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step4/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/scattered-showers.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step5/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step5/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/scattered-showers.png
--------------------------------------------------------------------------------
/step6-complete/images/thunderstorm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/thunderstorm.png
--------------------------------------------------------------------------------
/step1/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step1/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step2/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step2/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step3/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step3/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step4/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step4/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step5/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step5/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step6-complete/images/cloudy_s_sunny.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/cloudy_s_sunny.png
--------------------------------------------------------------------------------
/step6-complete/images/partly-cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/partly-cloudy.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-32x32.png
--------------------------------------------------------------------------------
/step6-complete/images/scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/scattered-showers.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/step6-complete/images/icons/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/icons/icon-256x256.png
--------------------------------------------------------------------------------
/step6-complete/images/cloudy-scattered-showers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/owencm/ModernWebSummitWorkshop/HEAD/step6-complete/images/cloudy-scattered-showers.png
--------------------------------------------------------------------------------
/step1/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step1/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step2/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step2/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step3/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step3/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step4/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step4/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step5/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step5/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step6-complete/images/ic_notifications_black_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/step6-complete/images/ic_notifications_white_24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ModernWebSummitWorkshop",
3 | "version": "1.0.0",
4 | "private": "true",
5 | "description": "",
6 | "main": "server.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "MIT",
13 | "bugs": {
14 | "url": "https://github.com/owencm/ModernWebSummitWorkshop/issues"
15 | },
16 | "homepage": "https://github.com/owencm/ModernWebSummitWorkshop#readme",
17 | "dependencies": {
18 | "body-parser": "^1.14.2",
19 | "express": "^4.13.4",
20 | "sw-toolbox": "^3.1.1",
21 | "web-push": "^1.0.2"
22 | },
23 | "devDependencies": {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | .DS_STORE
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directory
30 | node_modules
31 |
32 | # Optional npm cache directory
33 | .npm
34 |
35 | # Optional REPL history
36 | .node_repl_history
37 |
--------------------------------------------------------------------------------
/step5/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Weather",
3 | "short_name": "Weather",
4 | "icons": [{
5 | "src": "images/icons/icon-128x128.png",
6 | "sizes": "128x128",
7 | "type": "image/png"
8 | }, {
9 | "src": "images/icons/icon-144x144.png",
10 | "sizes": "144x144",
11 | "type": "image/png"
12 | }, {
13 | "src": "images/icons/icon-152x152.png",
14 | "sizes": "152x152",
15 | "type": "image/png"
16 | }, {
17 | "src": "images/icons/icon-192x192.png",
18 | "sizes": "192x192",
19 | "type": "image/png"
20 | }, {
21 | "src": "images/icons/icon-256x256.png",
22 | "sizes": "256x256",
23 | "type": "image/png"
24 | }],
25 | "start_url": "index.html?homescreen=1",
26 | "display": "standalone",
27 | "background_color": "#3E4EB8",
28 | "theme_color": "#2F3BA2",
29 | "gcm_sender_id": "70689946818"
30 | }
31 |
--------------------------------------------------------------------------------
/step6-complete/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Weather",
3 | "short_name": "Weather",
4 | "icons": [{
5 | "src": "images/icons/icon-128x128.png",
6 | "sizes": "128x128",
7 | "type": "image/png"
8 | }, {
9 | "src": "images/icons/icon-144x144.png",
10 | "sizes": "144x144",
11 | "type": "image/png"
12 | }, {
13 | "src": "images/icons/icon-152x152.png",
14 | "sizes": "152x152",
15 | "type": "image/png"
16 | }, {
17 | "src": "images/icons/icon-192x192.png",
18 | "sizes": "192x192",
19 | "type": "image/png"
20 | }, {
21 | "src": "images/icons/icon-256x256.png",
22 | "sizes": "256x256",
23 | "type": "image/png"
24 | }],
25 | "start_url": "index.html?homescreen=1",
26 | "display": "standalone",
27 | "background_color": "#3E4EB8",
28 | "theme_color": "#2F3BA2",
29 | "gcm_sender_id": "70689946818"
30 | }
31 |
--------------------------------------------------------------------------------
/step1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step4/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step6-complete/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Weather PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/step5/service-worker.js:
--------------------------------------------------------------------------------
1 | importScripts('../node_modules/sw-toolbox/sw-toolbox.js');
2 | var version = '6';
3 | var dataCacheName = 'weatherData-v'+version;
4 | var cacheName = 'weatherPWA-step-celebrate-'+version;
5 | var filesToCache = [
6 | './',
7 | './index.html',
8 | './scripts/app.js',
9 | './styles/inline.css',
10 | './images/icons/icon-256x256.png'
11 | ];
12 |
13 | toolbox.options.cache.name = cacheName;
14 | toolbox.precache(filesToCache);
15 |
16 | self.addEventListener('install', function(e) {
17 | e.waitUntil(self.skipWaiting());
18 | });
19 |
20 | // activate event
21 | self.addEventListener('activate', function(e) {
22 | console.log('[ServiceWorker] Activate');
23 | e.waitUntil(
24 | caches.keys().then(function(keyList) {
25 | return Promise.all(keyList.map(function(key) {
26 | console.log('[ServiceWorker] Removing old cache', key);
27 | if ((key !== dataCacheName || key !== cacheName) && key.indexOf("$$$inactive$$$") === -1) {
28 | return caches.delete(key);
29 | }
30 | }));
31 | })
32 | );
33 | });
34 |
35 | var nosw = 0;
36 | self.addEventListener('fetch', function(e) {
37 | var url = new URL(e.request.url);
38 | if (nosw || (url.search.indexOf("nosw=1") >= 0)) {
39 | nosw = 1;
40 | return;
41 | }
42 | });
43 |
44 | toolbox.router.get('/(.*)', toolbox.cacheFirst, {
45 | cache: { name: cacheName }
46 | });
47 |
48 | // You will use this later to set up push notifications
49 | // self.addEventListener('push', function(e) {
50 | // console.log('[ServiceWorker] Received push event');
51 | // });
52 |
--------------------------------------------------------------------------------
/step4/service-worker.js:
--------------------------------------------------------------------------------
1 | importScripts('../node_modules/sw-toolbox/sw-toolbox.js');
2 | var version = '6';
3 | var dataCacheName = 'weatherData-v'+version;
4 | var cacheName = 'weatherPWA-step-celebrate-'+version;
5 | var filesToCache = [
6 | './',
7 | './index.html',
8 | './scripts/app.js',
9 | './styles/inline.css',
10 | './images/icons/icon-256x256.png'
11 | ];
12 |
13 | toolbox.options.cache.name = cacheName;
14 | toolbox.precache(filesToCache);
15 |
16 | self.addEventListener('install', function(e) {
17 | e.waitUntil(self.skipWaiting());
18 | });
19 |
20 | // activate event
21 | self.addEventListener('activate', function(e) {
22 | console.log('[ServiceWorker] Activate');
23 | e.waitUntil(
24 | caches.keys().then(function(keyList) {
25 | return Promise.all(keyList.map(function(key) {
26 | console.log('[ServiceWorker] Removing old cache', key);
27 | if ((key !== dataCacheName || key !== cacheName) && key.indexOf("$$$inactive$$$") === -1) {
28 | return caches.delete(key);
29 | }
30 | }));
31 | })
32 | );
33 | });
34 |
35 | var nosw = 0;
36 | self.addEventListener('fetch', function(e) {
37 | var url = new URL(e.request.url);
38 | if (nosw || (url.search.indexOf("nosw=1") >= 0)) {
39 | nosw = 1;
40 | return;
41 | }
42 | });
43 |
44 | toolbox.router.get('/data/(.*)', toolbox.networkFirst, {
45 | cache: { name: dataCacheName }
46 | });
47 |
48 | toolbox.router.default = toolbox.cacheFirst;
49 |
50 | // You will use this later to set up push notifications
51 | // self.addEventListener('push', function(e) {
52 | // console.log('[ServiceWorker] Received push event');
53 | // });
54 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var bodyParser = require('body-parser');
4 | var jsonParser = bodyParser.json();
5 | var PORT = process.env.PORT || 8000;
6 | var webPush = require('web-push');
7 |
8 | // The GCM API key is AIzaSyDNlm9R_w_0FDGjSM1fzyx5I5JnJBXACqU
9 | webPush.setGCMAPIKey('AIzaSyDNlm9R_w_0FDGjSM1fzyx5I5JnJBXACqU');
10 |
11 | app.use(express.static(__dirname));
12 |
13 | app.use(bodyParser.json());
14 |
15 | app.use("/push", function(req, res, next) {
16 | console.log(res.body);
17 | if (req.body.action === 'subscribe') {
18 | var endpoint = req.body.subscription.endpoint;
19 |
20 | // Send a push once immediately after subscribing, and one 5 seconds later
21 | sendNotification(endpoint);
22 | setTimeout(function() {
23 | console.log("[[SENDING PUSH NOW: " + endpoint + "]]");
24 | sendNotification(endpoint);
25 | }, 5000);
26 | res.send({text:'Sending push in 5',status:"200"});
27 | } else {
28 | throw new Error ('Unsupported action');
29 | }
30 | });
31 |
32 | app.use("/pushdata",function(req,res,next){
33 | res.send(JSON.stringify({
34 | msg: "We have "+parseInt(Math.random()*9+1)+" cabs available for you for next one hour"
35 | }));
36 | });
37 |
38 | app.listen(PORT, 'localhost', function() {
39 | console.log('express server listening on port', PORT);
40 | });
41 |
42 | function sendNotification(endpoint) {
43 | console.log('endpoint', endpoint)
44 | webPush.sendNotification(endpoint)
45 | .then(function(response) {
46 | if (response) {
47 | console.log("PUSH RESPONSE: ", response);
48 | } else {
49 | console.log("PUSH SENT");
50 | }
51 | })
52 | .catch(function(err) {
53 | console.error("PUSH ERR: " + err);
54 | });
55 | }
56 |
--------------------------------------------------------------------------------
/step6-complete/service-worker.js:
--------------------------------------------------------------------------------
1 | importScripts('../node_modules/sw-toolbox/sw-toolbox.js');
2 | var version = '6';
3 | var dataCacheName = 'weatherData-v'+version;
4 | var cacheName = 'weatherPWA-step-celebrate-'+version;
5 | var filesToCache = [
6 | './',
7 | './index.html',
8 | './scripts/app.js',
9 | './styles/inline.css',
10 | './images/icons/icon-256x256.png'
11 | ];
12 |
13 | toolbox.options.cache.name = cacheName;
14 | toolbox.precache(filesToCache);
15 |
16 | self.addEventListener('install', function(e) {
17 | e.waitUntil(self.skipWaiting());
18 | });
19 |
20 | // activate event
21 | self.addEventListener('activate', function(e) {
22 | console.log('[ServiceWorker] Activate');
23 | e.waitUntil(
24 | caches.keys().then(function(keyList) {
25 | return Promise.all(keyList.map(function(key) {
26 | console.log('[ServiceWorker] Removing old cache', key);
27 | if ((key !== dataCacheName || key !== cacheName) && key.indexOf("$$$inactive$$$") === -1) {
28 | return caches.delete(key);
29 | }
30 | }));
31 | })
32 | );
33 | });
34 |
35 | var nosw = 0;
36 | self.addEventListener('fetch', function(e) {
37 | var url = new URL(e.request.url);
38 | if (nosw || (url.search.indexOf("nosw=1") >= 0)) {
39 | nosw = 1;
40 | return;
41 | }
42 | });
43 |
44 | self.addEventListener('push', function(e) {
45 | console.log('[ServiceWorker] Received push event');
46 | e.waitUntil(
47 | fetch('/pushdata').then(function(response) {
48 | return response.json();
49 | }).then(function(data) {
50 | var title = 'Weather PWA';
51 | var body = data.msg;
52 | var icon = '/images/icons/icon-256x256.png';
53 | var tag = 'static-tag';
54 | return self.registration.showNotification(title, {
55 | body: body,
56 | icon: icon,
57 | tag: tag
58 | });
59 | }, function(err) {
60 | console.error(err);
61 | })
62 | );
63 | });
64 |
65 | toolbox.router.get('/(.*)', toolbox.cacheFirst, {
66 | cache: { name: cacheName }
67 | });
68 |
--------------------------------------------------------------------------------
/step3/service-worker.js:
--------------------------------------------------------------------------------
1 | var version = '5';
2 | var dataCacheName = 'weatherData-v' + version;
3 | var cacheName = 'weatherPWA-v' + version;
4 | var filesToCache = [
5 | './',
6 | './index.html',
7 | './scripts/app.js',
8 | './images/icons/icon-256x256.png'
9 | ];
10 |
11 | self.addEventListener('install', (e) => {
12 | console.log('[ServiceWorker] Install');
13 | e.waitUntil(
14 | caches.open(cacheName).then((cache) => {
15 | console.log('[ServiceWorker] Caching App Shell');
16 | return cache.addAll(filesToCache);
17 | })
18 | );
19 | });
20 |
21 | self.addEventListener('activate', (e) => {
22 | console.log('[ServiceWorker] Activate');
23 | e.waitUntil(
24 | caches.keys().then((keyList) => {
25 | return Promise.all(keyList.map((key) => {
26 | console.log('[ServiceWorker] Removing old cache', key);
27 | if (key !== cacheName) {
28 | return caches.delete(key);
29 | }
30 | }));
31 | })
32 | );
33 | });
34 |
35 | var nosw = 0;
36 | self.addEventListener('fetch', (e) => {
37 | var url = new URL(e.request.url);
38 | if(nosw || (url.search.indexOf("nosw=1") >= 0)) {
39 | console.log('[ServiceWorker] Skipping the ServiceWorker');
40 | nosw = 1;
41 | return; // Fall through to the network
42 | }
43 |
44 | console.log('[ServiceWorker] Fetch', e.request.url);
45 | if (e.request.url.indexOf('data/') != -1) {
46 | e.respondWith(
47 | fetch(e.request)
48 | .then((response) => {
49 | return caches.open(dataCacheName).then((cache) => {
50 | cache.put(e.request.url, response.clone());
51 | console.log('[ServiceWorker] Fetched & Cached', e.request.url);
52 | return response;
53 | });
54 | })
55 | );
56 | } else {
57 | e.respondWith(
58 | caches.match(e.request).then((response) => {
59 | return response || fetch(e.request);
60 | })
61 | );
62 | }
63 | });
64 |
65 | // You will use this later to set up push notifications
66 | // self.addEventListener('push', function(e) {
67 | // console.log('[ServiceWorker] Received push event');
68 | // });
69 |
--------------------------------------------------------------------------------
/step2/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 |
55 | });
56 |
57 | /*****************************************************************************
58 | *
59 | * Methods for dealing with the network
60 | *
61 | ****************************************************************************/
62 |
63 | // Gets a forecast for a specific city
64 | app.getForecast = function(cityKey) {
65 | var url = '../data/' + cityKey + '.json';
66 | app.hasRequestPending = true;
67 | // Make the XHR to get the data, then update the card
68 | return fetch(url).then((response) => {
69 | if (response.status === 200) {
70 | return response.json();
71 | }
72 | }).then((data) => {
73 | app.hasRequestPending = false;
74 | return data;
75 | });
76 | };
77 |
78 | /*****************************************************************************
79 | *
80 | * Start the app
81 | *
82 | ****************************************************************************/
83 |
84 | app.selectedCityKeys = [
85 | 'austin',
86 | 'baltimore',
87 | 'boston',
88 | 'chicago',
89 | 'dallas',
90 | 'losangeles',
91 | 'newyork',
92 | 'sanfrancisco',
93 | ];
94 |
95 | app.selectedCityKeys.forEach((cityKey) => {
96 | app.getForecast(cityKey).then((forecast) => {
97 | app.updateForecastCard(cityKey, forecast);
98 | });
99 | });
100 |
--------------------------------------------------------------------------------
/step1/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 |
55 | });
56 |
57 | /*****************************************************************************
58 | *
59 | * Methods for dealing with the network
60 | *
61 | ****************************************************************************/
62 |
63 | // Gets a forecast for a specific city
64 | app.getForecast = function(cityKey) {
65 | var url = '../data/' + cityKey + '.json';
66 | app.hasRequestPending = true;
67 | // Make the XHR to get the data, then update the card
68 | return fetch(url).then((response) => {
69 | if (response.status === 200) {
70 | return response.json();
71 | }
72 | }).then((data) => {
73 | app.hasRequestPending = false;
74 | console.log('[App] Forecast Updated From Network');
75 | return data;
76 | });
77 | };
78 |
79 | /*****************************************************************************
80 | *
81 | * Start the app
82 | *
83 | ****************************************************************************/
84 |
85 | app.selectedCityKeys = [
86 | 'austin',
87 | 'baltimore',
88 | 'boston',
89 | 'chicago',
90 | 'dallas',
91 | 'losangeles',
92 | 'newyork',
93 | 'sanfrancisco',
94 | ];
95 |
96 | app.selectedCityKeys.forEach((cityKey) => {
97 | app.getForecast(cityKey).then((forecast) => {
98 | app.updateForecastCard(cityKey, forecast);
99 | });
100 | });
101 |
--------------------------------------------------------------------------------
/step3/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 |
55 | });
56 |
57 | /*****************************************************************************
58 | *
59 | * Methods for dealing with the network
60 | *
61 | ****************************************************************************/
62 |
63 | // Gets a forecast for a specific city
64 | app.getForecast = function(cityKey) {
65 | var url = '../data/' + cityKey + '.json';
66 | app.hasRequestPending = true;
67 | // Make the XHR to get the data, then update the card
68 | return fetch(url).then((response) => {
69 | if (response.status === 200) {
70 | return response.json();
71 | }
72 | }).then((data) => {
73 | app.hasRequestPending = false;
74 | return data;
75 | });
76 | };
77 |
78 | /*****************************************************************************
79 | *
80 | * Start the app
81 | *
82 | ****************************************************************************/
83 |
84 | app.selectedCityKeys = [
85 | 'austin',
86 | 'baltimore',
87 | 'boston',
88 | 'chicago',
89 | 'dallas',
90 | 'losangeles',
91 | 'newyork',
92 | 'sanfrancisco',
93 | ];
94 |
95 | app.selectedCityKeys.forEach((cityKey) => {
96 | app.getForecast(cityKey).then((forecast) => {
97 | app.updateForecastCard(cityKey, forecast);
98 | });
99 | });
100 |
101 | // Add feature check for Service Workers here
102 | if('serviceWorker' in navigator) {
103 | navigator.serviceWorker
104 | .register('./service-worker.js')
105 | .then(() => console.log('Service Worker Registered'));
106 | }
107 |
--------------------------------------------------------------------------------
/step4/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 |
55 | });
56 |
57 | /*****************************************************************************
58 | *
59 | * Methods for dealing with the network
60 | *
61 | ****************************************************************************/
62 |
63 | // Gets a forecast for a specific city
64 | app.getForecast = function(cityKey) {
65 | var url = '../data/' + cityKey + '.json';
66 | app.hasRequestPending = true;
67 | // Make the XHR to get the data, then update the card
68 | return fetch(url).then((response) => {
69 | if (response.status === 200) {
70 | return response.json();
71 | }
72 | }).then((data) => {
73 | app.hasRequestPending = false;
74 | return data;
75 | });
76 | };
77 |
78 | /*****************************************************************************
79 | *
80 | * Start the app
81 | *
82 | ****************************************************************************/
83 |
84 | app.selectedCityKeys = [
85 | 'austin',
86 | 'baltimore',
87 | 'boston',
88 | 'chicago',
89 | 'dallas',
90 | 'losangeles',
91 | 'newyork',
92 | 'sanfrancisco',
93 | ];
94 |
95 | app.selectedCityKeys.forEach((cityKey) => {
96 | app.getForecast(cityKey).then((forecast) => {
97 | app.updateForecastCard(cityKey, forecast);
98 | });
99 | });
100 |
101 | // Add feature check for Service Workers here
102 | if('serviceWorker' in navigator) {
103 | navigator.serviceWorker
104 | .register('./service-worker.js')
105 | .then(() => console.log('Service Worker Registered'));
106 | }
107 |
--------------------------------------------------------------------------------
/step5/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 |
55 | });
56 |
57 | /*****************************************************************************
58 | *
59 | * Methods for dealing with the network
60 | *
61 | ****************************************************************************/
62 |
63 | // Gets a forecast for a specific city
64 | app.getForecast = function(cityKey) {
65 | var url = '../data/' + cityKey + '.json';
66 | app.hasRequestPending = true;
67 | // Make the XHR to get the data, then update the card
68 | return fetch(url).then((response) => {
69 | if (response.status === 200) {
70 | return response.json();
71 | }
72 | }).then((data) => {
73 | app.hasRequestPending = false;
74 | return data;
75 | });
76 | };
77 |
78 | /*****************************************************************************
79 | *
80 | * Listen for the add to home screen events
81 | *
82 | ****************************************************************************/
83 |
84 | window.addEventListener('beforeinstallprompt', function(e) {
85 | console.log('[App] Showing install prompt');
86 |
87 | // e.userChoice will return a Promise.
88 | // For more details read: http://www.html5rocks.com/en/tutorials/es6/promises/
89 | e.userChoice.then(function(choiceResult) {
90 | console.log(choiceResult.outcome);
91 | });
92 | });
93 |
94 | /*****************************************************************************
95 | *
96 | * Start the app
97 | *
98 | ****************************************************************************/
99 |
100 | app.selectedCityKeys = [
101 | 'austin',
102 | 'baltimore',
103 | 'boston',
104 | 'chicago',
105 | 'dallas',
106 | 'losangeles',
107 | 'newyork',
108 | 'sanfrancisco',
109 | ];
110 |
111 | app.selectedCityKeys.forEach((cityKey) => {
112 | app.getForecast(cityKey).then((forecast) => {
113 | app.updateForecastCard(cityKey, forecast);
114 | });
115 | });
116 |
117 | // Add feature check for Service Workers here
118 | if('serviceWorker' in navigator) {
119 | navigator.serviceWorker
120 | .register('./service-worker.js')
121 | .then(() => console.log('Service Worker Registered'));
122 | }
123 |
--------------------------------------------------------------------------------
/step6-complete/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*****************************************************************************
4 | *
5 | * Setup the core app model
6 | *
7 | ****************************************************************************/
8 |
9 | var app = {
10 | isLoading: true,
11 | hasRequestPending: false,
12 | visibleCards: {},
13 | selectedCityKeys: [],
14 | spinner: document.querySelector('.loader'),
15 | cardTemplate: document.querySelector('.cardTemplate'),
16 | container: document.querySelector('#container'),
17 | daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
18 | };
19 |
20 | /*****************************************************************************
21 | *
22 | * Methods to update/refresh the UI
23 | *
24 | ****************************************************************************/
25 |
26 | // Updates a weather card with the latest weather forecast. If the card
27 | // doesn't already exist, it's cloned from the template.
28 | app.updateForecastCard = function(cityKey, data) {
29 | var card = app.visibleCards[cityKey];
30 | if (!card) {
31 | card = app.cardTemplate.cloneNode(true);
32 | card.classList.remove('cardTemplate');
33 | card.querySelector('.location').textContent = data.city;
34 | card.removeAttribute('hidden');
35 | app.container.appendChild(card);
36 | app.visibleCards[cityKey] = card;
37 | }
38 | card.querySelector('.temperature').innerHTML =
39 | Math.round(data.currently.temperature) + '°F';
40 | if (app.isLoading) {
41 | app.spinner.setAttribute('hidden', true);
42 | app.container.removeAttribute('hidden');
43 | app.isLoading = false;
44 | }
45 | };
46 |
47 | /*****************************************************************************
48 | *
49 | * Event listeners for the UI
50 | *
51 | ****************************************************************************/
52 |
53 | document.querySelector('#butNotif').addEventListener('click', (e) => {
54 | // Request permission to send notifications
55 | Notification.requestPermission().then(() => {
56 | // Get a reference to the SW
57 | return navigator.serviceWorker.ready;
58 | }).then((sw) => {
59 | // Tell it to subscribe with the push server
60 | return sw.pushManager.subscribe({userVisibleOnly: true});
61 | }).then((subscription) => {
62 | // Send details about the subscription to the server
63 | return fetch('../push', {
64 | method: 'POST',
65 | body: JSON.stringify({
66 | action: 'subscribe',
67 | subscription: subscription
68 | }),
69 | headers: new Headers({
70 | 'Content-Type': 'application/json'
71 | })
72 | });
73 | });
74 | });
75 |
76 | /*****************************************************************************
77 | *
78 | * Methods for dealing with the network
79 | *
80 | ****************************************************************************/
81 |
82 | // Gets a forecast for a specific city
83 | app.getForecast = function(cityKey) {
84 | var url = '../data/' + cityKey + '.json';
85 | app.hasRequestPending = true;
86 | // Make the XHR to get the data, then update the card
87 | return fetch(url).then((response) => {
88 | if (response.status === 200) {
89 | return response.json();
90 | }
91 | }).then((data) => {
92 | app.hasRequestPending = false;
93 | return data;
94 | });
95 | };
96 |
97 | /*****************************************************************************
98 | *
99 | * Listen for the add to home screen events
100 | *
101 | ****************************************************************************/
102 |
103 | window.addEventListener('beforeinstallprompt', function(e) {
104 | console.log('[App] Showing install prompt');
105 |
106 | // e.userChoice will return a Promise.
107 | // For more details read: http://www.html5rocks.com/en/tutorials/es6/promises/
108 | e.userChoice.then(function(choiceResult) {
109 | console.log(choiceResult.outcome);
110 | });
111 | });
112 |
113 | /*****************************************************************************
114 | *
115 | * Start the app
116 | *
117 | ****************************************************************************/
118 |
119 | app.selectedCityKeys = [
120 | 'austin',
121 | 'baltimore',
122 | 'boston',
123 | 'chicago',
124 | 'dallas',
125 | 'losangeles',
126 | 'newyork',
127 | 'sanfrancisco',
128 | ];
129 |
130 | app.selectedCityKeys.forEach((cityKey) => {
131 | app.getForecast(cityKey).then((forecast) => {
132 | app.updateForecastCard(cityKey, forecast);
133 | });
134 | });
135 |
136 | // Add feature check for Service Workers here
137 | if('serviceWorker' in navigator) {
138 | navigator.serviceWorker
139 | .register('./service-worker.js')
140 | .then(() => console.log('Service Worker Registered'));
141 | }
142 |
--------------------------------------------------------------------------------
/step1/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step2/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step3/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step4/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step5/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step6-complete/styles/inline.css:
--------------------------------------------------------------------------------
1 | .header,body {
2 | display: -webkit-box;
3 | display: -webkit-flex;
4 | display: -ms-flexbox;
5 | -webkit-box-direction: normal
6 | }
7 |
8 | *,.card,.loader #spinner {
9 | box-sizing: border-box
10 | }
11 |
12 | body,html {
13 | padding: 0;
14 | margin: 0;
15 | height: 100%;
16 | width: 100%;
17 | font-family: Helvetica,Verdana,sans-serif;
18 | font-weight: 400;
19 | font-display: optional;
20 | color: #444;
21 | -webkit-font-smoothing: antialiased;
22 | -moz-osx-font-smoothing: grayscale
23 | }
24 |
25 | body {
26 | display: flex;
27 | -webkit-box-orient: vertical;
28 | -webkit-flex-direction: column;
29 | -ms-flex-direction: column;
30 | flex-direction: column;
31 | -webkit-flex-wrap: nowrap;
32 | -ms-flex-wrap: nowrap;
33 | flex-wrap: nowrap;
34 | -webkit-box-pack: start;
35 | -webkit-justify-content: flex-start;
36 | -ms-flex-pack: start;
37 | justify-content: flex-start;
38 | -webkit-box-align: stretch;
39 | -webkit-align-items: stretch;
40 | -ms-flex-align: stretch;
41 | align-items: stretch;
42 | -webkit-align-content: stretch;
43 | -ms-flex-line-pack: stretch;
44 | align-content: stretch;
45 | background: #ececec
46 | }
47 |
48 | .header {
49 | width: 100%;
50 | height: 56px;
51 | color: #FFF;
52 | background: #3F51B5;
53 | position: fixed;
54 | font-size: 20px;
55 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 2px 9px 1px rgba(0,0,0,.12),0 4px 2px -2px rgba(0,0,0,.2);
56 | padding: 16px 16px 0;
57 | will-change: transform;
58 | display: flex;
59 | flex-direction: row;
60 | flex-wrap: nowrap;
61 | justify-content: flex-start;
62 | align-items: stretch;
63 | align-content: center;
64 | z-index: 10;
65 | }
66 |
67 | .header .headerButton {
68 | width: 24px;
69 | height: 24px;
70 | margin-right: 16px;
71 | text-indent: -30000px;
72 | overflow: hidden;
73 | opacity: .54;
74 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
75 | transition: opacity 333ms cubic-bezier(0,0,.21,1);
76 | border: none;
77 | outline: 0
78 | }
79 |
80 | .card,.dialog {
81 | border-radius: 2px
82 | }
83 |
84 | .header #butNotif {
85 | background: url(../images/ic_notifications_white_24px.svg) center center no-repeat
86 | }
87 |
88 | .header__title {
89 | font-weight: 400;
90 | font-size: 20px;
91 | margin: 0;
92 | -webkit-box-flex: 1;
93 | -webkit-flex: 1;
94 | -ms-flex: 1;
95 | flex: 1
96 | }
97 |
98 | .loader {
99 | left: 50%;
100 | top: 50%;
101 | position: fixed;
102 | -webkit-transform: translate(-50%,-50%);
103 | transform: translate(-50%,-50%)
104 | }
105 |
106 | .loader #spinner {
107 | stroke: #673AB7;
108 | stroke-width: 3px;
109 | -webkit-transform-origin: 50%;
110 | transform-origin: 50%;
111 | -webkit-animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite;
112 | animation: line 1.6s cubic-bezier(.4,0,.2,1) infinite,rotate 1.6s linear infinite
113 | }
114 |
115 | @-webkit-keyframes rotate {
116 | from {
117 | -webkit-transform: rotate(0);
118 | transform: rotate(0)
119 | }
120 |
121 | to {
122 | -webkit-transform: rotate(450deg);
123 | transform: rotate(450deg)
124 | }
125 | }
126 |
127 | @keyframes rotate {
128 | from {
129 | -webkit-transform: rotate(0);
130 | transform: rotate(0)
131 | }
132 |
133 | to {
134 | -webkit-transform: rotate(450deg);
135 | transform: rotate(450deg)
136 | }
137 | }
138 |
139 | @-webkit-keyframes line {
140 | 0% {
141 | stroke-dasharray: 2,85.964;
142 | -webkit-transform: rotate(0);
143 | transform: rotate(0)
144 | }
145 |
146 | 50% {
147 | stroke-dasharray: 65.973,21.9911;
148 | stroke-dashoffset: 0
149 | }
150 |
151 | 100% {
152 | stroke-dasharray: 2,85.964;
153 | stroke-dashoffset: -65.973;
154 | -webkit-transform: rotate(90deg);
155 | transform: rotate(90deg)
156 | }
157 | }
158 |
159 | @keyframes line {
160 | 0% {
161 | stroke-dasharray: 2,85.964;
162 | -webkit-transform: rotate(0);
163 | transform: rotate(0)
164 | }
165 |
166 | 50% {
167 | stroke-dasharray: 65.973,21.9911;
168 | stroke-dashoffset: 0
169 | }
170 |
171 | 100% {
172 | stroke-dasharray: 2,85.964;
173 | stroke-dashoffset: -65.973;
174 | -webkit-transform: rotate(90deg);
175 | transform: rotate(90deg)
176 | }
177 | }
178 |
179 | #container {
180 | padding-top: 60px;
181 | flex: 1;
182 | }
183 |
184 | .dialog-container {
185 | background: rgba(0,0,0,.57);
186 | position: fixed;
187 | left: 0;
188 | top: 0;
189 | width: 100%;
190 | height: 100%;
191 | opacity: 0;
192 | pointer-events: none;
193 | will-change: opacity;
194 | -webkit-transition: opacity 333ms cubic-bezier(0,0,.21,1);
195 | transition: opacity 333ms cubic-bezier(0,0,.21,1)
196 | }
197 |
198 | .dialog-container--visible {
199 | opacity: 1;
200 | pointer-events: auto
201 | }
202 |
203 | .dialog {
204 | background: #FFF;
205 | box-shadow: 0 0 14px rgba(0,0,0,.24),0 14px 28px rgba(0,0,0,.48);
206 | min-width: 280px;
207 | position: absolute;
208 | left: 50%;
209 | top: 50%;
210 | -webkit-transform: translate(-50%,-50%) translateY(30px);
211 | transform: translate(-50%,-50%) translateY(30px);
212 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
213 | transition: -webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
214 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms;
215 | transition: transform 333ms cubic-bezier(0,0,.21,1) 50ms,-webkit-transform 333ms cubic-bezier(0,0,.21,1) 50ms;
216 | padding: 24px
217 | }
218 |
219 | .card {
220 | padding: 16px;
221 | position: relative;
222 | background: #fff;
223 | margin: 16px;
224 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)
225 | }
226 |
227 | .weather-forecast .location {
228 | font-size: 1.75em
229 | }
230 |
231 | .weather-forecast .date,.weather-forecast .description {
232 | font-size: 1.25em
233 | }
234 |
235 | .weather-forecast .current {
236 | display: -webkit-box;
237 | display: -webkit-flex;
238 | display: -ms-flexbox;
239 | display: flex
240 | }
241 |
242 | .weather-forecast .current .icon {
243 | width: 128px;
244 | height: 128px
245 | }
246 |
247 | .weather-forecast .current .visual {
248 | display: -webkit-box;
249 | display: -webkit-flex;
250 | display: -ms-flexbox;
251 | display: flex;
252 | font-size: 4em
253 | }
254 |
255 | .weather-forecast .current .visual .scale {
256 | font-size: .5em;
257 | vertical-align: super
258 | }
259 |
260 | .weather-forecast .current .description,.weather-forecast .current .visual {
261 | -webkit-box-flex: 1;
262 | -webkit-flex-grow: 1;
263 | -ms-flex-positive: 1;
264 | flex-grow: 1
265 | }
266 |
267 | .weather-forecast .current .feels-like:before {
268 | content: "Feels like: ";
269 | color: #888
270 | }
271 |
272 | .weather-forecast .current .wind:before {
273 | content: "Wind: ";
274 | color: #888
275 | }
276 |
277 | .weather-forecast .current .precip:before {
278 | content: "Precipitation: ";
279 | color: #888
280 | }
281 |
282 | .weather-forecast .current .humidity:before {
283 | content: "Humidity: ";
284 | color: #888
285 | }
286 |
287 | .weather-forecast .current .pollen:before {
288 | content: "Pollen Count: ";
289 | color: #888
290 | }
291 |
292 | .weather-forecast .current .pcount:before {
293 | content: "Pollen ";
294 | color: #888
295 | }
296 |
297 | .weather-forecast .future {
298 | display: -webkit-box;
299 | display: -webkit-flex;
300 | display: -ms-flexbox;
301 | display: flex
302 | }
303 |
304 | .weather-forecast .future .oneday {
305 | -webkit-box-flex: 1;
306 | -webkit-flex-grow: 1;
307 | -ms-flex-positive: 1;
308 | flex-grow: 1;
309 | text-align: center
310 | }
311 |
312 | .weather-forecast .future .oneday .icon {
313 | width: 64px;
314 | height: 64px;
315 | margin-left: auto;
316 | margin-right: auto
317 | }
318 |
319 | .weather-forecast .future .oneday .temp-high,.weather-forecast .future .oneday .temp-low {
320 | display: inline-block
321 | }
322 |
323 | .weather-forecast .future .oneday .temp-low {
324 | color: #888
325 | }
326 |
327 | .weather-forecast .icon {
328 | background-repeat: no-repeat;
329 | background-size: contain
330 | }
331 |
332 | .weather-forecast .icon.clear-day,.weather-forecast .icon.clear-night {
333 | background-image: url(../images/clear.png)
334 | }
335 |
336 | .weather-forecast .icon.rain {
337 | background-image: url(../images/rain.png)
338 | }
339 |
340 | .weather-forecast .icon.snow {
341 | background-image: url(../images/snow.png)
342 | }
343 |
344 | .weather-forecast .icon.sleet {
345 | background-image: url(../images/sleet.png)
346 | }
347 |
348 | .weather-forecast .icon.wind {
349 | background-image: url(../images/wind.png)
350 | }
351 |
352 | .weather-forecast .icon.fog {
353 | background-image: url(../images/fog.png)
354 | }
355 |
356 | .weather-forecast .icon.cloudy {
357 | background-image: url(../images/cloudy.png)
358 | }
359 |
360 | .weather-forecast .icon.partly-cloudy-day,.weather-forecast .icon.partly-cloudy-night {
361 | background-image: url(../images/partly-cloudy.png)
362 | }
363 |
364 | .weather-forecast .icon.thunderstorms {
365 | background-image: url(../images/thunderstorms.png)
366 | }
367 |
368 | @media (max-width: 450px) {
369 | .weather-forecast .date,.weather-forecast .description {
370 | font-size:.9em
371 | }
372 |
373 | .weather-forecast .current .icon {
374 | width: 96px;
375 | height: 96px
376 | }
377 |
378 | .weather-forecast .current .visual {
379 | font-size: 3em
380 | }
381 |
382 | .weather-forecast .future .oneday .icon {
383 | width: 32px;
384 | height: 32px
385 | }
386 | }
387 |
--------------------------------------------------------------------------------
/step1/scripts/push-client.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 | http://www.apache.org/licenses/LICENSE-2.0
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | See the License for the specific language governing permissions and
11 | limitations under the License.
12 | */
13 |
14 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o