Our Personal Data Server from scratch! tranquil.farm
oauth atproto pds rust postgresql objectstorage fun
at main 59 lines 1.7 kB view raw
1<script lang="ts"> 2 import { getAuthState } from '../lib/auth.svelte' 3 import { navigate, routes } from '../lib/router.svelte' 4 import type { Snippet } from 'svelte' 5 import type { Session } from '../lib/types/api' 6 import { createAuthenticatedClient, type AuthenticatedClient } from '../lib/authenticated-client' 7 8 interface Props { 9 children: Snippet<[{ session: Session; client: AuthenticatedClient }]> 10 requireAdmin?: boolean 11 onReady?: (session: Session, client: AuthenticatedClient) => void 12 } 13 14 let { children, requireAdmin = false, onReady }: Props = $props() 15 const auth = $derived(getAuthState()) 16 let readyCalled = $state(false) 17 18 $effect(() => { 19 if (auth.kind === 'unauthenticated' || auth.kind === 'error') { 20 navigate(routes.login) 21 } 22 if (requireAdmin && auth.kind === 'authenticated' && !auth.session.isAdmin) { 23 navigate(routes.dashboard) 24 } 25 if (auth.kind === 'authenticated' && onReady && !readyCalled) { 26 readyCalled = true 27 onReady(auth.session, createAuthenticatedClient(auth.session)) 28 } 29 }) 30</script> 31 32{#if auth.kind === 'authenticated'} 33 {@render children({ session: auth.session, client: createAuthenticatedClient(auth.session) })} 34{:else} 35 <div class="loading-container"><div class="loading-spinner"></div></div> 36{/if} 37 38<style> 39 .loading-container { 40 display: flex; 41 justify-content: center; 42 align-items: center; 43 min-height: 200px; 44 padding: var(--space-7); 45 } 46 47 .loading-spinner { 48 width: 32px; 49 height: 32px; 50 border: 3px solid var(--border-color); 51 border-top-color: var(--accent); 52 border-radius: 50%; 53 animation: spin 0.8s linear infinite; 54 } 55 56 @keyframes spin { 57 to { transform: rotate(360deg); } 58 } 59</style>