JSFiddle - React, Tailwind, and code Playground
by Damian Dulisz
HTML
<div id="app">
<table>
<thead>
<tr>
<th>Metrics</th>
<th v-for="metric of metrics">
{{ metric.month }}
</th>
<th>{{ diff.name }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>Revenue</td>
<td v-for="metric of metrics">
<input v-model="metric.revenue" type="number">
</td>
<td :class="getClass(diff.revenue)">{{ diff.revenue }}%</td>
</tr>
<tr>
<td>Costs</td>
<td v-for="metric of metrics">
<input v-model="metric.costs" type="number">
</td>
<td :class="getClass(diff.costs)">{{ diff.costs }}%</td>
</tr>
<tr>
<td>Income</td>
<td v-for="metric of metrics">
<input v-model="metric.income" type="number">
</td>
<td :class="getClass(diff.income)">{{ diff.income }}%</td>
</tr>
<tr>
<td>cash</td>
<td v-for="metric of metrics">
<input v-model="metric.cash" type="number">
</td>
<td :class="getClass(diff.cash)">{{ diff.cash }}%</td>
</tr>
<tr>
<td>Customers</td>
<td v-for="metric of metrics">
<input v-model="metric.customers" type="number">
</td>
<td :class="getClass(diff.customers)">{{ diff.customers }}%</td>
</tr>
<tr>
<td>Projects sold</td>
<td v-for="metric of metrics">
<input v-model="metric.sold" type="number">
</td>
<td :class="getClass(diff.customers)">{{ diff.sold }}%</td>
</tr>
</tbody>
</table>
<input type="text" @keyup.enter="addMonth($event)" placeholder="Add month and press enter">
</div>
CSS
body {
font-family: Helvetica Neue, Arial, sans-serif;
font-size: 14px;
color: #444;
}
input {
padding: 10px;
}
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255,255,255,0.66);
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
td {
padding: 0;
}
th, td {
min-width: 120px;
height: 40px;
text-align: right;
}
td input {
width: 100%;
height: 100%;
border: none;
text-align: right;
padding: 10px;
box-sizing: border-box;
font-size: 13px;
}
.green {
color: green;
}
.red {
color: red;
}
}
}
Babel + JSX
let metrics = ['Feb 2017', 'Mar 2017', 'Apr 2017', 'May 2017'].map(m => ({
month: m,
revenue: Math.round(20000 * Math.random()),
costs: Math.round(20000 * Math.random()),
income: Math.round(20000 * Math.random()),
cash: Math.round(20000 * Math.random()),
customers: Math.round(20000 * Math.random()),
sold: Math.round(20000 * Math.random())
}))
new Vue({
data: {
metrics
},
computed: {
diff () {
const lastMetric = this.metrics[this.metrics.length - 1]
const prevMetric = this.metrics[this.metrics.length - 2]
return Object.keys(lastMetric).reduce((acc, key) => {
return {
name: `${prevMetric.month}-${lastMetric.month}`,
...acc,
[key]: Math.round((lastMetric[key] - prevMetric[key]) / prevMetric[key] * 100)
}
})
}
},
methods: {
getClass (v) {
return v > 0 ? 'green' : 'red'
},
addMonth (e) {
this.metrics.push({
month: e.target.value,
revenue: Math.round(20000 * Math.random()),
costs: Math.round(20000 * Math.random()),
income: Math.round(20000 * Math.random()),
cash: Math.round(20000 * Math.random()),
customers: Math.round(20000 * Math.random()),
sold: Math.round(20000 * Math.random())
})
}
}
}).$mount('#app')