Our Personal Data Server from scratch!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 4e2986199080ec4e4cf264540f3e2193dbc5bf49 205 lines 5.9 kB view raw
1<script lang="ts"> 2 import { getCurrentPath, navigate } from './lib/router.svelte' 3 import { initAuth, getAuthState } from './lib/auth.svelte' 4 import { initServerConfig } from './lib/serverConfig.svelte' 5 import { initI18n } from './lib/i18n' 6 import { isLoading as i18nLoading } from 'svelte-i18n' 7 import Toast from './components/Toast.svelte' 8 import Login from './routes/Login.svelte' 9 import Register from './routes/Register.svelte' 10 import RegisterPasskey from './routes/RegisterPasskey.svelte' 11 import Verify from './routes/Verify.svelte' 12 import ResetPassword from './routes/ResetPassword.svelte' 13 import RecoverPasskey from './routes/RecoverPasskey.svelte' 14 import RequestPasskeyRecovery from './routes/RequestPasskeyRecovery.svelte' 15 import Dashboard from './routes/Dashboard.svelte' 16 import AppPasswords from './routes/AppPasswords.svelte' 17 import InviteCodes from './routes/InviteCodes.svelte' 18 import Settings from './routes/Settings.svelte' 19 import Sessions from './routes/Sessions.svelte' 20 import Comms from './routes/Comms.svelte' 21 import RepoExplorer from './routes/RepoExplorer.svelte' 22 import Admin from './routes/Admin.svelte' 23 import OAuthConsent from './routes/OAuthConsent.svelte' 24 import OAuthLogin from './routes/OAuthLogin.svelte' 25 import OAuthAccounts from './routes/OAuthAccounts.svelte' 26 import OAuth2FA from './routes/OAuth2FA.svelte' 27 import OAuthTotp from './routes/OAuthTotp.svelte' 28 import OAuthPasskey from './routes/OAuthPasskey.svelte' 29 import OAuthDelegation from './routes/OAuthDelegation.svelte' 30 import OAuthError from './routes/OAuthError.svelte' 31 import Security from './routes/Security.svelte' 32 import TrustedDevices from './routes/TrustedDevices.svelte' 33 import Controllers from './routes/Controllers.svelte' 34 import DelegationAudit from './routes/DelegationAudit.svelte' 35 import ActAs from './routes/ActAs.svelte' 36 import Migration from './routes/Migration.svelte' 37 import DidDocumentEditor from './routes/DidDocumentEditor.svelte' 38 import { _ } from './lib/i18n' 39 initI18n() 40 41 const auth = $derived(getAuthState()) 42 43 let oauthCallbackPending = $state(hasOAuthCallback()) 44 let showSpinner = $state(false) 45 let loadingTimer: ReturnType<typeof setTimeout> | null = null 46 47 function hasOAuthCallback(): boolean { 48 if (window.location.pathname === '/app/migrate') { 49 return false 50 } 51 const params = new URLSearchParams(window.location.search) 52 return !!(params.get('code') && params.get('state')) 53 } 54 55 $effect(() => { 56 loadingTimer = setTimeout(() => { 57 showSpinner = true 58 }, 5000) 59 60 initServerConfig() 61 initAuth().then(({ oauthLoginCompleted }) => { 62 if (oauthLoginCompleted) { 63 navigate('/dashboard', { replace: true }) 64 } 65 oauthCallbackPending = false 66 if (loadingTimer) { 67 clearTimeout(loadingTimer) 68 loadingTimer = null 69 } 70 }) 71 72 return () => { 73 if (loadingTimer) { 74 clearTimeout(loadingTimer) 75 } 76 } 77 }) 78 79 const isLoading = $derived( 80 auth.kind === 'loading' || $i18nLoading || oauthCallbackPending 81 ) 82 83 $effect(() => { 84 if (auth.kind === 'loading') return 85 const path = getCurrentPath() 86 if (path === '/') { 87 if (auth.kind === 'authenticated') { 88 navigate('/dashboard', { replace: true }) 89 } else { 90 navigate('/login', { replace: true }) 91 } 92 } 93 }) 94 95 function getComponent(path: string) { 96 switch (path) { 97 case '/login': 98 return Login 99 case '/register': 100 return RegisterPasskey 101 case '/register-password': 102 return Register 103 case '/verify': 104 return Verify 105 case '/reset-password': 106 return ResetPassword 107 case '/recover-passkey': 108 return RecoverPasskey 109 case '/request-passkey-recovery': 110 return RequestPasskeyRecovery 111 case '/dashboard': 112 return Dashboard 113 case '/app-passwords': 114 return AppPasswords 115 case '/invite-codes': 116 return InviteCodes 117 case '/settings': 118 return Settings 119 case '/sessions': 120 return Sessions 121 case '/comms': 122 return Comms 123 case '/repo': 124 return RepoExplorer 125 case '/admin': 126 return Admin 127 case '/oauth/consent': 128 return OAuthConsent 129 case '/oauth/login': 130 return OAuthLogin 131 case '/oauth/accounts': 132 return OAuthAccounts 133 case '/oauth/2fa': 134 return OAuth2FA 135 case '/oauth/totp': 136 return OAuthTotp 137 case '/oauth/passkey': 138 return OAuthPasskey 139 case '/oauth/delegation': 140 return OAuthDelegation 141 case '/oauth/error': 142 return OAuthError 143 case '/security': 144 return Security 145 case '/trusted-devices': 146 return TrustedDevices 147 case '/controllers': 148 return Controllers 149 case '/delegation-audit': 150 return DelegationAudit 151 case '/act-as': 152 return ActAs 153 case '/migrate': 154 return Migration 155 case '/did-document': 156 return DidDocumentEditor 157 default: 158 return Login 159 } 160 } 161 162 let currentPath = $derived(getCurrentPath()) 163 let CurrentComponent = $derived(getComponent(currentPath)) 164</script> 165 166<main> 167 {#if isLoading} 168 <div class="loading"> 169 {#if showSpinner} 170 <div class="loading-content"> 171 <div class="spinner"></div> 172 <p>{$_('common.loading')}</p> 173 </div> 174 {/if} 175 </div> 176 {:else} 177 <CurrentComponent /> 178 {/if} 179</main> 180<Toast /> 181 182<style> 183 main { 184 min-height: 100vh; 185 } 186 187 .loading { 188 min-height: 100vh; 189 display: flex; 190 align-items: center; 191 justify-content: center; 192 } 193 194 .loading-content { 195 display: flex; 196 flex-direction: column; 197 align-items: center; 198 gap: var(--space-4); 199 } 200 201 .loading-content p { 202 margin: 0; 203 color: var(--text-secondary); 204 } 205</style>