The previous paddingTop on a wrapper div didn't affect the Vuexy layout's fixed-position sidebar or sticky navbar. Replace with scoped :deep() CSS overrides that shift both elements down 48px when impersonation is active. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
3.6 KiB
Vue
114 lines
3.6 KiB
Vue
<script lang="ts" setup>
|
|
import { orgNavItems, platformNavItems } from '@/navigation/vertical'
|
|
import { useAuthStore } from '@/stores/useAuthStore'
|
|
import { useImpersonationStore } from '@/stores/useImpersonationStore'
|
|
|
|
const authStore = useAuthStore()
|
|
const impersonationStore = useImpersonationStore()
|
|
|
|
const hasOrganisation = computed(() => !!authStore.organisations.length)
|
|
|
|
const navItems = computed(() => {
|
|
const orgName = authStore.currentOrganisation?.name ?? 'Beheer'
|
|
|
|
let orgItems = orgNavItems.map(item => {
|
|
if ('heading' in item && item.heading === 'Beheer') {
|
|
return { ...item, heading: orgName }
|
|
}
|
|
return item
|
|
})
|
|
|
|
// During impersonation: hide org-dependent items if user has no organisation
|
|
if (impersonationStore.isImpersonating && !hasOrganisation.value) {
|
|
orgItems = orgItems.filter(item => {
|
|
if ('heading' in item) return false
|
|
return 'to' in item && item.to?.name === 'dashboard'
|
|
})
|
|
}
|
|
|
|
// Platform items: only for super_admin AND only when NOT impersonating
|
|
if (authStore.isSuperAdmin && !impersonationStore.isImpersonating) {
|
|
return [...orgItems, ...platformNavItems]
|
|
}
|
|
|
|
return orgItems
|
|
})
|
|
|
|
// Components
|
|
import ImpersonationBanner from '@/components/platform/ImpersonationBanner.vue'
|
|
import Footer from '@/layouts/components/Footer.vue'
|
|
import NavBarNotifications from '@/layouts/components/NavBarNotifications.vue'
|
|
import NavSearchBar from '@/layouts/components/NavSearchBar.vue'
|
|
import NavbarShortcuts from '@/layouts/components/NavbarShortcuts.vue'
|
|
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
|
|
import UserProfile from '@/layouts/components/UserProfile.vue'
|
|
import OrganisationSwitcher from '@/components/layout/OrganisationSwitcher.vue'
|
|
|
|
// @layouts plugin
|
|
import { VerticalNavLayout } from '@layouts'
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="{ 'impersonation-active': impersonationStore.isImpersonating }">
|
|
<VerticalNavLayout :nav-items="navItems">
|
|
<!-- 👉 Organisation switcher -->
|
|
<template #before-vertical-nav-items>
|
|
<OrganisationSwitcher />
|
|
<div class="vertical-nav-items-shadow" />
|
|
</template>
|
|
|
|
<!-- 👉 navbar (match Vuexy full-version: search + actions; search flex-grows) -->
|
|
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
|
<div
|
|
class="d-flex h-100 align-center w-100"
|
|
style="min-inline-size: 0;"
|
|
>
|
|
<IconBtn
|
|
id="vertical-nav-toggle-btn"
|
|
class="ms-n3 d-lg-none flex-shrink-0"
|
|
@click="toggleVerticalOverlayNavActive(true)"
|
|
>
|
|
<VIcon
|
|
size="26"
|
|
icon="tabler-menu-2"
|
|
/>
|
|
</IconBtn>
|
|
|
|
<NavSearchBar class="flex-grow-1 ms-lg-n3 min-w-0" />
|
|
|
|
<NavbarThemeSwitcher class="flex-shrink-0 me-2" />
|
|
<NavbarShortcuts class="flex-shrink-0" />
|
|
<NavBarNotifications class="flex-shrink-0 me-1" />
|
|
<UserProfile class="flex-shrink-0" />
|
|
</div>
|
|
</template>
|
|
|
|
<!-- 👉 Impersonation Banner -->
|
|
<ImpersonationBanner />
|
|
|
|
<!-- 👉 Pages -->
|
|
<slot />
|
|
|
|
<!-- 👉 Footer -->
|
|
<template #footer>
|
|
<Footer />
|
|
</template>
|
|
|
|
<!-- 👉 Customizer -->
|
|
<!-- <TheCustomizer /> -->
|
|
</VerticalNavLayout>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Push sidebar, navbar, and content below the fixed 48px impersonation banner */
|
|
.impersonation-active :deep(.layout-vertical-nav) {
|
|
inset-block-start: 48px;
|
|
block-size: calc(100% - 48px);
|
|
}
|
|
|
|
.impersonation-active :deep(.layout-navbar-sticky .layout-navbar) {
|
|
inset-block-start: 48px;
|
|
}
|
|
</style>
|