ncounter.git

git clone https://git.crispbyte.dev/ncounter.git

commit
fdbc654
parent
76557c7
author
CheddarCrisp
date
2020-02-16 19:56:38 +0100 CET
Add history display
6 files changed,  +220, -19
M package-lock.json
+35, -0
 1@@ -907,6 +907,35 @@
 2         "supports-color": "^5.3.0"
 3       }
 4     },
 5+    "chart.js": {
 6+      "version": "2.9.3",
 7+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
 8+      "integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
 9+      "dev": true,
10+      "requires": {
11+        "chartjs-color": "^2.1.0",
12+        "moment": "^2.10.2"
13+      }
14+    },
15+    "chartjs-color": {
16+      "version": "2.4.1",
17+      "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
18+      "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
19+      "dev": true,
20+      "requires": {
21+        "chartjs-color-string": "^0.6.0",
22+        "color-convert": "^1.9.3"
23+      }
24+    },
25+    "chartjs-color-string": {
26+      "version": "0.6.0",
27+      "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
28+      "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
29+      "dev": true,
30+      "requires": {
31+        "color-name": "^1.0.0"
32+      }
33+    },
34     "chokidar": {
35       "version": "2.1.6",
36       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
37@@ -3828,6 +3857,12 @@
38         }
39       }
40     },
41+    "moment": {
42+      "version": "2.24.0",
43+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
44+      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
45+      "dev": true
46+    },
47     "move-concurrently": {
48       "version": "1.0.1",
49       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
M package.json
+1, -0
1@@ -12,6 +12,7 @@
2   "license": "MIT",
3   "devDependencies": {
4     "@beyonk/google-fonts-webpack-plugin": "^1.2.3",
5+    "chart.js": "^2.9.3",
6     "clean-webpack-plugin": "^3.0.0",
7     "css-loader": "^3.4.2",
8     "google-fonts-webpack-plugin": "^0.4.4",
M src/ncounter/App.svelte
+13, -8
 1@@ -2,8 +2,8 @@
 2 {#each $counters as counter}
 3 <Counter counterId={ counter.id }></Counter>
 4 {/each}
 5-</div>
 6 <button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
 7+</div>
 8 {#if showAddDialog}
 9 <div class="dialog">
10     <div class="dialog-content">
11@@ -60,6 +60,8 @@ function add(){
12         bottom: 15px;
13         right: 15px;
14 
15+        z-index: 2;
16+
17         background-color: #90C090;
18         border-radius: 50%;
19 
20@@ -72,13 +74,16 @@ function add(){
21         margin-left: auto;
22     }
23 
24-    .dialog-content button {
25-        padding: 10px;
26-        font-size: 14px;
27-        font-weight: 600;
28-    }
29-
30     .app {
31-        padding: 5px 5px 60px 5px;
32+        padding: 5px;
33+        position: fixed;
34+        top: 0;
35+        right: 0;
36+        bottom: 0;
37+        left: 0;
38+
39+        z-index: 1;
40+
41+        overflow: auto;
42     }
43 </style>
M src/ncounter/Counter.svelte
+22, -11
 1@@ -7,8 +7,11 @@
 2     <div class="controls">
 3         <button on:click={ () => { showIncrement = true; } }><i class="material-icons">add</i></button>
 4         <button on:click={ () => { showSet = true; } }><i class="material-icons">edit</i></button>
 5-        <button class="reset" on:click={ reset }><i class="material-icons">undo</i></button>
 6-        <button on:click={ startEdit }><i class="material-icons">edit</i></button>
 7+        <button class="reset" on:click={ reset }><i class="material-icons">replay</i></button>
 8+        {#if counter.saveHistory}
 9+        <button class="history" on:click={ () => { showHistory = true; } }><i class="material-icons">show_chart</i></button>
10+        {/if}
11+        <button on:click={ startEdit }><i class="material-icons">settings</i></button>
12         <button on:click={ remove }><i class="material-icons">delete</i></button>
13     </div>
14     {#if showValueDialog}
15@@ -33,15 +36,16 @@
16         </div>
17     </div>
18     {/if}
19+    {#if showHistory}
20+    <History { counterId } on:close={ () => { showHistory = false; } }></History>
21+    {/if}
22 </div>
23 <script>
24 import MyProgress from './MyProgress.svelte';
25+import History from './History.svelte';
26 import { tick } from 'svelte';
27-import { createEventDispatcher } from 'svelte';
28 import { counters } from './db.js';
29 
30-const dispatch = createEventDispatcher();
31-
32 export let counterId;
33 
34 $: counter = $counters.find(x => x.id == counterId);
35@@ -51,6 +55,7 @@ let showIncrement;
36 let showSet;
37 let showEditDialog;
38 let editingCounter;
39+let showHistory;
40 
41 $: showValueDialog = showIncrement || showSet;
42 
43@@ -125,6 +130,10 @@ function remove(){
44     padding: 5px;
45 }
46 
47+.counter:last-child {
48+    margin-bottom: 72px;
49+}
50+
51 .controls {
52     display: flex;
53 }
54@@ -142,9 +151,17 @@ header {
55 }
56 
57 .reset {
58+    margin-left: 24px;
59+}
60+
61+.reset + button {
62     margin-left: auto;
63 }
64 
65+.history {
66+    margin-right: 24px;
67+}
68+
69 .dialog-value {
70     width: 100%;
71     margin: 5px 0;
72@@ -153,10 +170,4 @@ header {
73 .ok {
74     margin-left: auto;
75 }
76-
77-.dialog-content button {
78-    padding: 10px;
79-    font-size: 14px;
80-    font-weight: 600;
81-}
82 </style>
A src/ncounter/History.svelte
+143, -0
  1@@ -0,0 +1,143 @@
  2+<div class="history-container">
  3+    <header>
  4+        <h1>{ counter.title }</h1>
  5+        <button class="close" on:click={ close }><i class="material-icons">close</i></button>
  6+    </header>
  7+    <canvas class="chart-container" bind:this={ chartEl } width="{ window.outerWidth }" height="250">
  8+    </canvas>
  9+    <div class="table-container">
 10+        <table class="history">
 11+            <thead>
 12+                <tr>
 13+                    <th>Time</th>
 14+                    <th>Value</th>
 15+                </tr>
 16+            </thead>
 17+            <tbody>
 18+            {#each history as data}
 19+                <tr>
 20+                    <td>{ data.time }</td>
 21+                    <td>{ data.value }</td>
 22+                </tr>
 23+            {/each}
 24+            </tbody>
 25+        </table>
 26+    </div>
 27+</div>
 28+<script>
 29+import { createEventDispatcher } from 'svelte';
 30+import { counters } from './db.js';
 31+import Chart from 'chart.js';
 32+
 33+const dispatch = createEventDispatcher();
 34+
 35+const formatter = new Intl.DateTimeFormat('en-US',
 36+        {
 37+            month: 'short',
 38+            day: 'numeric',
 39+            year: 'numeric',
 40+            hour: 'numeric',
 41+            minute: 'numeric'
 42+        });
 43+
 44+$: counter = $counters.find(x => x.id == counterId);
 45+$: history = counter.history.map(x => {
 46+    return {
 47+        time: formatter.format(x.time),
 48+        value: x.value
 49+    }
 50+});
 51+$: dataset = counter.history.reduce((acc, x) => {
 52+    return {
 53+        labels: [...acc.labels, x.time],
 54+        datasets: [
 55+            {
 56+                data: [...acc.datasets[0].data, x.value]
 57+            }
 58+        ]
 59+    }
 60+}, {
 61+    labels: [],
 62+    datasets: [
 63+        {
 64+            data: []
 65+        }
 66+    ]
 67+});
 68+
 69+export let counterId;
 70+
 71+let chartEl;
 72+
 73+$: {
 74+    if(chartEl){
 75+        new Chart(chartEl, {
 76+            type: 'line',
 77+            data: dataset,
 78+            options: {
 79+                scales: {
 80+                    xAxes: [
 81+                        {
 82+                            type: 'time'
 83+                        }
 84+                    ]
 85+                },
 86+                legend: {
 87+                    display: false
 88+                }
 89+            }
 90+        });
 91+    }
 92+}
 93+
 94+function close(){
 95+    dispatch('close');
 96+}
 97+</script>
 98+<style>
 99+    .history-container{
100+        background-color: white;
101+        position: fixed;
102+        top: 0;
103+        right: 0;
104+        bottom: 0;
105+        left: 0;
106+        z-index: 3;
107+
108+        display: flex;
109+        flex-direction: column;
110+        align-items: stretch;
111+
112+        overflow: auto;
113+    }
114+
115+    header {
116+        display: flex;
117+    }
118+
119+    header h1 {
120+        font-size: 22px;
121+        font-weight: 600;
122+        margin: 5px;
123+    }
124+
125+    .table-container {
126+        position: relative;
127+    }
128+
129+    .close {
130+        margin-left: auto;
131+    }
132+
133+    .history th {
134+        font-weight: 600;
135+        position: sticky;
136+        background-color: white;
137+        top: 0;
138+    }
139+
140+    .history th, .history td {
141+        border: 1px solid black;
142+        padding: 5px;
143+    }
144+</style>
M src/ncounter/site.css
+6, -0
 1@@ -70,6 +70,12 @@ button {
 2     margin-left: auto;
 3 }
 4 
 5+.dialog-content button {
 6+    padding: 10px;
 7+    font-size: 14px;
 8+    font-weight: 600;
 9+}
10+
11 input[type="text"],
12 input[type="number"] {
13     font-size: 16px;