221 lines
7.7 KiB
Vue
221 lines
7.7 KiB
Vue
<script setup lang="ts">
|
|
import log from "loglevel";
|
|
|
|
import AccountMenu from "@/components/header/AccountMenu.vue";
|
|
import MobileMenu from "@/components/header/MobileMenu.vue";
|
|
import NotificationPopover from "@/components/notifications/NotificationPopover.vue";
|
|
import NotificationPopoverContent from "@/components/notifications/NotificationPopoverContent.vue";
|
|
import ItFullScreenModal from "@/components/ui/ItFullScreenModal.vue";
|
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
import { useNotificationsStore } from "@/stores/notifications";
|
|
import { useUserStore } from "@/stores/user";
|
|
import { useRouteLookups } from "@/utils/route";
|
|
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue";
|
|
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
|
|
import { computed, onMounted, reactive } from "vue";
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
log.debug("MainNavigationBar created");
|
|
|
|
const breakpoints = useBreakpoints(breakpointsTailwind);
|
|
const userStore = useUserStore();
|
|
const courseSessionsStore = useCourseSessionsStore();
|
|
const notificationsStore = useNotificationsStore();
|
|
const { inCockpit, inCompetenceProfile, inCourse, inLearningPath } = useRouteLookups();
|
|
|
|
const { t } = useI18n();
|
|
const state = reactive({
|
|
showMobileNavigationMenu: false,
|
|
showMobileProfileMenu: false,
|
|
});
|
|
|
|
function popoverClick(event: Event) {
|
|
if (breakpoints.smaller("lg").value) {
|
|
event.preventDefault();
|
|
state.showMobileProfileMenu = true;
|
|
}
|
|
}
|
|
|
|
const selectedCourseSessionTitle = computed(() => {
|
|
return courseSessionsStore.currentCourseSession?.title;
|
|
});
|
|
|
|
onMounted(() => {
|
|
log.debug("MainNavigationBar mounted");
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Teleport to="body">
|
|
<MobileMenu
|
|
v-if="userStore.loggedIn"
|
|
:show="state.showMobileNavigationMenu"
|
|
:course-session="courseSessionsStore.currentCourseSession"
|
|
:media-url="courseSessionsStore.currentCourseSession?.media_library_url"
|
|
:user="userStore"
|
|
@closemodal="state.showMobileNavigationMenu = false"
|
|
@logout="userStore.handleLogout()"
|
|
/>
|
|
</Teleport>
|
|
<Teleport to="body">
|
|
<ItFullScreenModal
|
|
v-if="userStore.loggedIn"
|
|
:show="state.showMobileProfileMenu"
|
|
@closemodal="state.showMobileProfileMenu = false"
|
|
>
|
|
<AccountMenu />
|
|
</ItFullScreenModal>
|
|
</Teleport>
|
|
<Transition name="nav">
|
|
<nav class="bg-blue-900 text-white">
|
|
<div class="mx-auto px-4 lg:px-8">
|
|
<div class="relative flex h-16 justify-between">
|
|
<div class="absolute inset-y-0 left-0 flex items-center lg:hidden">
|
|
<!-- Mobile menu button -->
|
|
<div class="flex" @click="state.showMobileNavigationMenu = true">
|
|
<button
|
|
type="button"
|
|
class="h-8 w-8 text-white hover:text-sky-500 focus:text-sky-500 focus:outline-none"
|
|
>
|
|
<it-icon-menu class="h-8 w-8" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-1 items-stretch justify-start">
|
|
<div class="hidden flex-shrink-0 items-center lg:flex">
|
|
<div class="flex items-center">
|
|
<router-link to="/" class="flex">
|
|
<it-icon-vbv class="-ml-3 -mt-6 mr-3 h-8 w-16" />
|
|
</router-link>
|
|
<router-link to="/" class="flex">
|
|
<div
|
|
class="ml-1 border-l border-white pl-3 pr-10 text-2xl text-white"
|
|
>
|
|
{{ t("general.title") }}
|
|
</div>
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="hidden space-x-8 lg:flex">
|
|
<!-- Navigation Links Desktop -->
|
|
<router-link
|
|
v-if="
|
|
inCourse() &&
|
|
courseSessionsStore.currentCourseSession &&
|
|
courseSessionsStore.hasCockpit
|
|
"
|
|
:to="`${courseSessionsStore.currentCourseSession.course_url}/cockpit`"
|
|
class="nav-item"
|
|
:class="{ 'nav-item--active': inCockpit() }"
|
|
>
|
|
{{ t("cockpit.title") }}
|
|
</router-link>
|
|
|
|
<router-link
|
|
v-if="inCourse() && courseSessionsStore.currentCourseSession"
|
|
:to="courseSessionsStore.currentCourseSession.learning_path_url"
|
|
class="nav-item"
|
|
:class="{ 'nav-item--active': inLearningPath() }"
|
|
>
|
|
{{ t("general.learningPath") }}
|
|
</router-link>
|
|
|
|
<router-link
|
|
v-if="inCourse() && courseSessionsStore.currentCourseSession"
|
|
:to="courseSessionsStore.currentCourseSession.competence_url"
|
|
class="nav-item"
|
|
:class="{ 'nav-item--active': inCompetenceProfile() }"
|
|
>
|
|
{{ t("competences.title") }}
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-stretch justify-start space-x-8">
|
|
<!-- Notification Bell & Menu -->
|
|
<div v-if="userStore.loggedIn" class="nav-item">
|
|
<NotificationPopover>
|
|
<template #toggleButtonContent>
|
|
<div class="flex">
|
|
<it-icon-notification class="h-6 w-6" />
|
|
<div
|
|
v-if="notificationsStore.hasUnread"
|
|
aria-label="unread notifications"
|
|
class="mt-1 h-1.5 w-1.5 rounded-full bg-sky-500"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<template #popoverContent>
|
|
<NotificationPopoverContent />
|
|
</template>
|
|
</NotificationPopover>
|
|
</div>
|
|
|
|
<div
|
|
v-if="selectedCourseSessionTitle"
|
|
class="hidden items-center lg:inline-flex"
|
|
>
|
|
<div class="">
|
|
{{ selectedCourseSessionTitle }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="nav-item">
|
|
<div v-if="userStore.loggedIn" class="flex items-center">
|
|
<Popover class="relative">
|
|
<PopoverButton @click="popoverClick($event)">
|
|
<div v-if="userStore.avatar_url">
|
|
<img
|
|
class="inline-block h-8 w-8 rounded-full"
|
|
:src="userStore.avatar_url"
|
|
alt=""
|
|
/>
|
|
</div>
|
|
<div v-else>
|
|
{{ userStore.getFullName }}
|
|
</div>
|
|
</PopoverButton>
|
|
|
|
<PopoverPanel
|
|
class="absolute -right-2 top-8 z-50 w-[500px] bg-white shadow-lg"
|
|
>
|
|
<div class="p-4">
|
|
<AccountMenu />
|
|
</div>
|
|
</PopoverPanel>
|
|
</Popover>
|
|
</div>
|
|
<div v-else><a class="" href="/login">Login</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</Transition>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="postcss" scoped>
|
|
.nav-item {
|
|
@apply inline-flex items-center border-b-4 border-transparent px-1 pt-1 text-white hover:text-sky-500;
|
|
}
|
|
|
|
.nav-item--active {
|
|
@apply border-sky-500;
|
|
}
|
|
|
|
.nav-enter-active,
|
|
.nav-leave-active {
|
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
}
|
|
|
|
.nav-enter-from,
|
|
.nav-leave-to {
|
|
opacity: 0;
|
|
transform: translateY(-80px);
|
|
}
|
|
</style>
|