Add /beeper
This commit is contained in:
parent
2c6402ff4b
commit
a68dd83183
BIN
src/resources/beeping/beep.ogg
Normal file
BIN
src/resources/beeping/beep.ogg
Normal file
Binary file not shown.
47
src/resources/beeping/index.html
Normal file
47
src/resources/beeping/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Beeper!</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script type="text/javascript" src="main.js"></script>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body onload="main()">
|
||||
<div class="content">
|
||||
<p class="timer"><span id="seconds">0</span><span class="timer-milliseconds">.<span id="milliseconds">00</span></span></p>
|
||||
<div class="padding">
|
||||
<p class="inline">Do a beep at </p>
|
||||
<div class="input-container"><button id="minus" class="scroller">-</button><input id="time-input"
|
||||
placeholder="5"></input><button id="plus" class="scroller">+</button></div>
|
||||
<p class="inline">second intervals</p>
|
||||
</div>
|
||||
<p class="padding"><button id="begin">Begin!</button></p>
|
||||
|
||||
<div id="audiocontrols">
|
||||
<div class="inline">
|
||||
<p>Volume (<span id="volume">100</span>%):</p>
|
||||
<input class="padding" id="volume-slider" type="range" min="0" max="100" value="100" class="slider">
|
||||
|
||||
</div>
|
||||
<div class="inline">
|
||||
|
||||
<p>Custom audio file:</p>
|
||||
<input id="file" type="file" accept="audio/*">
|
||||
<p id="audiotext">default audio</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footnote">
|
||||
<p><a href="https://opengameart.org/content/select-beep-and-error">Default beep sound by dklon</a></p>
|
||||
</div>
|
||||
<audio id="audio" controls>
|
||||
<source id="audiosource" src="beep.ogg">
|
||||
</audio>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
160
src/resources/beeping/main.js
Normal file
160
src/resources/beeping/main.js
Normal file
@ -0,0 +1,160 @@
|
||||
var beeperBegun = false;
|
||||
var beepInterval = 0;
|
||||
var beepTimeCounter = 0;
|
||||
var intervalId = 0;
|
||||
var timeChangedWhileBegun = false;
|
||||
var lastSec = -1;
|
||||
|
||||
var showBeep = 0;
|
||||
|
||||
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
|
||||
function main() {
|
||||
timeChanged();
|
||||
updateInvalidness();
|
||||
|
||||
document.getElementById("plus").onclick = () => changeSeconds(1);
|
||||
document.getElementById("minus").onclick = () => changeSeconds(-1);
|
||||
document.getElementById("time-input").onchange = () => {
|
||||
timeChanged();
|
||||
updateInvalidness();
|
||||
};
|
||||
document.getElementById("begin").onclick = toggle;
|
||||
var audio = document.getElementById("audio");
|
||||
let slider = document.getElementById("volume-slider");
|
||||
document.getElementById("volume-slider").onchange = () => {
|
||||
audio.volume = (slider.value / 100);
|
||||
document.getElementById("volume").innerText = slider.value;
|
||||
};
|
||||
|
||||
document.getElementById("file").addEventListener('change', () => {
|
||||
var file = document.getElementById("file").files[0];
|
||||
document.getElementById("audiosource").setAttribute("src", URL.createObjectURL(file));
|
||||
document.getElementById("audio").load();
|
||||
});
|
||||
document.getElementById("audio").addEventListener("loadeddata", (event) => {
|
||||
document.getElementById("audiotext").innerText = "Loaded audio";
|
||||
});
|
||||
document.getElementById("audio").addEventListener("loadstart", (event) => {
|
||||
document.getElementById("audiotext").innerText = "Loading/Error";
|
||||
});
|
||||
|
||||
console.log("Beeper initialized!");
|
||||
}
|
||||
|
||||
function isTimeValid() {
|
||||
value = document.getElementById("time-input").value;
|
||||
if (value != "" && (isNaN(value) || value < 1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
if (!isTimeValid()) {
|
||||
return 1;
|
||||
}
|
||||
value = document.getElementById("time-input").value;
|
||||
if (value == "") {
|
||||
return 5;
|
||||
}
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
|
||||
function updateInvalidness() {
|
||||
input = document.getElementById("time-input");
|
||||
if (!isTimeValid()) {
|
||||
input.classList = "invalid";
|
||||
} else {
|
||||
input.classList = "";
|
||||
}
|
||||
}
|
||||
|
||||
function changeSeconds(diff) {
|
||||
value = document.getElementById("time-input").value;
|
||||
if (!isNaN(value)) {
|
||||
if (value == "") {
|
||||
value = 5;
|
||||
}
|
||||
value = parseFloat(value);
|
||||
if ((value + diff) >= 1 || diff > 0) {
|
||||
input.value = value + diff;
|
||||
updateInvalidness();
|
||||
timeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeChanged() {
|
||||
if (isTimeValid()) {
|
||||
if (beeperBegun) {
|
||||
timeChangedWhileBegun = true;
|
||||
return;
|
||||
}
|
||||
time = getTime();
|
||||
sec = Math.floor(time);
|
||||
millis = Math.floor((time - sec) * 100) / 100;
|
||||
millis = Intl.NumberFormat("en-US", { minimumFractionDigits: 2 }).format(millis);
|
||||
millis = ("" + millis).slice(2);
|
||||
|
||||
seconds = document.getElementById("seconds").innerText = sec;
|
||||
milliseconds = document.getElementById("milliseconds").innerText = millis;
|
||||
|
||||
beepInterval = getTime();
|
||||
beepTimeCounter = beepInterval;
|
||||
}
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var button = document.getElementById("begin");
|
||||
if (!beeperBegun && !isTimeValid()) {
|
||||
return;
|
||||
}
|
||||
beeperBegun = !beeperBegun;
|
||||
if (beeperBegun) {
|
||||
button.innerText = "Stop!";
|
||||
intervalId = setInterval(update, 10);
|
||||
} else {
|
||||
button.innerText = "Begin!";
|
||||
clearInterval(intervalId);
|
||||
if (timeChangedWhileBegun) {
|
||||
timeChangedWhileBegun = false;
|
||||
timeChanged();
|
||||
}
|
||||
lastSec = -1;
|
||||
showBeep = 0;
|
||||
document.title = "Beeper!";
|
||||
|
||||
document.getElementById("audio").pause()
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var seconds = document.getElementById("seconds");
|
||||
var milliseconds = document.getElementById("milliseconds");
|
||||
|
||||
beepTimeCounter -= 0.01;
|
||||
showBeep -= 0.1;
|
||||
if (beepTimeCounter <= 0) {
|
||||
beepTimeCounter = beepInterval;
|
||||
showBeep = 0.5;
|
||||
document.getElementById("audio").fastSeek(0)
|
||||
document.getElementById("audio").play()
|
||||
}
|
||||
var sec = Math.floor(beepTimeCounter);
|
||||
seconds.innerText = sec;
|
||||
var millis = Math.floor((beepTimeCounter - sec) * 100) / 100;
|
||||
millis = Intl.NumberFormat("en-US", { minimumFractionDigits: 2 }).format(millis);
|
||||
millis = ("" + millis).slice(2);
|
||||
milliseconds.innerText = millis;
|
||||
|
||||
if (lastSec != sec) {
|
||||
lastSec = sec;
|
||||
if (showBeep > 0) {
|
||||
document.title = "Beeeep!";
|
||||
} else {
|
||||
document.title = "Beeper - " + sec;
|
||||
}
|
||||
}
|
||||
}
|
154
src/resources/beeping/style.css
Normal file
154
src/resources/beeping/style.css
Normal file
@ -0,0 +1,154 @@
|
||||
:root {
|
||||
font-family: Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #44444a;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.padding {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 10vh;
|
||||
text-align: center;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.timer {
|
||||
font-size: 15vw;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.timer-milliseconds {
|
||||
font-size: 25%;
|
||||
font-family: Iosevka, monospace;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: inline-block;
|
||||
height: 1.9em;
|
||||
}
|
||||
|
||||
button {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0.3em;
|
||||
padding-left: 0.6em;
|
||||
padding-right: 0.6em;
|
||||
font-size: 1em;
|
||||
transition: 0.2s;
|
||||
font-family: helvetica, sans-serif;
|
||||
background-color: #ddd;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
audio {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scroller:first-child {
|
||||
border-top-left-radius: 0.3em;
|
||||
border-bottom-left-radius: 0.3em;
|
||||
background-color: #eb6868;
|
||||
}
|
||||
|
||||
.scroller:last-child {
|
||||
border-top-right-radius: 0.3em;
|
||||
border-bottom-right-radius: 0.3em;
|
||||
background-color: #77e777;
|
||||
}
|
||||
|
||||
.scroller:first-child:hover {
|
||||
background-color: #dd5151;
|
||||
}
|
||||
|
||||
.scroller:last-child:hover {
|
||||
background-color: #53db53;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #c0c0c0;
|
||||
}
|
||||
|
||||
#time-input {
|
||||
border: none;
|
||||
background: none;
|
||||
position: relative;
|
||||
background-color: #eee;
|
||||
max-width: 5ch;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
transition: 0.2s;
|
||||
font-size: 1em;
|
||||
font-family: helvetica, sans-serif;
|
||||
}
|
||||
|
||||
#volume-slider {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#time-input:hover {
|
||||
background-color: #cbcbcb;
|
||||
}
|
||||
|
||||
#audiocontrols {
|
||||
display: inline-flex;
|
||||
width: 50vw;
|
||||
}
|
||||
|
||||
#audiocontrols > * {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#file {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
background-color: #dd7979
|
||||
}
|
||||
|
||||
.invalid:hover {
|
||||
background-color: #c56161
|
||||
}
|
||||
|
||||
.footnote {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
bottom: 0;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.footnote a {
|
||||
color: #c7c5ee;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.timer {
|
||||
font-size: 40vw;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user