astro-loading-indicator
astro-loading-indicator copied to clipboard
What about computing the animation duration dinamically based on the time to load the previous page?
<div
transition:persist
id="astro-loading-indicator"
class="astro-loading-indicator"
>
</div>
<style>
.astro-loading-indicator {
--progress: 0;
--animation-duration: 300ms;
--opacity-animation-duration: 150ms;
pointer-events: none;
background-color: hsl(192, 41%, 84%);
position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 3px;
transition:
transform var(--animation-duration) ease-out,
opacity var(--opacity-animation-duration)
var(--opacity-animation-duration) ease-in;
transform: translate3d(0, 0, 0) scaleX(var(--progress, 0));
transform-origin: 0;
}
</style>
<script>
(() => {
// This is the initial interval
let animationDuration = 50;
let progress = 0.25;
let opacity = 0;
let trickleInterval: number | undefined = undefined;
let preparationTimestamp: number = 0;
const element = document.getElementById("astro-loading-indicator");
/** @param {typeof progress} _progress */
const setProgress = (_progress: number) => {
progress = _progress;
element?.style.setProperty("--progress", String(progress));
};
/** @param {typeof opacity} _opacity */
const setOpacity = (_opacity: number) => {
opacity = _opacity;
element?.style.setProperty("opacity", String(opacity));
};
const setAnimationDuration = (duration: number) => {
animationDuration = duration;
let styleAnimationDuration = Math.min(300, animationDuration);
element?.style.setProperty(
"--animation-duration",
`${styleAnimationDuration}ms`,
);
element?.style.setProperty(
"--opacity-animation-duration",
`${styleAnimationDuration / 2}ms`,
);
return styleAnimationDuration;
};
setOpacity(opacity);
document.addEventListener("astro:before-preparation", () => {
preparationTimestamp = performance.now();
setOpacity(1);
trickleInterval = window.setInterval(() => {
setProgress(progress + Math.random() * 0.05);
}, animationDuration * 0.05);
});
document.addEventListener("astro:before-swap", (ev) => {
let computedDuration = performance.now() - preparationTimestamp;
var styleAnimationDuration = setAnimationDuration(computedDuration);
window.clearInterval(trickleInterval);
trickleInterval = undefined;
setProgress(1);
window.setTimeout(() => {
setOpacity(0);
}, styleAnimationDuration / 2);
window.setTimeout(() => {
setProgress(0.25);
}, styleAnimationDuration * 1.5);
});
})();
</script>
I can't remember exactly where it is but @martrapp had been doing experiments about getting the upcoming page loading time for better loaders, but it's not possible because of streaming or something. I'm not in favor of adjusting the loader based on the previous page because there can be many differences between 2 pages (eg. not as heavy, connection downgrade etc) but thanks for the snippet! still useful for anyone wanting it