2025-04-30 01:30:11 +00:00
|
|
|
<script lang="ts">
|
2025-08-12 20:43:58 +00:00
|
|
|
import { onNavigate, beforeNavigate } from "$app/navigation";
|
2025-08-13 19:22:02 +00:00
|
|
|
import { LoaderCircle } from "lucide-svelte";
|
2025-04-30 01:30:11 +00:00
|
|
|
|
|
|
|
|
let visible = $state(false);
|
|
|
|
|
let progress = $state(0);
|
|
|
|
|
let load_durations = $state<number[]>([]);
|
|
|
|
|
let average_load = $derived(
|
|
|
|
|
load_durations.reduce((a, b) => a + b, 0) / load_durations.length,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const increment = 1;
|
2025-08-12 20:43:58 +00:00
|
|
|
let interval: number | null = null;
|
2025-04-30 01:30:11 +00:00
|
|
|
|
2025-08-12 20:43:58 +00:00
|
|
|
beforeNavigate(() => {
|
|
|
|
|
// Start the progress bar immediately when navigation begins
|
2025-04-30 01:30:11 +00:00
|
|
|
visible = true;
|
|
|
|
|
progress = 0;
|
2025-08-12 20:43:58 +00:00
|
|
|
|
|
|
|
|
// Clear any existing interval
|
|
|
|
|
if (interval) {
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const typical_load_time = average_load || 200; // ms
|
|
|
|
|
const frequency = typical_load_time / 100;
|
|
|
|
|
|
|
|
|
|
interval = setInterval(() => {
|
|
|
|
|
// Increment the progress bar but cap at 20% during beforeNavigate
|
|
|
|
|
if (progress < 20) {
|
|
|
|
|
progress += increment;
|
|
|
|
|
}
|
2025-04-30 01:30:11 +00:00
|
|
|
}, frequency);
|
2025-08-12 20:43:58 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onNavigate((navigation) => {
|
|
|
|
|
console.log("Navigating to", navigation?.to);
|
|
|
|
|
let start = performance.now();
|
|
|
|
|
|
2025-04-30 01:30:11 +00:00
|
|
|
// Resolve the promise when the page is done loading
|
|
|
|
|
navigation?.complete.then(() => {
|
|
|
|
|
progress = 100; // Fill out the progress bar
|
2025-08-12 20:43:58 +00:00
|
|
|
if (interval) {
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
interval = null;
|
|
|
|
|
}
|
2025-04-30 01:30:11 +00:00
|
|
|
// after 100 ms hide the progress bar
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
visible = false;
|
|
|
|
|
}, 500);
|
|
|
|
|
// Log how long that one took
|
|
|
|
|
const end = performance.now();
|
|
|
|
|
const duration = end - start;
|
|
|
|
|
load_durations = [...load_durations, duration];
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
{#if visible}
|
|
|
|
|
<div class="progress" style="width: {progress}%;"></div>
|
2025-08-13 19:22:02 +00:00
|
|
|
<div class="loader-container">
|
|
|
|
|
<LoaderCircle class="loader-icon" size={20} />
|
|
|
|
|
</div>
|
2025-04-30 01:30:11 +00:00
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<style lang="postcss">
|
|
|
|
|
.progress {
|
|
|
|
|
background: var(--lightGrey);
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
height: 0.25rem;
|
|
|
|
|
z-index: 50;
|
|
|
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
|
}
|
2025-08-13 19:22:02 +00:00
|
|
|
|
|
|
|
|
.loader-container {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 1rem;
|
|
|
|
|
right: 1rem;
|
|
|
|
|
z-index: 50;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:global(.loader-icon) {
|
|
|
|
|
animation: spin 1s linear infinite;
|
|
|
|
|
color: var(--lightGrey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
from {
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-30 01:30:11 +00:00
|
|
|
</style>
|