Skip to content

What about computing the animation duration dinamically based on the time to load the previous page? #6

Open
@zanhk

Description

@zanhk
<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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions