Feat: initial proof of concept
This commit is contained in:
parent
1414e378aa
commit
608f6b9590
15 changed files with 184 additions and 0 deletions
28
index.css
Normal file
28
index.css
Normal file
|
@ -0,0 +1,28 @@
|
|||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.timer {
|
||||
font-size: 8em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.timer.over {
|
||||
color: #0f0;
|
||||
animation: blinker 2s ease infinite;
|
||||
}
|
||||
|
||||
main {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
main > div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
48
index.html
Normal file
48
index.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
||||
<script src="https://unpkg.com/crypto-js@4.1.1/crypto-js.js"></script>
|
||||
|
||||
<script src="js/index.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css" />
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
|
||||
<audio id="sound-0" src="sound/0.mp3" preload="auto"></audio>
|
||||
<audio id="sound-1" src="sound/1.mp3" preload="auto"></audio>
|
||||
<audio id="sound-2" src="sound/2.mp3" preload="auto"></audio>
|
||||
<audio id="sound-3" src="sound/3.mp3" preload="auto"></audio>
|
||||
<audio id="sound-4" src="sound/4.mp3" preload="auto"></audio>
|
||||
<audio id="sound-5" src="sound/5.mp3" preload="auto"></audio>
|
||||
<audio id="sound-6" src="sound/6.mp3" preload="auto"></audio>
|
||||
<audio id="sound-7" src="sound/7.mp3" preload="auto"></audio>
|
||||
<audio id="sound-8" src="sound/8.mp3" preload="auto"></audio>
|
||||
<audio id="sound-9" src="sound/9.mp3" preload="auto"></audio>
|
||||
<audio id="sound-ok-ready-go" src="sound/ok-ready-go.mp3" preload="auto"></audio>
|
||||
<audio id="sound-silence" src="sound/silence.mp3" preload="auto"></audio>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="container">
|
||||
<div x-data>
|
||||
<div @click="$store.localState.next()">
|
||||
|
||||
|
||||
<hgroup>
|
||||
<h1>OK! .. READY! ... GO!</h1>
|
||||
<h2 x-text="$store.localState.stateHint"></h2>
|
||||
</hgroup>
|
||||
|
||||
<div x-data="Timer">
|
||||
<p :class="'timer' + (over ? ' over':'')"
|
||||
x-text="time + 's'"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
108
js/index.js
Normal file
108
js/index.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
async function play() {
|
||||
const number = document.getElementById("number").value;
|
||||
sayNumber(number);
|
||||
}
|
||||
|
||||
async function sayNumber(number) {
|
||||
console.log(number)
|
||||
number = number.toString();
|
||||
number = number.replace(/[^0-9]/, "");
|
||||
for(let i = 0; i < number.length; i++) {
|
||||
await playAudio(document.getElementById(`sound-${number[i]}`));
|
||||
}
|
||||
}
|
||||
|
||||
function playAudio(audio){
|
||||
return new Promise(res=>{
|
||||
audio.play()
|
||||
audio.onended = res
|
||||
})
|
||||
}
|
||||
|
||||
function Timer() {
|
||||
return {
|
||||
time: 0,
|
||||
over: false,
|
||||
init() {
|
||||
setInterval(() => {
|
||||
const startedAt = Alpine.store("localState").startedAt;
|
||||
const resultTime = Alpine.store("localState").time;
|
||||
|
||||
let time;
|
||||
if (!startedAt && !resultTime) {
|
||||
time = 0;
|
||||
this.over = false;
|
||||
} else if (resultTime) {
|
||||
time = (resultTime / 1000);
|
||||
this.over = true;
|
||||
} else {
|
||||
this.over = false;
|
||||
time =
|
||||
((new Date().getTime() - startedAt) / 1000)
|
||||
;
|
||||
}
|
||||
|
||||
this.time = time.toFixed(2)
|
||||
}, 10);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
|
||||
Alpine.store("localState", {
|
||||
_state: 0,
|
||||
// 0: idle
|
||||
// 1: starting
|
||||
// 2: running
|
||||
// 3: stopped
|
||||
|
||||
startedAt: null,
|
||||
time: null,
|
||||
stateHint: "",
|
||||
|
||||
init() {
|
||||
Alpine.effect(() => {
|
||||
switch(this._state) {
|
||||
case 0: {
|
||||
this.startedAt = null;
|
||||
this.time = null;
|
||||
this.stateHint = "Tap to start";
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
this.stateHint = "Get ready..."
|
||||
playAudio(document.getElementById("sound-ok-ready-go")).then(() => {
|
||||
Alpine.store("localState")._state = 2;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
this.stateHint = "Tap to stop"
|
||||
this.startedAt = new Date().getTime() - 200;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
this.stateHint = "Tap to reset"
|
||||
this.time = new Date().getTime() - this.startedAt;
|
||||
sayNumber((this.time / 1000).toFixed(2));
|
||||
this.startedAt = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
next() {
|
||||
console.log("next");
|
||||
playAudio(document.getElementById("sound-silence"))
|
||||
|
||||
if(this._state == 1) return;
|
||||
|
||||
this._state = (this._state + 1) % 4
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
BIN
sound/0.mp3
Normal file
BIN
sound/0.mp3
Normal file
Binary file not shown.
BIN
sound/1.mp3
Normal file
BIN
sound/1.mp3
Normal file
Binary file not shown.
BIN
sound/2.mp3
Normal file
BIN
sound/2.mp3
Normal file
Binary file not shown.
BIN
sound/3.mp3
Normal file
BIN
sound/3.mp3
Normal file
Binary file not shown.
BIN
sound/4.mp3
Normal file
BIN
sound/4.mp3
Normal file
Binary file not shown.
BIN
sound/5.mp3
Normal file
BIN
sound/5.mp3
Normal file
Binary file not shown.
BIN
sound/6.mp3
Normal file
BIN
sound/6.mp3
Normal file
Binary file not shown.
BIN
sound/7.mp3
Normal file
BIN
sound/7.mp3
Normal file
Binary file not shown.
BIN
sound/8.mp3
Normal file
BIN
sound/8.mp3
Normal file
Binary file not shown.
BIN
sound/9.mp3
Normal file
BIN
sound/9.mp3
Normal file
Binary file not shown.
BIN
sound/ok-ready-go.mp3
Normal file
BIN
sound/ok-ready-go.mp3
Normal file
Binary file not shown.
BIN
sound/silence.mp3
Normal file
BIN
sound/silence.mp3
Normal file
Binary file not shown.
Loading…
Reference in a new issue