180 lines
5.2 KiB
Vue
180 lines
5.2 KiB
Vue
<template>
|
|
<div class="relative flex h-full flex-col">
|
|
<n-layout class="h-full" has-sider>
|
|
<n-layout-sider
|
|
v-if="!isSignupFlow && !$isMobile && !isHideSidebar && $session.user"
|
|
bordered
|
|
collapse-mode="width"
|
|
:collapsed-width="64"
|
|
:width="240"
|
|
v-model:collapsed="sidebarCollapsed"
|
|
:show-trigger="true"
|
|
:responsive="true"
|
|
:breakpoint="768"
|
|
class="app-sidebar-sider"
|
|
@collapse="sidebarCollapsed = true"
|
|
@expand="sidebarCollapsed = false"
|
|
>
|
|
<AppSidebar :collapsed="sidebarCollapsed" />
|
|
</n-layout-sider>
|
|
<n-layout class="h-full">
|
|
<div class="w-full h-full overflow-auto" id="scrollContainer">
|
|
<MobileNav
|
|
v-if="!isSignupFlow && $isMobile && !isHideSidebar && $session.user"
|
|
/>
|
|
<div
|
|
v-if="
|
|
!isSignupFlow &&
|
|
!isSiteLogin &&
|
|
!$session.user &&
|
|
!$route.meta.isLoginPage
|
|
"
|
|
class="border bg-red-200 px-5 py-3 text-base text-red-900"
|
|
>
|
|
You are not logged in.
|
|
<router-link to="/login" class="underline">Login</router-link> to
|
|
access dashboard.
|
|
</div>
|
|
<router-view />
|
|
</div>
|
|
</n-layout>
|
|
</n-layout>
|
|
<Toaster position="top-right" />
|
|
<component v-for="dialog in dialogs" :is="dialog" :key="dialog.id" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { defineAsyncComponent, computed, watch, ref, provide, onMounted } from 'vue';
|
|
import { NLayout, NLayoutSider } from 'naive-ui';
|
|
import { Toaster } from 'vue-sonner';
|
|
import { dialogs } from './utils/components';
|
|
import { useRoute } from 'vue-router';
|
|
import { getTeam } from './data/team';
|
|
import { session } from './data/session.js';
|
|
|
|
const AppSidebar = defineAsyncComponent(
|
|
() => import('./components/AppSidebar.vue'),
|
|
);
|
|
const MobileNav = defineAsyncComponent(
|
|
() => import('./components/MobileNav.vue'),
|
|
);
|
|
|
|
const route = useRoute();
|
|
const team = getTeam();
|
|
|
|
// 侧边栏折叠状态
|
|
const sidebarCollapsed = ref(false);
|
|
|
|
// 响应式:在移动端默认折叠
|
|
onMounted(() => {
|
|
const checkMobile = () => {
|
|
if (window.innerWidth < 768) {
|
|
sidebarCollapsed.value = true;
|
|
}
|
|
};
|
|
checkMobile();
|
|
window.addEventListener('resize', checkMobile);
|
|
});
|
|
|
|
const isHideSidebar = computed(() => {
|
|
const alwaysHideSidebarRoutes = [
|
|
'Site Login',
|
|
'SignupLoginToSite',
|
|
'SignupSetup',
|
|
];
|
|
const alwaysHideSidebarPaths = ['/dashboard/site-login'];
|
|
|
|
if (!session.user) return false;
|
|
if (
|
|
alwaysHideSidebarRoutes.includes(route.name) ||
|
|
alwaysHideSidebarPaths.includes(window.location.pathname)
|
|
)
|
|
return true;
|
|
|
|
return (
|
|
route.meta.hideSidebar && session.user && team?.pg?.hide_sidebar === true
|
|
);
|
|
});
|
|
|
|
const isSignupFlow = ref(
|
|
window.location.pathname.startsWith('/dashboard/create-site') ||
|
|
window.location.pathname.startsWith('/dashboard/setup-account') ||
|
|
window.location.pathname.startsWith('/dashboard/site-login') ||
|
|
window.location.pathname.startsWith('/dashboard/signup'),
|
|
);
|
|
const isSiteLogin = ref(window.location.pathname.endsWith('/site-login'));
|
|
|
|
watch(
|
|
() => route.name,
|
|
() => {
|
|
isSignupFlow.value =
|
|
window.location.pathname.startsWith('/dashboard/create-site') ||
|
|
window.location.pathname.startsWith('/dashboard/setup-account') ||
|
|
window.location.pathname.startsWith('/dashboard/site-login') ||
|
|
window.location.pathname.startsWith('/dashboard/signup');
|
|
},
|
|
);
|
|
|
|
provide('team', team);
|
|
provide('session', session);
|
|
</script>
|
|
|
|
<style src="../src/assets/style.css"></style>
|
|
|
|
<style>
|
|
/* 侧边栏整体样式优化 - 平滑过渡 */
|
|
.app-sidebar-sider {
|
|
background: #fafafa !important;
|
|
border-right: 1px solid rgba(0, 0, 0, 0.06) !important;
|
|
/* 使用平滑的缓动函数,避免抖动 */
|
|
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
|
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
|
}
|
|
|
|
.app-sidebar-sider:not(.n-layout-sider--collapsed) {
|
|
box-shadow: 2px 0 12px rgba(0, 0, 0, 0.04) !important;
|
|
}
|
|
|
|
/* 触发器样式优化 - 平滑过渡 */
|
|
.app-sidebar-sider .n-layout-sider-trigger {
|
|
background: #fff !important;
|
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
|
|
/* 使用平滑的缓动函数,避免抖动 */
|
|
transition: background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
|
box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
|
width: 32px !important;
|
|
height: 32px !important;
|
|
border-radius: 50% !important;
|
|
right: -16px !important;
|
|
backdrop-filter: blur(10px);
|
|
-webkit-backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.app-sidebar-sider .n-layout-sider-trigger:hover {
|
|
background: #f5f5f5 !important;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
|
}
|
|
|
|
.app-sidebar-sider .n-layout-sider-trigger:active {
|
|
background: #eeeeee !important;
|
|
}
|
|
|
|
.app-sidebar-sider .n-layout-sider-trigger .n-base-icon {
|
|
color: #666;
|
|
font-size: 14px;
|
|
/* 移除旋转动画,避免抖动 */
|
|
transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
|
}
|
|
|
|
/* 确保侧边栏内容正确显示 */
|
|
.app-sidebar-sider .n-layout-sider-scroll-container {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
/* 添加内容过渡效果 */
|
|
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
|
}
|
|
</style>
|