frontend facelift with jsx and babel

develop
Kenneth Barbour 2020-07-07 21:37:12 -04:00
parent e7366ebfcb
commit 219c9136e6
12 changed files with 1716 additions and 12 deletions

View File

@ -0,0 +1,9 @@
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "m",
"pragmaFrag": "'['"
}]
]
}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,10 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/plugin-transform-react-jsx": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"babel-loader": "^8.1.0",
"bulma": "^0.7.5",
"chart.js": "^2.8.0",
"css-loader": "^3.2.1",
@ -20,11 +24,11 @@
"mini-css-extract-plugin": "^0.8.0",
"mithril": "^2.0.4",
"node-sass": "^4.13.0",
"npm-watch": "^0.6.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.1",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9",
"npm-watch": "^0.6.0"
"webpack-cli": "^3.3.9"
},
"watch": {
"sandbox-server": {

View File

@ -63,7 +63,7 @@ server = http.createServer(function(req, res) {
res.write(JSON.stringify({
"time": new Date(),
"temperature": 24,
"pressure": 1013.25,
"pressure": 101361.7,
"humidity": 55,
"battery": {
"voltage": 3.6,

View File

@ -0,0 +1,20 @@
import m from 'mithril';
import Navbar from '../components/Navbar';
class Layout {
view(vnode) {
const { children } = vnode;
return (
<>
<Navbar />
<section class="section">
<div class="container">
{children}
</div>
</section>
</>
);
}
}
export default Layout;

View File

@ -0,0 +1,15 @@
import m from 'mithril';
class Measurement {
view(vnode) {
const { title, value } = vnode.attrs;
return (
<div>
<p class="heading">{title}</p>
<p class="title">{value}</p>
</div>
);
}
}
export default Measurement;

View File

@ -0,0 +1,17 @@
import m from 'mithril';
class MeasurementList {
view(vnode) {
return (
<div class="level">
{vnode.children.map( child => (
<div class="level-item has-text-centered">
{child}
</div>
))}
</div>
);
}
}
export default MeasurementList;

View File

@ -0,0 +1,88 @@
import m from 'mithril';
import { Link } from 'mithril/route'
import UserPrefs from '../models/UserPrefs';
import Weather from '../models/weather';
class Navbar {
oninit() {
UserPrefs.load();
}
view() {
const batteryClass = 'is-success'; // TODO: determine from battery
const batteryPercentage = 65;
const batteryVoltage = 3.6;
const batteryIsCharging = false;
const menuActiveClass = Navbar.isMenuActive ? 'is-active' : '';
return (
<nav class="navbar" role="navigation" aria-label="main-navigation">
<div class="navbar-brand">
<div class="navbar-item">
<Link href="/">
<img src="/favicon.ico" alt="uWeather" width="28" height="28" />
</Link>
</div>
<div class="navbar-burger" role="button" aria-label="menu" aria-expanded="false" onclick={()=>{ Navbar.isMenuActive = !Navbar.isMenuActive}}>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</div>
</div>
<div class={`navbar-menu ${menuActiveClass}`}>
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<div class="navbar-link">
<progress class={`progress is-small ${batteryClass}`}
style="width: 32px;"
value={batteryPercentage}
max="100">
{batteryPercentage}%
</progress>
</div>
<div class="navbar-dropdown is-right">
<div class="navbar-item">{batteryVoltage} volts</div>
<div class="navbar-item">{batteryPercentage} %</div>
<div class="navbar-item">{batteryIsCharging ? 'Charging' : 'Not charging'}</div>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<div class="navbar-link">
<a>&#128295;</a>
</div>
<div class="navbar-dropdown is-right">
<div class="navbar-item checkbox">
<div class="control">
<label class="checkbox">
<input type="checkbox" class="checkbox" checked={UserPrefs.prefs.useImperial} onclick={()=>{UserPrefs.set('useImperial',!UserPrefs.prefs.useImperial);}} />
Convert to Imperial (&#176;F, inHg)
</label>
</div>
</div>
<div class="navbar-item checkbox">
<div class="control">
<label class="checkbox">
<input type="checkbox" class="checkbox" checked={UserPrefs.prefs.liveUpdate} onclick={()=>{UserPrefs.set('liveUpdate',!UserPrefs.prefs.liveUpdate);}} />
Live update
</label>
</div>
</div>
<div class="navbar-item">
<button class="button is-small is-info" disabled={UserPrefs.prefs.liveUpdate} onclick={Weather.loadCurrent} >Refresh</button>
</div>
<hr class="navbar-divider"/>
<a class="navbar-item" href="/setup">Setup</a>
</div>
</div>
</div>
</div>
</nav>
)
}
}
Navbar.isMenuActive = false;
export default Navbar;

View File

@ -1,6 +1,4 @@
require('./style.scss');
var m = require('mithril');
var Weather = require("./models/weather.js");
var CurrentView = require('./views/CurrentView');
import m from 'mithril';
import CurrentConditions from './views/CurrentConditions';
m.mount(document.body, CurrentView);
m.mount(document.body, CurrentConditions);

View File

@ -0,0 +1,29 @@
const UserPrefs = {
prefs: {
useImperial: false,
liveUpdate: true,
},
loaded: false,
load: function() {
if (UserPrefs.loaded) return;
const localPrefs = window.localStorage.getItem('user-prefs');
if (localPrefs) {
const prefsObj = JSON.parse(localPrefs);
UserPrefs.prefs = { ...UserPrefs.prefs, ...prefsObj };
}
UserPrefs.loaded = true;
},
set: function(name, value) {
UserPrefs.prefs[name] = value;
UserPrefs.save();
},
save: function() {
window.localStorage.setItem('user-prefs', JSON.stringify(UserPrefs.prefs));
}
}
export default UserPrefs

View File

@ -0,0 +1,88 @@
import m from 'mithril';
import Layout from '../components/Layout';
import Weather from '../models/weather';
import MeasurementList from '../components/MeasurementList';
import Measurement from '../components/Measurement';
import UserPrefs from '../models/UserPrefs';
function localeTemperature(celsius)
{
if (UserPrefs.prefs.useImperial) {
const f = cToF(celsius);
return `${f.toFixed(1)} °F`;
}
return `${celsius.toFixed(1)} °C`;
}
function localePressure(hpa)
{
if (UserPrefs.prefs.useImperial) {
const inHg = hpa * 0.00029529980164712;
return `${inHg.toFixed(2)} inHg`;
}
const millibar = hpa * 0.01;
return `${millibar.toFixed(0)} mb`;
}
function cToF(celsius)
{
return celsius * 1.8 + 32;
}
function fToC(f)
{
return (f - 32) / 1.8;
}
function feelsLike(celsius, rh)
{
const f = cToF(celsius);
const hindex = -42.379 + (2.04901523 * f) + (10.14333127 * rh)
- (0.22475541 * f * rh) - (6.83783e-3 * f * f)
- (5.481717e-2 * rh * rh) + (1.22874e-3 * f * f * rh)
+ (8.5282e-4 * f * rh * rh) - (1.99e-6 * f * f * rh * rh);
return fToC(hindex);
}
function dewPoint(celsius, rh)
{
const a = 6.1121;
const b = 18.678;
const c = 257.14;
const d = 234.5;
const e = 2.7182818284;
const trh = Math.log(rh / 100) + (b*celsius/(c + celsius));
return (c * trh / (b-trh));
}
class CurrentConditions {
oninit() {
return Weather.loadCurrent();
}
view() {
if (!Weather.current) {
return (
<Layout>
<div class="notification">Loading current conditions</div>
</Layout>
);
}
return (
<Layout>
<h1 class="title">Current Conditions</h1>
<MeasurementList>
<Measurement title="Temperature" value={localeTemperature(Weather.current.temperature)} />
<Measurement title="Feels like" value={localeTemperature(feelsLike(Weather.current.temperature, Weather.current.humidity))} />
<Measurement title="Pressure" value={localePressure(Weather.current.pressure)} />
<Measurement title="Humidity" value={`${Weather.current.humidity}%`} />
<Measurement title="Dew Point" value={localeTemperature(dewPoint(Weather.current.temperature, Weather.current.humidity))} />
</MeasurementList>
</Layout>
);
}
}
export default CurrentConditions;

View File

@ -11,7 +11,15 @@ module.exports = {
filename: 'js/[name].js'
},
module: {
rules: [{
rules: [
{
test:/\.js$/,
exclude: /\/node_modules\//,
use: {
loader: 'babel-loader'
}
},
{
test: /\.s[ac]ss$/,
use: [
MiniCssExtractPlugin.loader,