feat: implement a simple loader
Play with htmx events
This commit is contained in:
@@ -1,3 +1,89 @@
|
||||
h1 {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
[data-loader] {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
height: .2em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: blue;
|
||||
transition: all 500ms;
|
||||
}
|
||||
|
||||
body {
|
||||
display: grid;
|
||||
grid-template-columns: 15em 1fr;
|
||||
grid-template-rows: 3em 1fr 3em;
|
||||
|
||||
grid-template-areas:
|
||||
"nav header"
|
||||
"nav main"
|
||||
"nav footer";
|
||||
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
body {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 3em 1fr 3em;
|
||||
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"main"
|
||||
"footer";
|
||||
}
|
||||
|
||||
nav {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 15em;
|
||||
}
|
||||
}
|
||||
|
||||
body > * {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
hgroup * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
grid-area: nav;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
header {
|
||||
grid-area: header;
|
||||
|
||||
background-color: orange;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
main {
|
||||
grid-area: main;
|
||||
|
||||
background-color: darkgray;
|
||||
}
|
||||
|
||||
footer {
|
||||
grid-area: footer;
|
||||
|
||||
background-color: grey;
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
98
static/js/loader.js
Normal file
98
static/js/loader.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* A loading bar that hooks into htmx events to automatically indicate the
|
||||
* progression of pending requests.
|
||||
*
|
||||
* ```html
|
||||
* <div data-loader></div>
|
||||
* ```
|
||||
* Only the first loader will be used.
|
||||
*/
|
||||
(function () {
|
||||
var MAX_INCREMENT = 20;
|
||||
var MIN_INCREMENT = 3;
|
||||
var ADVANCE_UNTIL = 90;
|
||||
|
||||
var pending = 0;
|
||||
var increment = MAX_INCREMENT;
|
||||
var timeout = null;
|
||||
var interval = null;
|
||||
|
||||
function getLoader() {
|
||||
return document.querySelector("[data-loader]");
|
||||
}
|
||||
|
||||
function clamp(x, a, b) {
|
||||
return Math.max(a, Math.min(x, b));
|
||||
}
|
||||
|
||||
function progress(loader) {
|
||||
loader.hidden = false;
|
||||
var current = parseInt(loader.dataset.loader);
|
||||
|
||||
if (current < ADVANCE_UNTIL) {
|
||||
current = Math.min(current + increment, ADVANCE_UNTIL);
|
||||
loader.dataset.loader = current;
|
||||
loader.style.right = 100 - current + "%";
|
||||
increment = clamp(Math.floor(increment * 0.65), MIN_INCREMENT, MAX_INCREMENT);
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
pending++;
|
||||
|
||||
if (pending > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(timeout);
|
||||
clearInterval(interval);
|
||||
|
||||
increment = MAX_INCREMENT;
|
||||
|
||||
var loader = getLoader();
|
||||
if (!loader) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give the request a reasonable time to complete before triggering the
|
||||
// loader.
|
||||
timeout = setTimeout(function () {
|
||||
loader.dataset.loader = 0;
|
||||
loader.style.right = "100%";
|
||||
loader.hidden = false;
|
||||
|
||||
// Increment the loader state until it reaches the threshold.
|
||||
// Trickery and lies!
|
||||
interval = setInterval(function () {
|
||||
progress(loader)
|
||||
}, 100);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
pending--;
|
||||
|
||||
if (pending <= 0) {
|
||||
clearTimeout(timeout);
|
||||
clearInterval(interval);
|
||||
|
||||
var loader = getLoader();
|
||||
if (!loader) {
|
||||
return;
|
||||
}
|
||||
|
||||
loader.style.right = 0;
|
||||
timeout = setTimeout(function () {
|
||||
loader.hidden = true;
|
||||
timeout = setTimeout(function () {
|
||||
loader.dataset.loader = 0;
|
||||
loader.style.right = "100%";
|
||||
}, 500);
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("htmx:beforeRequest", start);
|
||||
addEventListener("htmx:afterRequest", finish);
|
||||
})();
|
||||
Reference in New Issue
Block a user