first commit
This commit is contained in:
146
resources/js/layouts/AppLayout.vue
Normal file
146
resources/js/layouts/AppLayout.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<script setup lang="ts">
|
||||
import { router, usePage } from '@inertiajs/vue3';
|
||||
import {
|
||||
NAlert,
|
||||
NButton,
|
||||
NDropdown,
|
||||
NEl,
|
||||
NLayout,
|
||||
NLayoutHeader,
|
||||
NSpin,
|
||||
NText,
|
||||
useThemeVars,
|
||||
} from 'naive-ui';
|
||||
import { computed, h } from 'vue';
|
||||
import { TbKey, TbLogout, TbShieldLock, TbUser } from 'vue-icons-plus/tb';
|
||||
import AppDialogManager from '../components/AppDialogManager.vue';
|
||||
import Noise from '../components/Noise.vue';
|
||||
import { useGlobalLoading } from '../composables/useGlobalLoading';
|
||||
|
||||
const { isGlobalLoading } = useGlobalLoading();
|
||||
const themeVars = useThemeVars();
|
||||
const page = usePage();
|
||||
|
||||
const appName = computed(() => (page.props.name as string) ?? 'Приложение');
|
||||
const user = computed(
|
||||
() => (page.props.auth as { user?: { name?: string } })?.user,
|
||||
);
|
||||
|
||||
const blobBg = computed(() => {
|
||||
const p = themeVars.value.primaryColor;
|
||||
const w = themeVars.value.warningColor;
|
||||
const i = themeVars.value.infoColor;
|
||||
|
||||
return [
|
||||
`radial-gradient(circle 12vw at 50% -4%, color-mix(in srgb, ${p} 20%, transparent), transparent 100%)`,
|
||||
`radial-gradient(circle 16vw at 102% 52%, color-mix(in srgb, ${w} 20%, transparent), transparent 100%)`,
|
||||
`radial-gradient(circle 16vw at -4% 102%, color-mix(in srgb, ${i} 20%, transparent), transparent 100%)`,
|
||||
].join(', ');
|
||||
});
|
||||
|
||||
const userMenu = [
|
||||
{ label: 'Сменить пароль', key: 'password', icon: () => h(TbKey) },
|
||||
{ label: 'Выйти', key: 'logout', icon: () => h(TbLogout) },
|
||||
];
|
||||
|
||||
const onUserSelect = (key: string): void => {
|
||||
if (key === 'logout') {
|
||||
router.post('/logout');
|
||||
} else if (key === 'password') {
|
||||
router.get('/password/expired');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Noise />
|
||||
<AppDialogManager />
|
||||
|
||||
<NLayout position="absolute">
|
||||
<NLayoutHeader bordered style="height: 48px">
|
||||
<div class="flex h-12 items-center justify-between px-4">
|
||||
<div class="flex items-center gap-2 font-semibold">
|
||||
<TbShieldLock class="size-5 opacity-80" />
|
||||
<span>{{ appName }}</span>
|
||||
</div>
|
||||
|
||||
<NDropdown
|
||||
trigger="click"
|
||||
:options="userMenu"
|
||||
@select="onUserSelect"
|
||||
>
|
||||
<NButton text>
|
||||
<template #icon>
|
||||
<TbUser />
|
||||
</template>
|
||||
{{ user?.name ?? 'Пользователь' }}
|
||||
</NButton>
|
||||
</NDropdown>
|
||||
</div>
|
||||
</NLayoutHeader>
|
||||
|
||||
<Transition name="wait-alert">
|
||||
<NEl
|
||||
v-if="isGlobalLoading"
|
||||
class="pointer-events-none fixed inset-x-0 top-[56px] z-[2600] flex justify-center px-3"
|
||||
>
|
||||
<NAlert
|
||||
type="info"
|
||||
:show-icon="false"
|
||||
class="wait-banner w-full max-w-md"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-center gap-2.5 text-[13px] leading-none"
|
||||
>
|
||||
<NSpin :size="14" />
|
||||
<NText depth="1">Подождите, загружаем данные…</NText>
|
||||
</div>
|
||||
</NAlert>
|
||||
</NEl>
|
||||
</Transition>
|
||||
|
||||
<NEl class="pointer-events-none fixed inset-x-0 top-12 bottom-0 z-0">
|
||||
<div class="absolute inset-0" :style="`background: ${blobBg};`" />
|
||||
<div class="grid-overlay absolute inset-0 opacity-60" />
|
||||
</NEl>
|
||||
|
||||
<NLayout
|
||||
position="absolute"
|
||||
class="relative top-12! bottom-0! z-10 overflow-hidden"
|
||||
content-class="relative z-10"
|
||||
:native-scrollbar="false"
|
||||
style="--n-color: transparent"
|
||||
>
|
||||
<div class="mx-auto w-full max-w-5xl p-4">
|
||||
<slot name="header" />
|
||||
<slot />
|
||||
</div>
|
||||
</NLayout>
|
||||
</NLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.wait-alert-enter-active,
|
||||
.wait-alert-leave-active {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.wait-alert-enter-from,
|
||||
.wait-alert-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
|
||||
.wait-banner {
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
:deep(.wait-banner .n-alert-body) {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
:global(body:has(.n-modal-container)) .wait-layer {
|
||||
top: 24px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user