Created
June 19, 2018 17:20
-
-
Save davidlinse/d2ce0fc4826757c2c17c91032eae443b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>title</title> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<!-- meta name="viewport" content="width=device-width,initial-scale=1" --> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
<meta name="author" content="name"> | |
<meta name="description" content="description here"> | |
<meta name="keywords" content="keywords,here"> | |
<meta http-equiv="cleartype" content="on"> | |
<meta name="MobileOptimized" content="320"> | |
<meta name="HandheldFriendly" content="True"> | |
<meta name="apple-mobile-web-app-capable" content="yes"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/slideout/1.0.1/slideout.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script> | |
<!-- script src="https://cdn.rawgit.com/haydenbbickerton/vue-charts/master/dist/vue-charts.min.js" type="application/javascript"></script //--> | |
<!-- script src="https://unpkg.com/vuex@2.0.0"></script //--> | |
<style> | |
body { | |
width: 100%; | |
height: 100%; | |
margin: 0 | |
} | |
.slideout-menu { | |
position: fixed; | |
top: 0; | |
bottom: 0; | |
width: 256px; | |
min-height: 100vh; | |
overflow-y: scroll; | |
-webkit-overflow-scrolling: touch; | |
z-index: 0; | |
display: none; | |
} | |
.slideout-menu-left { | |
left: 0; | |
} | |
.slideout-menu-right { | |
right: 0; | |
} | |
.slideout-panel { | |
position: relative; | |
z-index: 1; | |
will-change: transform; | |
background-color: #0FF; /* A background-color is required */ | |
min-height: 100vh; | |
} | |
.slideout-open, | |
.slideout-open body, | |
.slideout-open .slideout-panel { | |
overflow: hidden; | |
} | |
.slideout-open .slideout-menu { | |
display: block; | |
} | |
/* https://stackoverflow.com/questions/15976245/how-to-stick-footer-element-at-the-bottom-of-the-page-html5-and-css3 | |
#app-content { | |
min-height: -webkit-calc(100% - 100px); // Chrome | |
min-height: -moz-calc(100% - 100px); // Firefox | |
min-height: calc(100% - 100px); // native | |
} | |
*/ | |
/* sticky footer */ | |
.total-price { | |
background-color: #333; | |
color: #fff; | |
width: 100%; | |
bottom: 0; | |
position: fixed; | |
text-align: center; | |
} | |
input { | |
max-width: 90px | |
} | |
</style> | |
</head> | |
<body> | |
<nav id="menu"> | |
<section> | |
<h3>Menu</h3> | |
<ul> | |
<li><a href>Day</a></li> | |
<li><a href>Month(s)</a></li> | |
<li><a href>Statistics</a></li> | |
<li><a href>Settings</a></li> | |
</ul> | |
</section> | |
<section> | |
<h3>About</h3> | |
<ul> | |
<li><a href>Developer</a></li> | |
<li><a href>License(s)</a></li> | |
</ul> | |
</section> | |
</nav> | |
<main id="panel"> | |
<header> | |
<button class="toggle-button">☰</button> | |
<h3>Current Date goes here</h3> | |
</header> | |
<section id="app"> | |
<!-- form id='moneytracker' --> <!-- v-on:submit.prevent="persist" --> | |
<div id="app-content"> | |
<!-- input type='number' id='amount' v-model.number='amount' placeholder='Amount (optional)' step='1' value='0' min='0.00' / --> | |
<input type='number' id='price' v-model.number='price' placeholder='Price' value='0.00' step='0.10' min='0.00' /> | |
<input type='text' id='description' v-model.number='description' placeholder='Spent for ..' /> | |
<input type='text' id='tag' v-model.string='tag' placeholder='Tag' /> | |
<button id='submit' @click='persist'>Save</button> | |
</div> | |
<!-- | |
<vue-chart | |
:chart-type="chartType" | |
:columns="columns" | |
:rows="rows" | |
:options="options" | |
></vue-chart> | |
--> | |
<footer> | |
<total-price class='total-price' v-bind:value='computed_total_price'></total-price> | |
<footer> | |
<!-- form --> | |
</section> | |
</main> | |
<script> | |
let log = function(msg) { | |
console.log(msg); | |
} | |
</script> | |
<script> | |
// Vue.use(Vuex); | |
let now = Date.now(); | |
let store = { | |
state: { | |
total: 0, | |
entries: [ | |
{ price: 10.99, description: 'a beer', tag: 'beer', ts: now + 60000 }, | |
{ price: 3.50, description: 'another beer', tag: 'beer', ts: now + 180000 }, | |
{ price: 5.99, description: 'menthol liquid', tag: 'dampf', ts: now + 230000 } | |
] | |
}, | |
entry: function(price, description, tag) { | |
return { | |
price: price || 0, | |
descr: description || '', | |
tag: tag || '', | |
ts: Date.now() | |
} | |
} | |
}; | |
Vue.component('total-price', { | |
props: { | |
value: { | |
type: Number, | |
required: true | |
} | |
}, | |
data() { | |
return { | |
} | |
}, | |
template: '<div>{{value}}</div>' | |
}); | |
Vue.component('daily-graph', { | |
props: { | |
value: { | |
type: Number, | |
required: true | |
} | |
}, | |
template: '<div>{{value}}</div>' | |
}); | |
// Vue.use(VueCharts); | |
let app = new Vue({ | |
el: '#app', | |
data: { | |
// business logic | |
amount: 1, | |
price: 1.0, | |
total_price: store.state.total, | |
description: '', | |
tag: '', | |
entries: [], | |
// statistics | |
chartType: 'LineChart', | |
activeSet: 'cost', | |
options: { | |
chart: { | |
title: 'Chart Title', | |
subtitle: 'Subtitle' | |
}, | |
hAxis: {title: 'Date'}, | |
vAxis: {title: 'Price'}, | |
height: 500, | |
animation: { | |
duration: 500, | |
easing: 'out', | |
} | |
} | |
}, | |
methods: { | |
persist() { | |
//-- calculate price based on amount and value | |
var value = this.amount * this.price; | |
// TOOD: research setting `value` two times is really neccesary | |
// -- currently needed to live update the component | |
// -- as it 'listenes' to property value changes (~?!) | |
// | |
//-- update store and internal values | |
store.state.total = this.total_price += value; | |
//-- add new entry to store | |
store.state.entries.push(new store.entry(value, this.description, this.tag)); | |
//-- persist store | |
localStorage.setItem('moneytracker', JSON.stringify(store)); | |
} | |
}, | |
mounted() { | |
if (!localStorage.moneytracker) { | |
localStorage.setItem('moneytracker', JSON.stringify(store)); | |
}; | |
let data = JSON.parse(localStorage.getItem('moneytracker')); | |
this.total_price = data.state.total; | |
}, | |
computed: { | |
computed_total_price() { | |
return parseFloat(this.total_price.toFixed(2)); | |
}, | |
columns() { | |
return [ | |
{ | |
'type': 'date', | |
'label' : 'Date' | |
}, | |
{ | |
'type' : 'number', | |
'label' : 'Spent' | |
}]; | |
}, | |
rows() { | |
//return [[1,1],[5,10], [7,2], [15,20]]; | |
const statKeys = ['ts', 'price']; | |
let result = _ | |
.chain(store.state.entries) | |
.mapValues(function(stat) { | |
let picked = _.pick(stat, statKeys); | |
picked['ts'] = new Date(picked['ts']); | |
return _.values(picked) | |
}) | |
.toArray() | |
.value(); | |
return result; | |
} | |
} | |
}); | |
</script> | |
<script> | |
var slideout = new Slideout({ | |
'panel': document.getElementById('panel'), | |
'menu': document.getElementById('menu'), | |
'padding': 130, | |
'tolerance': 70 | |
}); | |
// Toggle button | |
document.querySelector('.toggle-button').addEventListener('click', () => { | |
slideout.toggle(); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment