Files
sori.studio/app.vue

100 lines
2.7 KiB
Vue

<script setup>
import { DEFAULT_BRAND_COLOR, normalizeBrandColor } from './lib/brand-color.js'
const { data: appSiteSettings } = await useFetch('/api/site-settings', {
key: 'site-settings-public',
default: () => ({
title: 'sori.studio',
faviconUrl: '',
logoUrl: '',
logoText: '井',
brandColor: DEFAULT_BRAND_COLOR
})
})
const siteAccentColor = computed(() => normalizeBrandColor(appSiteSettings.value?.brandColor || DEFAULT_BRAND_COLOR))
const siteAccentStyle = computed(() => ({
'--site-accent': siteAccentColor.value
}))
const isSitePageNavigating = ref(false)
if (import.meta.client) {
const nuxtApp = useNuxtApp()
/**
* 공개 페이지 이동 로딩 오버레이를 표시한다.
* @returns {void}
*/
const showSitePageNavigationOverlay = () => {
isSitePageNavigating.value = true
}
/**
* 공개 페이지 이동 로딩 오버레이를 숨긴다.
* @returns {void}
*/
const hideSitePageNavigationOverlay = () => {
isSitePageNavigating.value = false
}
nuxtApp.hook('page:loading:start', showSitePageNavigationOverlay)
nuxtApp.hook('page:loading:end', hideSitePageNavigationOverlay)
}
useHead(() => ({
titleTemplate: (titleChunk) => titleChunk || appSiteSettings.value.title,
link: appSiteSettings.value.faviconUrl
? [
{
rel: 'icon',
type: 'image/png',
href: appSiteSettings.value.faviconUrl
}
]
: []
}))
</script>
<template>
<div class="site-app" :style="siteAccentStyle">
<NuxtLoadingIndicator :color="siteAccentColor" :height="3" :throttle="80" :duration="5000" />
<Transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<div
v-if="isSitePageNavigating"
class="site-page-loading fixed inset-0 z-[90] grid place-items-center bg-[var(--site-bg)]/78 text-[var(--site-text)] backdrop-blur-[2px]"
role="status"
aria-live="polite"
>
<div class="site-page-loading__panel grid place-items-center gap-3 text-center">
<span class="site-page-loading__spinner size-8 rounded-full border-2 border-[var(--site-line)] border-t-[var(--site-accent)]" aria-hidden="true" />
<span class="text-xs font-semibold uppercase tracking-[0.18em] opacity-70">Loading</span>
</div>
</div>
</Transition>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
<style scoped>
.site-page-loading__spinner {
animation: site-page-loading-spin 0.8s linear infinite;
}
@keyframes site-page-loading-spin {
to {
transform: rotate(360deg);
}
}
</style>