docent/web/src/routes/+layout.svelte
Pen Anderson b2ffbe865e
Some checks are pending
check / frontend (push) Waiting to run
check / server (push) Waiting to run
Prototype commit
2026-05-05 09:33:51 -05:00

72 lines
1.9 KiB
Svelte

<script lang="ts">
import '../app.css';
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { dev } from '$app/environment';
import { authState, checkAuth, consumeKeyParam } from '$lib/auth.svelte';
import { precacheAll } from '$lib/precache.svelte';
let { children } = $props();
let booted = $state(false);
onMount(async () => {
if ('serviceWorker' in navigator) {
if (dev) {
const regs = await navigator.serviceWorker.getRegistrations();
await Promise.all(regs.map((r) => r.unregister()));
const keys = await caches.keys();
await Promise.all(keys.map((k) => caches.delete(k)));
} else {
navigator.serviceWorker
.register('/service-worker.js', { type: 'module' })
.catch((err) => console.warn('sw register failed:', err));
}
}
const keyResult = await consumeKeyParam();
if (keyResult !== 'success') await checkAuth();
const path = $page.url.pathname;
if (authState() === 'signed-out' && path !== '/login') {
const params = new URLSearchParams({ next: path });
if (keyResult === 'failed') params.set('error', 'qr');
await goto('/login?' + params.toString(), { replaceState: true });
}
// Production-only: kick off audio/image bulk precache once authenticated.
// SW does the work; failures non-fatal.
if (!dev && authState() === 'signed-in') {
precacheAll().catch(() => undefined);
}
booted = true;
});
</script>
{#if booted}
{@render children()}
{:else}
<div class="splash">
<div class="ring" aria-hidden="true"></div>
</div>
{/if}
<style>
.splash {
flex: 1;
display: grid;
place-items: center;
}
.ring {
width: 32px;
height: 32px;
border-radius: 50%;
border: 2px solid var(--rule);
border-top-color: var(--accent);
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>