refactor: add and use router event store

This commit is contained in:
Ax333l 2022-10-24 16:04:55 +02:00 committed by afn
parent ea599f2397
commit 4feed9982b
3 changed files with 59 additions and 38 deletions

42
src/data/RouterEvents.ts Normal file
View File

@ -0,0 +1,42 @@
import { navigating, page } from '$app/stores';
import { derived, type Readable } from 'svelte/store';
export interface RouterEvent {
// URL of the current page or the page we are navigating to.
target_url: URL;
// Are we navigating?
navigating: boolean;
}
function makeStore(): Readable<RouterEvent> {
// This stuff will run both client side and server side.
if (typeof location === 'undefined') {
// `location` does not exist on the server.
// Return a derived store based on `page` for SSR.
// Server will never navigate so this is fine.
return derived(page, $page => {
return { navigating: false, target_url: $page.url };
});
} else {
// On client.
let current = new URL(location);
// Return store that responds to navigation events.
// The `navigating` store immediately "pushes" `null`.
// This in turn causes this derived store to immediately "push" the current URL.
return derived(navigating, $nav => {
let navigating = false;
// $nav is null when navigation finishes.
if ($nav != null && $nav.to != null) {
current = $nav.to.url;
navigating = true;
}
return { navigating, target_url: current };
});
}
}
// Do not subscribe to it outside of components!
export default makeStore();

View File

@ -1,21 +1,10 @@
<script>
import { page, navigating } from '$app/stores';
import RouterEvents from '../../../data/RouterEvents';
export let href = '/';
let nav = null;
$: current_page = $page.url.pathname;
$: {
nav = $navigating;
if (nav != null && nav.to != null) {
current_page = nav.to.url.pathname;
}
}
$: current = href === current_page;
</script>
<a data-sveltekit-prefetch {href}>
<li class:selected={current === true}>
<li class:selected={href === $RouterEvents.target_url.pathname}>
<slot />
</li>
</a>

View File

@ -1,31 +1,21 @@
<script lang="ts">
import { derived } from "svelte/store";
import NavHost from "$lib/components/molecules/NavHost.svelte";
import Spinner from '$lib/components/atoms/Spinner.svelte';
import RouterEvents from '../data/RouterEvents';
import '../app.css';
import { navigating } from '$app/stores'
import { onMount } from "svelte";
import Spinner from '$lib/components/atoms/Spinner.svelte';
let timeout = 0;
let is_navigating = false;
onMount(() => {
// Show spinner if we are still waiting for navigation after 150ms
navigating.subscribe(nav => {
// cancel current timer, if any
clearTimeout(timeout);
// null after navigation finishes
if (nav != null) {
timeout = setTimeout(() => {
is_navigating = true;
}, 150);
} else {
// navigation finished
is_navigating = false;
}
});
});
// Just like the set/clearInterval example found here: https://svelte.dev/docs#run-time-svelte-store-derived
const show_loading_animation = derived(RouterEvents, ($event, set) => {
if ($event.navigating) {
// Wait 300 ms before showing the animation.
const timeout = setTimeout(() => set(true), 300);
return () => clearTimeout(timeout);
} else {
set(false)
}
}, false);
</script>
<svelte:head>
@ -42,7 +32,7 @@
</svelte:head>
<NavHost/>
{#if is_navigating}
{#if $show_loading_animation}
<Spinner />
{:else}
<slot />