Skip to content

Commit

Permalink
docs(pwa-example): add example for pwa
Browse files Browse the repository at this point in the history
ported google pwa example to work with maleo

re airyrooms#152
  • Loading branch information
alvinkl committed Mar 28, 2019
1 parent 8b450ac commit 4e04627
Show file tree
Hide file tree
Showing 34 changed files with 1,083 additions and 0 deletions.
3 changes: 3 additions & 0 deletions example/pwa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Maleo Progressive Web Application Example

This example is ported from [Google's PWA Tutorial](https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/) to work with Maleo
34 changes: 34 additions & 0 deletions example/pwa/_document.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { default as Document, Header, Scripts, Main } from '@airy/maleo/document';

export default class CustomDocument extends Document {
render() {
return (
<html>
<Header>
<meta charSet="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#2F3BA2" />
<title>Weather PWA</title>

{/* Safari */}
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="Weather PWA" />
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png" />

{/* Windows */}
<meta name="msapplication-TileImage" content="images/icons/icon-144x144.png" />
<meta name="msapplication-TileColor" content="#2F3BA2" />
</Header>
<body>
<Main />
<Scripts />
</body>
</html>
);
}
}
17 changes: 17 additions & 0 deletions example/pwa/_wrap.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import Wrap from '@airy/maleo/wrap';
import pageWithStyles from '@airy/maleo-css-plugin/pageWithStyles';

@pageWithStyles
export default class extends Wrap {
static getInitialProps = () => {
// Register Service Worker on client
if (typeof window !== 'undefined') {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw').then(function() {
console.log('Service Worker Registered');
});
}
}
};
}
Binary file added example/pwa/images/clear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/cloudy-scattered-showers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/cloudy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/cloudy_s_sunny.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/fog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions example/pwa/images/ic_add_white_24px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions example/pwa/images/ic_refresh_white_24px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-144x144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-152x152.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-256x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/icons/icon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/partly-cloudy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/rain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/scattered-showers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/sleet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/snow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/thunderstorm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/pwa/images/wind.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions example/pwa/maleo.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const cssPlugin = require('@airy/maleo-css-plugin');

module.exports = cssPlugin({
enableISL: true,
cssLoader: {
modules: true,
camelCase: true,
},
});
35 changes: 35 additions & 0 deletions example/pwa/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "Weather",
"short_name": "Weather",
"icons": [
{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "images/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"background_color": "#3E4EB8",
"theme_color": "#2F3BA2"
}
17 changes: 17 additions & 0 deletions example/pwa/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "pwa",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "maleo dev",
"build": "export NODE_ENV=production && maleo build",
"start": "export NODE_ENV=production && node .maleo/server.js"
},
"dependencies": {
"@airy/maleo": "latest",
"@airy/maleo-css-plugin": "^0.1.6",
"classnames": "^2.2.6",
"react": "^16.8.5"
}
}
6 changes: 6 additions & 0 deletions example/pwa/routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"path": "/",
"page": "./src/RootComponent"
}
]
72 changes: 72 additions & 0 deletions example/pwa/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Server } from '@airy/maleo/server';
import path from 'path';
import express from 'express';

const PORT = process.env.PORT || 3000;

const maleoServer = Server.init({
port: PORT,
});

// register static image folder
maleoServer.applyExpressMiddleware('/images', express.static('./images'));
// register path /sw to return service worker file
maleoServer.applyExpressMiddleware('/sw', (req, res, next) => {
res.sendFile(path.resolve('.', 'sw.js'));
});
maleoServer.applyExpressMiddleware('/manifest.json', (req, res, next) => {
res.sendFile(path.resolve('.', 'manifest.json'));
});
maleoServer.faviconHandler = (req, res) => {
res.sendFile(path.resolve('.', 'images', 'icons', 'icon-32x32.png'));
};

// example for client fetching data
maleoServer.applyExpressMiddleware('/api/forecast', (req, res) => {
setTimeout(() => {
res.send({
query: {
created: Date.parse(new Date()),
result: {
key: '2459115',
label: 'New York, NY',
created: '2016-07-22T01:00:00Z',
channel: {
astronomy: {
sunrise: '5:43 am',
sunset: '8:21 pm',
},
item: {
condition: {
text: 'Windy',
date: 'Thu, 21 Jul 2016 09:00 PM EDT',
temp: 56,
code: 24,
},
forecast: [
{ code: 44, high: 86, low: 70 },
{ code: 44, high: 94, low: 73 },
{ code: 4, high: 95, low: 78 },
{ code: 24, high: 75, low: 89 },
{ code: 24, high: 89, low: 77 },
{ code: 44, high: 92, low: 79 },
{ code: 44, high: 89, low: 77 },
],
},
atmosphere: {
humidity: 56,
},
wind: {
speed: 25,
direction: 195,
},
},
},
},
});
}, 2000);
});

maleoServer.run(() => {
console.log('Custom Server running on port:', PORT);
});
140 changes: 140 additions & 0 deletions example/pwa/src/Cards.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import cn from 'classnames';
import withStyles from '@airy/maleo-css-plugin/withStyles';

import style from './style.css';

const daysOfWeek = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

function Cards({ visibleCards }) {
const today = new Date().getDay();

return (
<main className={style.main}>
{Object.keys(visibleCards).map((card) => {
const {
channel: {
astronomy: { sunrise, sunset },
atmosphere: { humidity },
item: { condition, forecast },
wind,
},
created,
key,
label,
} = visibleCards[card];

return (
<div key={created} className={cn(style.card, style.cardTemplate, style.weatherForecast)}>
<div className={style.cityKey} />
<div className={style.cardLastUpdated} />
<div className={style.location} />
<div className={style.date}>{condition.date}</div>
<div className={style.description}>{condition.text}</div>
<div className={style.current}>
<div className={style.visual}>
<div className={cn(style.icon, getIconClass(condition.code, style))} />
<div className={style.temperature}>
<span className={style.value}>{Math.round(condition.temp)}</span>
<span className={style.scale}>°F</span>
</div>
</div>
<div className={style.description}>
<div className={style.humidity}>{Math.round(humidity)}%</div>
<div className={style.wind}>
<span className={style.value}>{Math.round(wind.speed)}</span>
<span className={style.scale}>mph</span>
<span className={style.direction}>{wind.direction}</span>°
</div>
<div className={style.sunrise}>{sunrise}</div>
<div className={style.sunset}>{sunset}</div>
</div>
</div>
<div className={style.future}>
{forecast.map((fc, i) => (
<div key={i} className={style.oneday}>
<div className={style.date}>{daysOfWeek[(i + today) % 7]}</div>
<div className={cn(style.icon, getIconClass(fc.code, style))} />
<div className={style.tempHigh}>
<span className={style.value}>{Math.round(fc.high)}</span>°
</div>
<br />
<div className={style.tempLow}>
<span className={style.value}>{Math.round(fc.low)}</span>°
</div>
</div>
))}
</div>
</div>
);
})}
</main>
);
}

function getIconClass(weatherCode, style) {
weatherCode = parseInt(weatherCode);
switch (weatherCode) {
case 25: // cold
case 32: // sunny
case 33: // fair (night)
case 34: // fair (day)
case 36: // hot
case 3200: // not available
return style.clearDay;
case 0: // tornado
case 1: // tropical storm
case 2: // hurricane
case 6: // mixed rain and sleet
case 8: // freezing drizzle
case 9: // drizzle
case 10: // freezing rain
case 11: // showers
case 12: // showers
case 17: // hail
case 35: // mixed rain and hail
case 40: // scattered showers
return style.rain;
case 3: // severe thunderstorms
case 4: // thunderstorms
case 37: // isolated thunderstorms
case 38: // scattered thunderstorms
case 39: // scattered thunderstorms (not a typo)
case 45: // thundershowers
case 47: // isolated thundershowers
return style.thunderstorms;
case 5: // mixed rain and snow
case 7: // mixed snow and sleet
case 13: // snow flurries
case 14: // light snow showers
case 16: // snow
case 18: // sleet
case 41: // heavy snow
case 42: // scattered snow showers
case 43: // heavy snow
case 46: // snow showers
return style.snow;
case 15: // blowing snow
case 19: // dust
case 20: // foggy
case 21: // haze
case 22: // smoky
return style.fog;
case 24: // windy
case 23: // blustery
return style.windy;
case 26: // cloudy
case 27: // mostly cloudy (night)
case 28: // mostly cloudy (day)
case 31: // clear (night)
return style.cloudy;
case 29: // partly cloudy (night)
case 30: // partly cloudy (day)
case 44: // partly cloudy
return style.partlyCloudyDay;
default:
return '';
}
}

export default withStyles(style)(Cards);
39 changes: 39 additions & 0 deletions example/pwa/src/Dialog.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import withStyles from '@airy/maleo-css-plugin/withStyles';

import style from './style.css';

export function Dialog({ toggleAddDialog, addCity, selectedCity, changeSelectedCity, cities }) {
return (
<div className={style.dialogContainer}>
<div className={style.dialog}>
<div className={style.dialogTitle}>Add new city</div>
<div className={style.dialogBody}>
<select
value={selectedCity}
onChange={changeSelectedCity}
onClick={() => console.log('asd')}>
{cities.map(({ value, city }) => (
<option key={value} value={value}>
{city}
</option>
))}
</select>
</div>
<div className={style.dialogButtons}>
<button id={style.butAddCity} className={style.button} onClick={addCity}>
Add
</button>
<button
id={style.butAddCancel}
className={style.button}
onClick={toggleAddDialog.bind(null, false)}>
Cancel
</button>
</div>
</div>
</div>
);
}

export default withStyles(style)(Dialog);
Loading

0 comments on commit 4e04627

Please sign in to comment.