Initial checkin
This commit is contained in:
parent
260fdfc0a2
commit
aace75679a
12 changed files with 5726 additions and 1 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
2
LICENSE
2
LICENSE
|
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
52
dist/index.html
vendored
Normal file
52
dist/index.html
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<title>NCounter</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
background-color: rgba(0,0,0,0.25);
|
||||||
|
|
||||||
|
z-index: 12;
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
background-color: #E0E0E0;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
width: 250px;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
dist/index.js
vendored
Normal file
1
dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5364
package-lock.json
generated
Normal file
5364
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
20
package.json
Normal file
20
package.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "ncounter",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"build": "webpack",
|
||||||
|
"start": "webpack-dev-server --open"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"svelte": "^3.4.1",
|
||||||
|
"svelte-loader": "^2.13.4",
|
||||||
|
"webpack": "^4.31.0",
|
||||||
|
"webpack-cli": "^3.3.2",
|
||||||
|
"webpack-dev-server": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
3
src/index.js
Normal file
3
src/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import App from './ncounter/App.svelte';
|
||||||
|
|
||||||
|
new App({ target: document.body });
|
110
src/ncounter/App.svelte
Normal file
110
src/ncounter/App.svelte
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<div class="app">
|
||||||
|
{#each counters as counter}
|
||||||
|
<Counter counter={ counter } on:save={() => { save(counter); } }></Counter>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
|
||||||
|
{#if showAddDialog}
|
||||||
|
<div class="dialog">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<label>Name: <input type="text" bind:value={newCounter.title} use:focus/></label>
|
||||||
|
<label>Initial Value: <input type="number" bind:value={newCounter.value} /></label>
|
||||||
|
<label>Target: <input type="number" bind:value={newCounter.max} /></label>
|
||||||
|
<label>Click counter: <input type="checkbox" bind:value={newCounter.isClickCounter} /></label>
|
||||||
|
<button on:click={ () => { showAddDialog = false; } }>Cancel</button>
|
||||||
|
<button class="ok" on:click={ addCounter }>OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<script>
|
||||||
|
import Counter from './Counter.svelte';
|
||||||
|
|
||||||
|
let showAddDialog = false;
|
||||||
|
|
||||||
|
let newCounter = null;
|
||||||
|
|
||||||
|
let counters = [
|
||||||
|
{
|
||||||
|
title: 'Test 1',
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Test 2',
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Max Test',
|
||||||
|
value: 0,
|
||||||
|
max: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Click Test',
|
||||||
|
value: 0,
|
||||||
|
isClickCounter: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function focus(node){
|
||||||
|
node.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(counter){
|
||||||
|
alert('Save ' + counter.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAdd(){
|
||||||
|
newCounter = {
|
||||||
|
title: '',
|
||||||
|
value: 0,
|
||||||
|
isClickCounter: false
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({ newCounter });
|
||||||
|
|
||||||
|
showAddDialog = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCounter(){
|
||||||
|
counters = [...counters, newCounter];
|
||||||
|
|
||||||
|
showAddDialog = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.add {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 15px;
|
||||||
|
right: 15px;
|
||||||
|
|
||||||
|
background-color: #90C090;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content > label {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content > label > input {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content button {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app {
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
112
src/ncounter/Counter.svelte
Normal file
112
src/ncounter/Counter.svelte
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<div class="counter" on:click="{ clickCount }">
|
||||||
|
<header>{ counter.title }</header>
|
||||||
|
<span class="value">{ counter.value }</span>
|
||||||
|
{#if counter.max}
|
||||||
|
<MyProgress value={ counter.value } max={ counter.max }></MyProgress>
|
||||||
|
{/if}
|
||||||
|
<div class="controls">
|
||||||
|
{#if !counter.isClickCounter}
|
||||||
|
<button on:click={ () => { showIncrement = true; } }><i class="material-icons">add</i></button>
|
||||||
|
{/if}
|
||||||
|
<button class="reset" on:click={ reset }><i class="material-icons">undo</i></button>
|
||||||
|
<button on:click={ save }><i class="material-icons">save</i></button>
|
||||||
|
</div>
|
||||||
|
{#if showIncrement}
|
||||||
|
<div class="dialog">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<input class="increment-value" type="number" bind:value={ incrementValue } use:focus />
|
||||||
|
<button on:click={ () => { showIncrement = false; } }>Cancel</button>
|
||||||
|
<button class="ok" on:click={ increment }>OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
import MyProgress from './MyProgress.svelte';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let counter;
|
||||||
|
|
||||||
|
let incrementValue;
|
||||||
|
let showIncrement;
|
||||||
|
|
||||||
|
function focus(node){
|
||||||
|
node.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment(){
|
||||||
|
counter.value += incrementValue;
|
||||||
|
showIncrement = false;
|
||||||
|
incrementValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if(confirm(`Reset ${counter.title}?`))
|
||||||
|
counter.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
dispatch('save');
|
||||||
|
counter.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickCount() {
|
||||||
|
if(!counter.isClickCounter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
counter.value++;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.counter{
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.increment-value {
|
||||||
|
width: 100%;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content button {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
40
src/ncounter/MyProgress.svelte
Normal file
40
src/ncounter/MyProgress.svelte
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<div class="progress-bar">
|
||||||
|
<span class="progress" {style}></span>
|
||||||
|
<span class="text">{value} / {max}</span>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
export let value;
|
||||||
|
export let max;
|
||||||
|
|
||||||
|
$: style = `width: ${(Math.min(1, value / max) * 100)}%`;
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.progress-bar {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
margin: 3px 0;
|
||||||
|
|
||||||
|
background-color: #F0F0F0;
|
||||||
|
border: 1px solid black;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .progress {
|
||||||
|
display: block;
|
||||||
|
background-color: #C0CFC0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar > .text {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
0
src/ncounter/store.js
Normal file
0
src/ncounter/store.js
Normal file
22
webpack.config.js
Normal file
22
webpack.config.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.js',
|
||||||
|
output: {
|
||||||
|
filename: 'index.js',
|
||||||
|
path: path.resolve(__dirname, 'dist')
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: './dist'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.svelte$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'svelte-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
devtool: 'inline-source-map'
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue