schon/storefront/app/app.vue
2026-02-27 21:59:51 +03:00

206 lines
No EOL
4.7 KiB
Vue

<template>
<div
class="main"
:style="{ 'padding-top': uiConfig.isHeaderFixed ? '83px': '0' }"
>
<nuxt-loading-indicator :color="accentColor" />
<base-header />
<ui-breadcrumbs v-if="uiConfig.showBreadcrumbs && showBreadcrumbs" />
<transition
name="opacity"
mode="out-in"
v-if="uiConfig.isAuthModals"
>
<base-auth v-if="activeState">
<forms-login v-if="appStore.isLogin" />
<forms-register v-if="appStore.isRegister" />
<forms-reset-password v-if="appStore.isForgot" />
<forms-new-password v-if="appStore.isReset" />
</base-auth>
</transition>
<nuxt-page />
<ui-button
:type="'button'"
class="demo__button"
v-if="isDemoMode"
@click="appStore.setDemoSettings(!appStore.isDemoSettings)"
>
<icon
name="material-symbols:settings"
size="30"
/>
</ui-button>
<transition name="opacity" mode="out-in">
<demo-settings />
</transition>
<base-footer />
</div>
</template>
<script setup lang="ts">
import {DEFAULT_LOCALE} from '@appConstants';
import {useRefresh} from '@composables/auth';
import {useLanguages, useLocaleRedirect} from '@composables/languages';
import {useCompanyInfo} from '@composables/company';
import {useCategories} from '@composables/categories';
import {useProjectConfig} from '@composables/config';
const { locale } = useI18n();
const route = useRoute();
const router = useRouter();
const appStore = useAppStore();
const { isDemoMode, uiConfig } = useProjectConfig();
const toaster = { position: uiConfig.value.toastPosition };
const switchLocalePath = useSwitchLocalePath();
const { $appHelpers } = useNuxtApp();
const showBreadcrumbs = computed(() => {
const name = typeof route.name === 'string' ? route.name : '';
return ![
'index',
'search',
'profile',
'activate-user',
'reset-password',
'auth-sign-in',
'auth-sign-up',
'auth-reset-password',
'contact',
'blog',
'docs'
].some(prefix => name.startsWith(prefix));
});
const activeState = computed(() => appStore.activeAuthState);
const cookieLocale = useCookie(
$appHelpers.COOKIES_LOCALE_KEY,
{
default: () => DEFAULT_LOCALE,
path: '/'
}
);
const { refresh } = useRefresh();
const { getCategories } = await useCategories();
const { isSupportedLocale } = useLocaleRedirect();
let refreshInterval: NodeJS.Timeout;
if (import.meta.server) {
await Promise.all([
refresh(),
useLanguages(),
useCompanyInfo(),
getCategories()
]);
}
watch(
() => [appStore.activeAuthState, appStore.isDemoSettings],
([authState, isDemo]) => {
appStore.setOverflowHidden(authState !== '' || isDemo);
},
{ immediate: true }
);
watch(locale, () => {
useHead({
htmlAttrs: {
lang: locale.value
}
});
});
let stopWatcher: VoidFunction = () => {};
if (!cookieLocale.value) {
cookieLocale.value = DEFAULT_LOCALE;
await router.push({path: switchLocalePath(cookieLocale.value)});
}
if (locale.value !== cookieLocale.value) {
if (isSupportedLocale(cookieLocale.value)) {
await router.push({
path: switchLocalePath(cookieLocale.value),
query: route.query
});
} else {
cookieLocale.value = DEFAULT_LOCALE
await router.push({
path: switchLocalePath(DEFAULT_LOCALE),
query: route.query
});
}
}
const accentColor = ref('');
const getCssVariable = (name: string): string => {
if (import.meta.client) {
return getComputedStyle(document.documentElement)
.getPropertyValue(name)
.trim();
}
return '';
};
onMounted( async () => {
refreshInterval = setInterval(async () => {
await refresh();
}, 600000);
stopWatcher = watch(
() => appStore.isOverflowHidden,
(hidden) => {
const root = document.documentElement;
const body = document.body;
if (hidden) {
root.classList.add('lock-scroll');
body.classList.add('lock-scroll');
} else {
root.classList.remove('lock-scroll');
body.classList.remove('lock-scroll');
}
},
{ immediate: true }
);
accentColor.value = getCssVariable('--accent');
useHead({
htmlAttrs: {
lang: locale.value
}
});
});
onBeforeUnmount(() => {
stopWatcher()
document.documentElement.classList.remove('lock-scroll');
document.body.classList.remove('lock-scroll');
});
</script>
<style lang="scss">
.main {
background-color: $light;
position: relative;
}
.lock-scroll {
overflow: hidden !important;
}
.demo {
&__button {
position: fixed !important;
width: fit-content !important;
bottom: 20px;
right: 20px;
padding: 10px !important;
}
}
</style>