ui: add initial loading states
This commit is contained in:
@@ -155,6 +155,7 @@ const showSettingsThemePanel = computed(() => route.name === 'profile')
|
||||
const showTopicViewToggle = computed(() => route.name === 'topicHub')
|
||||
const topicViewMode = computed(() => (route.query.view === 'list' ? 'list' : 'grid'))
|
||||
const showBackendFallback = computed(() => !isPreviewMode.value && ['maintenance', 'offline'].includes(backendState.value))
|
||||
const showInitialAppLoading = computed(() => !authReady.value && !showBackendFallback.value)
|
||||
const shouldLockRightRailBodyScroll = computed(() => isRightRailOverlay.value && rightRailOpen.value && !showBackendFallback.value)
|
||||
const leftBottomPrimaryAction = computed(() => {
|
||||
if (!authReady.value) return null
|
||||
@@ -580,6 +581,16 @@ function reloadApp() {
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
<template v-else-if="showInitialAppLoading">
|
||||
<main class="appLoading">
|
||||
<section class="appLoading__card">
|
||||
<div class="appLoading__eyebrow">Loading</div>
|
||||
<h1 class="appLoading__title">접속 정보를 확인하고 있어요.</h1>
|
||||
<p class="appLoading__desc">로그인 상태와 기본 데이터를 확인한 뒤 화면을 보여드릴게요.</p>
|
||||
<div class="appLoading__spinner" aria-hidden="true"></div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
<template v-else>
|
||||
<aside class="leftRail">
|
||||
<div class="leftRail__top railHeader">
|
||||
@@ -837,7 +848,8 @@ function reloadApp() {
|
||||
transition: grid-template-columns 220ms ease;
|
||||
}
|
||||
|
||||
.backendFallback {
|
||||
.backendFallback,
|
||||
.appLoading {
|
||||
min-width: 100dvw;
|
||||
min-height: 100dvh;
|
||||
display: grid;
|
||||
@@ -848,7 +860,8 @@ function reloadApp() {
|
||||
var(--theme-shell-bg);
|
||||
}
|
||||
|
||||
.backendFallback__card {
|
||||
.backendFallback__card,
|
||||
.appLoading__card {
|
||||
width: min(100%, 560px);
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
@@ -859,7 +872,8 @@ function reloadApp() {
|
||||
box-shadow: inset 0 1px 0 var(--theme-card-shadow);
|
||||
}
|
||||
|
||||
.backendFallback__eyebrow {
|
||||
.backendFallback__eyebrow,
|
||||
.appLoading__eyebrow {
|
||||
color: var(--theme-accent-strong);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
@@ -867,20 +881,37 @@ function reloadApp() {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.backendFallback__title {
|
||||
.backendFallback__title,
|
||||
.appLoading__title {
|
||||
margin: 0;
|
||||
font-size: clamp(28px, 4vw, 42px);
|
||||
line-height: 1.05;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.backendFallback__desc {
|
||||
.backendFallback__desc,
|
||||
.appLoading__desc {
|
||||
margin: 0;
|
||||
color: var(--theme-text-muted);
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.appLoading__spinner {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 999px;
|
||||
border: 3px solid color-mix(in srgb, var(--theme-text-faint) 34%, transparent);
|
||||
border-top-color: var(--theme-accent-strong);
|
||||
animation: appLoadingSpin 820ms linear infinite;
|
||||
}
|
||||
|
||||
@keyframes appLoadingSpin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.backendFallback__actions {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
|
||||
Reference in New Issue
Block a user