- commit
- 67a40cf
- parent
- a291d68
- author
- CheddarCrisp
- date
- 2020-02-28 16:00:41 +0100 CET
Redesign UI to add some color, eliminate the FAB, and make dialogs look better Add an about page
9 files changed,
+318,
-51
+104,
-0
1@@ -2767,6 +2767,15 @@
2 "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=",
3 "dev": true
4 },
5+ "get-npm-tarball-url": {
6+ "version": "2.0.1",
7+ "resolved": "https://registry.npmjs.org/get-npm-tarball-url/-/get-npm-tarball-url-2.0.1.tgz",
8+ "integrity": "sha512-POrVRGyS9X5w+855/H46JGVYBGuVgJXyIkbsTCzW+sv5x2qH+rfQjc7652DzkgOskF+cqLevA2En7V0hu0gZCg==",
9+ "dev": true,
10+ "requires": {
11+ "normalize-registry-url": "^1.0.0"
12+ }
13+ },
14 "get-stream": {
15 "version": "4.1.0",
16 "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
17@@ -3925,6 +3934,34 @@
18 "to-regex": "^3.0.1"
19 }
20 },
21+ "needle": {
22+ "version": "2.3.2",
23+ "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.2.tgz",
24+ "integrity": "sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w==",
25+ "dev": true,
26+ "requires": {
27+ "debug": "^3.2.6",
28+ "iconv-lite": "^0.4.4",
29+ "sax": "^1.2.4"
30+ },
31+ "dependencies": {
32+ "debug": {
33+ "version": "3.2.6",
34+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
35+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
36+ "dev": true,
37+ "requires": {
38+ "ms": "^2.1.1"
39+ }
40+ },
41+ "ms": {
42+ "version": "2.1.2",
43+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
44+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
45+ "dev": true
46+ }
47+ }
48+ },
49 "negotiator": {
50 "version": "0.6.2",
51 "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
52@@ -4013,6 +4050,12 @@
53 "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
54 "dev": true
55 },
56+ "normalize-registry-url": {
57+ "version": "1.0.0",
58+ "resolved": "https://registry.npmjs.org/normalize-registry-url/-/normalize-registry-url-1.0.0.tgz",
59+ "integrity": "sha512-0v6T4851b72ykk5zEtFoN4QX/Fqyk7pouIj9xZyAvAe9jlDhAwT4z6FlwsoQCHjeuK2EGUoAwy/F4y4B1uZq9A==",
60+ "dev": true
61+ },
62 "npm-run-path": {
63 "version": "2.0.2",
64 "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
65@@ -4857,6 +4900,12 @@
66 "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=",
67 "dev": true
68 },
69+ "sax": {
70+ "version": "1.2.4",
71+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
72+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
73+ "dev": true
74+ },
75 "schema-utils": {
76 "version": "1.0.0",
77 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
78@@ -5258,6 +5307,37 @@
79 "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
80 "dev": true
81 },
82+ "spdx-exceptions": {
83+ "version": "2.2.0",
84+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
85+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
86+ "dev": true
87+ },
88+ "spdx-expression-parse": {
89+ "version": "3.0.0",
90+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
91+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
92+ "dev": true,
93+ "requires": {
94+ "spdx-exceptions": "^2.1.0",
95+ "spdx-license-ids": "^3.0.0"
96+ }
97+ },
98+ "spdx-expression-validate": {
99+ "version": "2.0.0",
100+ "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz",
101+ "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==",
102+ "dev": true,
103+ "requires": {
104+ "spdx-expression-parse": "^3.0.0"
105+ }
106+ },
107+ "spdx-license-ids": {
108+ "version": "3.0.5",
109+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
110+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
111+ "dev": true
112+ },
113 "spdy": {
114 "version": "4.0.0",
115 "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz",
116@@ -5414,6 +5494,16 @@
117 "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
118 "dev": true
119 },
120+ "string-replace-loader": {
121+ "version": "2.2.0",
122+ "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-2.2.0.tgz",
123+ "integrity": "sha512-Ukt4ZC8+xVWdBRut3/iwnPJCNL1yV8AbVKXn8UcWdYrHgtuW4UDDAbBSi/J/CQDEWQBt824AJvPYahF23eJLRg==",
124+ "dev": true,
125+ "requires": {
126+ "loader-utils": "^1.2.3",
127+ "schema-utils": "^1.0.0"
128+ }
129+ },
130 "string-width": {
131 "version": "2.1.1",
132 "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
133@@ -6125,6 +6215,20 @@
134 }
135 }
136 },
137+ "webpack-license-plugin": {
138+ "version": "4.1.1",
139+ "resolved": "https://registry.npmjs.org/webpack-license-plugin/-/webpack-license-plugin-4.1.1.tgz",
140+ "integrity": "sha512-CYqPx4f8e7thGIrv5aruoUAF8sTw94o3dGhZbALc4szYIjdQPGLO3lCB/YLUj7UaI+JJeuboVz0lu3QPx5k+ZA==",
141+ "dev": true,
142+ "requires": {
143+ "chalk": "^2.4.1",
144+ "get-npm-tarball-url": "^2.0.1",
145+ "lodash": "^4.17.10",
146+ "needle": "^2.2.4",
147+ "spdx-expression-validate": "^2.0.0",
148+ "webpack-sources": "^1.3.0"
149+ }
150+ },
151 "webpack-log": {
152 "version": "2.0.0",
153 "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
+2,
-0
1@@ -20,6 +20,7 @@
2 "idb-keyval": "^3.2.0",
3 "reset-css": "^5.0.1",
4 "serviceworker-webpack-plugin": "^1.0.1",
5+ "string-replace-loader": "^2.2.0",
6 "style-loader": "^1.1.3",
7 "svelte": "^3.4.1",
8 "svelte-loader": "^2.13.4",
9@@ -27,6 +28,7 @@
10 "webpack": "^4.31.0",
11 "webpack-cli": "^3.3.2",
12 "webpack-dev-server": "^3.4.1",
13+ "webpack-license-plugin": "^4.1.1",
14 "webpack-merge": "^4.2.2",
15 "workbox-cacheable-response": "^5.0.0",
16 "workbox-expiration": "^5.0.0",
+64,
-0
1@@ -0,0 +1,64 @@
2+<div class="about">
3+ <button class="close" on:click={ () => { dispatch('close'); } }><i class="material-icons">close</i></button>
4+ <header>
5+ <h1>NCounter</h1>
6+ <h2>Release |BUILD_DATE|</h2>
7+ <h2>© |BUILD_YEAR|</h2>
8+ </header>
9+ <div class="licenses">
10+ <h2>Open Source License Information</h2>
11+ <Licenses></Licenses>
12+ </div>
13+</div>
14+<script>
15+import Licenses from './Licenses.svelte';
16+import { createEventDispatcher } from 'svelte';
17+const dispatch = createEventDispatcher();
18+</script>
19+<style>
20+.about {
21+ background-color: white;
22+ position: fixed;
23+ top: 0;
24+ right: 0;
25+ bottom: 0;
26+ left: 0;
27+ z-index: 3;
28+
29+ display: flex;
30+ flex-direction: column;
31+ align-items: stretch;
32+
33+ overflow: auto;
34+
35+ padding: 5px;
36+}
37+
38+.about > header {
39+ flex: center;
40+ text-align: center;
41+}
42+
43+h1 {
44+ font-weight: 600;
45+ font-size: 24px;
46+}
47+
48+h2 {
49+ font-size: 18px;
50+}
51+
52+.licenses h2{
53+ font-weight: 600;
54+}
55+
56+.close {
57+ position: absolute;
58+ top: 15px;
59+ right: 15px;
60+}
61+
62+.licenses {
63+ margin-top: 32px;
64+}
65+</style>
+51,
-32
1@@ -1,27 +1,36 @@
2 <div class="app">
3-<button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
4-{#each $counters as counter}
5-<Counter counterId={ counter.id }></Counter>
6-{/each}
7+ <div class="counter-list">
8+ {#each $counters as counter}
9+ <Counter counterId={ counter.id }></Counter>
10+ {/each}
11+ </div>
12+ <div class="tool-bar">
13+ <button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
14+ <button class="about" on:click="{ () => { showAbout = true; } }">?</button>
15+ </div>
16 </div>
17 {#if showAddDialog}
18 <div class="dialog">
19 <div class="dialog-content">
20- <label>Name: <input type="text" bind:value={newCounter.title} use:focus/></label>
21- <label>Initial Value: <input type="number" bind:value={newCounter.initialValue} /></label>
22- <label>Target: <input type="number" bind:value={newCounter.max} /></label>
23- <label>Save history: <input type="checkbox" bind:checked={newCounter.saveHistory} /></label>
24+ <label>Name<input type="text" bind:value={newCounter.title} use:focus/></label>
25+ <label>Initial Value<input type="number" bind:value={newCounter.initialValue} /></label>
26+ <label>Target<input type="number" bind:value={newCounter.max} /></label>
27+ <label>Save history<input type="checkbox" bind:checked={newCounter.saveHistory} /></label>
28 <button on:click={ () => { showAddDialog = false; } }>Cancel</button>
29 <button class="ok" on:click={ add }>OK</button>
30 </div>
31 </div>
32 {/if}
33+{#if showAbout}
34+<About on:close="{ () => { showAbout = false; } }"></About>
35+{/if}
36 <script>
37+import About from './About.svelte';
38 import Counter from './Counter.svelte';
39 import { counters } from './db.js';
40
41 let showAddDialog = false;
42-
43+let showAbout = false;
44 let newCounter = null;
45
46 function focus(node){
47@@ -50,34 +59,16 @@ function add(){
48 showAddDialog = false;
49 }
50 </script>
51-<style>
52- .add {
53- display: flex;
54- align-items: center;
55- justify-content: center;
56-
57- position: fixed;
58- bottom: 15px;
59- right: 15px;
60-
61- z-index: 2;
62-
63- background-color: #90C090;
64- border-radius: 50%;
65-
66- box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
67-
68- width: 40px;
69- height: 40px;
70- color: white;
71- }
72-
73+<style lang="scss">
74 .ok {
75 margin-left: auto;
76 }
77
78 .app {
79- padding: 5px;
80+ display: flex;
81+ flex-direction: column;
82+ align-items: stretch;
83+
84 position: fixed;
85 top: 0;
86 right: 0;
87@@ -85,7 +76,35 @@ function add(){
88 left: 0;
89
90 z-index: 1;
91+ }
92
93+ .counter-list {
94+ padding: 5px;
95 overflow: auto;
96+ flex: 1 0 0;
97+
98+ background-color: #8baec6;
99+ }
100+
101+ .tool-bar {
102+ flex: none;
103+
104+ display: flex;
105+
106+ border-top: 2px solid #3A86B7;
107+ }
108+
109+ .tool-bar > button {
110+ background-color: #3A86B7;
111+ color: white;
112+ }
113+
114+ .tool-bar > button:focus, .tool-bar > button:hover {
115+ border: 2px solid #303030;
116+ }
117+
118+ .about {
119+ margin-left: auto;
120+ font-size: 20px;
121 }
122 </style>
+10,
-11
1@@ -27,10 +27,10 @@
2 {#if showEditDialog}
3 <div class="dialog">
4 <div class="dialog-content">
5- <label>Name: <input type="text" bind:value={editingCounter.title} use:focus/></label>
6- <label>Initial Value: <input type="number" bind:value={editingCounter.initialValue} /></label>
7- <label>Target: <input type="number" bind:value={editingCounter.max} /></label>
8- <label>Save history: <input type="checkbox" bind:checked={editingCounter.saveHistory} /></label>
9+ <label>Name<input type="text" bind:value={editingCounter.title} use:focus/></label>
10+ <label>Initial Value<input type="number" bind:value={editingCounter.initialValue} /></label>
11+ <label>Target<input type="number" bind:value={editingCounter.max} /></label>
12+ <label>Save history<input type="checkbox" bind:checked={editingCounter.saveHistory} /></label>
13 <button on:click={ () => { showEditDialog = false; } }>Cancel</button>
14 <button class="ok" on:click={ finishEdit }>OK</button>
15 </div>
16@@ -122,7 +122,10 @@ function remove(){
17 <style>
18 .counter{
19 box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
20- margin-bottom: 12px;
21+
22+ background-color: #FCFCFC;
23+
24+ margin-bottom: 4px;
25
26 display: flex;
27 flex-direction: column;
28@@ -130,10 +133,6 @@ function remove(){
29 padding: 5px;
30 }
31
32-.counter:last-child {
33- margin-bottom: 72px;
34-}
35-
36 .controls {
37 display: flex;
38 }
39@@ -151,7 +150,7 @@ header {
40 }
41
42 .reset {
43- margin-left: 24px;
44+ margin-left: 12px;
45 }
46
47 .reset + button {
48@@ -159,7 +158,7 @@ header {
49 }
50
51 .history {
52- margin-right: 24px;
53+ margin-right: 12px;
54 }
55
56 .dialog-value {
+2,
-2
1@@ -107,8 +107,6 @@ function close(){
2 display: flex;
3 flex-direction: column;
4 align-items: stretch;
5-
6- overflow: auto;
7 }
8
9 header {
10@@ -124,6 +122,8 @@ function close(){
11
12 .table-container {
13 position: relative;
14+
15+ overflow: auto;
16 }
17
18 .close {
+39,
-0
1@@ -0,0 +1,39 @@
2+<div>
3+ {#each licenses as license}
4+ <header>
5+ <h1>{license.name} by {license.author}</h1>
6+ <div>Source: <a href="{license.repository}" target="_blank">{license.repository}</a></div>
7+ </header>
8+ <pre>{license.licenseText}</pre>
9+ {/each}
10+ {#if !licenses}
11+ <progress></progress>
12+ {/if}
13+</div>
14+<script>
15+let licenses = [];
16+
17+(async () => {
18+ licenses = await fetch('oss-licenses.json')
19+ .then(response => {
20+ if(response.ok)
21+ return response.json();
22+ });
23+})();
24+</script>
25+<style>
26+header {
27+ margin-top: 12px;
28+}
29+
30+header h1 {
31+ font-weight: 600;
32+}
33+
34+pre {
35+ margin: 5px;
36+ padding: 5px;
37+ white-space: pre-wrap;
38+ background-color: #F0F0F0;
39+}
40+</style>
+31,
-4
1@@ -25,7 +25,21 @@ body {
2 button {
3 background: 0;
4 border: 0;
5+
6+ width: 36px;
7 height: 36px;
8+
9+ display: flex;
10+ align-items: center;
11+ justify-content: center;
12+
13+ cursor: pointer;
14+
15+ font-family: inherit;
16+}
17+
18+button:focus, button:hover {
19+ border: 2px solid #3A86B7;
20 }
21
22 .dialog {
23@@ -47,14 +61,13 @@ button {
24 }
25
26 .dialog-content {
27- background-color: #E0E0E0;
28+ background-color: #FCFCFC;
29 pointer-events: all;
30
31- width: 300px;
32+ width: 315px;
33
34- border-radius: 5px;
35 box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
36- padding: 5px;
37+ padding: 10px;
38
39 display: flex;
40 flex-wrap: wrap;
41@@ -64,16 +77,30 @@ button {
42 display: flex;
43 width: 100%;
44 margin-bottom: 5px;
45+ align-items: center;
46+ height: 26px;
47+ font-weight: 600;
48 }
49
50 .dialog-content > label > input {
51 margin-left: auto;
52 }
53
54+.dialog-content input[type='text'], .dialog-content input[type='number'] {
55+ width: 175px;
56+}
57+
58 .dialog-content button {
59 padding: 10px;
60 font-size: 14px;
61 font-weight: 600;
62+
63+ width: auto;
64+}
65+
66+.dialog-content button:focus, .dialog-content button:hover {
67+ border: 0;
68+ outline: 2px solid #3A86B7;
69 }
70
71 input[type="text"],
+15,
-2
1@@ -3,6 +3,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
2 const GoogleFontsPlugin = require('@beyonk/google-fonts-webpack-plugin');
3 const { CleanWebpackPlugin } = require('clean-webpack-plugin');
4 const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin');
5+const LicensePlugin = require('webpack-license-plugin');
6
7 module.exports = {
8 entry: './src/index.js',
9@@ -21,7 +22,8 @@ module.exports = {
10 new ServiceWorkerWebpackPlugin({
11 entry: path.join(__dirname, 'src/sw.js'),
12 publicPath: './'
13- })
14+ }),
15+ new LicensePlugin()
16 ],
17 output: {
18 filename: 'index.js',
19@@ -32,7 +34,18 @@ module.exports = {
20 {
21 test: /\.svelte$/,
22 exclude: /node_modules/,
23- loader: 'svelte-loader'
24+ use: [
25+ 'svelte-loader',
26+ {
27+ loader: 'string-replace-loader',
28+ options: {
29+ multiple: [
30+ { search: '|BUILD_YEAR|', replace: '2020' },
31+ { search: '|BUILD_DATE|', replace: '2020-02-28'}
32+ ]
33+ }
34+ }
35+ ]
36 },
37 {
38 test: /\.css$/,