delayed loading spinner in frontend, more functional-style code

This commit is contained in:
lewis
2026-01-12 08:46:52 +02:00
parent 16fb4dbd03
commit 0bad085ead
21 changed files with 816 additions and 565 deletions
+45 -2
View File
@@ -35,11 +35,14 @@
import ActAs from './routes/ActAs.svelte'
import Migration from './routes/Migration.svelte'
import DidDocumentEditor from './routes/DidDocumentEditor.svelte'
import { _ } from './lib/i18n'
initI18n()
const auth = $derived(getAuthState())
let oauthCallbackPending = $state(hasOAuthCallback())
let showSpinner = $state(false)
let loadingTimer: ReturnType<typeof setTimeout> | null = null
function hasOAuthCallback(): boolean {
if (window.location.pathname === '/app/migrate') {
@@ -50,15 +53,33 @@
}
$effect(() => {
loadingTimer = setTimeout(() => {
showSpinner = true
}, 5000)
initServerConfig()
initAuth().then(({ oauthLoginCompleted }) => {
if (oauthLoginCompleted) {
navigate('/dashboard', { replace: true })
}
oauthCallbackPending = false
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
})
return () => {
if (loadingTimer) {
clearTimeout(loadingTimer)
}
}
})
const isLoading = $derived(
auth.kind === 'loading' || $i18nLoading || oauthCallbackPending
)
$effect(() => {
if (auth.kind === 'loading') return
const path = getCurrentPath()
@@ -143,8 +164,15 @@
</script>
<main>
{#if auth.kind === 'loading' || $i18nLoading || oauthCallbackPending}
<div class="loading"></div>
{#if isLoading}
<div class="loading">
{#if showSpinner}
<div class="loading-content">
<div class="spinner"></div>
<p>{$_('common.loading')}</p>
</div>
{/if}
</div>
{:else}
<CurrentComponent />
{/if}
@@ -158,5 +186,20 @@
.loading {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-4);
}
.loading-content p {
margin: 0;
color: var(--text-secondary);
}
</style>
+37 -1
View File
@@ -27,6 +27,8 @@
}
let loading = $state(true)
let showSpinner = $state(false)
let loadingTimer: ReturnType<typeof setTimeout> | null = null
let error = $state<string | null>(null)
let submitting = $state(false)
let consentData = $state<ConsentData | null>(null)
@@ -71,6 +73,11 @@
error = $_('oauth.error.genericError')
} finally {
loading = false
showSpinner = false
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
}
}
@@ -151,7 +158,17 @@
}
$effect(() => {
loadingTimer = setTimeout(() => {
if (loading) {
showSpinner = true
}
}, 5000)
fetchConsentData()
return () => {
if (loadingTimer) {
clearTimeout(loadingTimer)
}
}
})
let scopeGroups = $derived(consentData ? groupScopesByCategory(consentData.scopes) : {})
@@ -159,7 +176,14 @@
<div class="consent-container">
{#if loading}
<div class="loading"></div>
<div class="loading">
{#if showSpinner}
<div class="loading-content">
<div class="spinner"></div>
<p>{$_('common.loading')}</p>
</div>
{/if}
</div>
{:else if error}
<div class="error-container">
<h1>{$_('oauth.error.title')}</h1>
@@ -296,6 +320,18 @@
color: var(--text-secondary);
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-4);
}
.loading-content p {
margin: 0;
color: var(--text-secondary);
}
.error-container {
text-align: center;
max-width: var(--width-sm);
+27
View File
@@ -494,3 +494,30 @@ hr {
.info-panel p:last-child {
margin-bottom: 0;
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid var(--border-color);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
.spinner.sm {
width: 20px;
height: 20px;
border-width: 2px;
}
.spinner.lg {
width: 60px;
height: 60px;
border-width: 4px;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}