Files
SvelteRouter/router.svelte
2026-02-14 01:50:02 +01:00

87 lines
2.0 KiB
Svelte

<script>
import { onMount } from 'svelte';
let { loading, fallback } = $props();
const modules = import.meta.glob('../../routes/**/*.svelte');
const routes = Object.entries(modules).map(([key, load]) => {
const path = key
.replace('../../routes', '')
.replace('.svelte', '')
.replace(/\/index$/, '') || '/';
return {
pattern: new RegExp(path.replace(/\[([^\]]+)\]/g, '(?<$1>[^/]+)') + '$'),
load
};
});
let match = $state(null);
let CurrentPage = $state(null);
let params = $state({});
async function update() {
const path = window.location.pathname;
let found = null;
for (const r of routes) {
const m = path.match(r.pattern);
if (m) {
found = r;
params = m.groups || {};
break;
}
}
if (found) {
const mod = await found.load();
CurrentPage = mod.default;
match = true;
} else {
match = false;
}
}
onMount(() => {
update();
const handlePopState = () => update();
window.addEventListener('popstate', handlePopState);
const handleClick = (e) => {
const a = e.target.closest('a');
if (!a || a.target === '_blank' || e.ctrlKey || e.metaKey) return;
const href = a.getAttribute('href');
if (!href || href.startsWith('#') || href.includes('://')) return;
e.preventDefault();
history.pushState({}, '', new URL(href, window.location.href).pathname);
update();
};
window.addEventListener('click', handleClick);
return () => {
window.removeEventListener('popstate', handlePopState);
window.removeEventListener('click', handleClick);
};
});
</script>
{#if match === true}
{#if CurrentPage}
{#key CurrentPage}
<CurrentPage {...params} />
{/key}
{/if}
{:else if match === false}
{#if fallback}
{@render fallback()}
{:else}
<h1>404 - Not found</h1>
{/if}
{:else}
{#if loading}
{@render loading()}
{:else}
<p>Loading...</p>
{/if}
{/if}