Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
App.vue 4.73 KiB
<template>
<div id="app">
<header class="coscine-header">
<Navbar />
<LoadingIndicator />
</header>
<div>
<div v-if="!navigationError">
<SidebarMenu v-if="isLoggedIn && areTosAccepted" />
<main :class="mainContainerSizing">
<b-container fluid>
<Maintenance />
<BreadCrumbs v-if="isLoggedIn && areTosAccepted" />
<RouterView />
</b-container>
</main>
<ExpiryToast v-if="routeRequiresAuth" />
<NotificationToast />
</div>
<main v-else>
<!-- Router View for Error Pages -->
<RouterView />
</main>
</div>
<!-- Footer -->
<Footer v-if="!isLoggedIn" />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
// import the main store
import useMainStore from "@/store/index";
import useLoginStore from "@/modules/login/store";
import useUserStore from "@/modules/user/store";
export default defineComponent({
setup() {
const mainStore = useMainStore();
const loginStore = useLoginStore();
const userStore = useUserStore();
return { mainStore, loginStore, userStore };
},
computed: {
isLoggedIn(): boolean {
return this.loginStore.isLoggedIn;
},
routeRequiresAuth(): boolean {
return this.$route.meta?.requiresAuth ?? false;
},
areTosAccepted(): boolean | null | undefined {
return this.userStore.user?.areToSAccepted;
},
localeChange(): string {
return this.mainStore.coscine.locale;
},
sidebarMenuToggled(): boolean {
return this.mainStore.sidebarActive;
},
navigationError(): boolean {
if (this.$route.name == "not-found") {
return true;
} else return false;
},
mainContainerSizing(): string {
if (this.isLoggedIn && this.areTosAccepted) {
// User is logged in, sidebar is present.
return this.sidebarMenuToggled ? "sidebar-active" : "sidebar-inactive";
} else {
// User is not logged in, no sidebar. Center overlay.
return "px-4";
}
},
},
watch: {
// Listen for token changes and reload the page to fetch data again
"mainStore.coscine.authorization.bearer"() {
window.location.reload();
},
async areTosAccepted() {
await this.initializeUser();
},
localeChange() {
this.$root.$i18n.locale = this.localeChange;
},
},
async mounted() {
await this.initialize();
},
methods: {
async initialize() {
if (this.isLoggedIn) {
// Fetch Current TOS Version
if (!this.loginStore.currentTosVersion) {
await this.loginStore.retrieveCurrentTosVersion();
}
await this.initializeUser();
}
},
async initializeUser() {
if (!this.userStore.user) {
await this.userStore.retrieveUser();
this.userStore.setUserLanguagePreference();
// Forward to ToS page. Don't change the logic bellow. Variable may be null or undefined.
if (this.areTosAccepted === false) {
this.$router.push({ name: "tos" });
}
}
},
},
});
</script>
<style>
.coscine-header {
position: fixed;
top: 0;
width: 100%;
z-index: 999;
}
main {
margin-top: var(--sidebar-offset-top);
padding-right: 1.5rem;
padding-left: 0;
}
.h-divider {
margin-top: 5px;
margin-bottom: 10px;
height: 1px;
width: 100%;
border-top: 1px solid var(--light);
}
a[target="_blank"]:after {
/* URL icon styling for a new tab.
CSS Code Point from icon page (https://icons.getbootstrap.com/) */
content: " \F1C0";
font-size: 0.8em;
font-weight: normal;
color: unset;
font-family: "bootstrap-icons";
src: url("bootstrap-icons.woff2?856008caa5eb66df68595e734e59580d")
format("woff2"),
url("bootstrap-icons.woff?856008caa5eb66df68595e734e59580d") format("woff");
}
.hasInfoPopover:after {
/* Info icon styling.
CSS Code Point from icon page (https://icons.getbootstrap.com/) */
content: " \F431";
font-size: 0.8em;
font-weight: normal;
color: unset;
font-family: "bootstrap-icons";
src: url("bootstrap-icons.woff2?856008caa5eb66df68595e734e59580d")
format("woff2"),
url("bootstrap-icons.woff?856008caa5eb66df68595e734e59580d") format("woff");
}
#card-deck {
/* Used to align the cards' and container's left edges */
margin: 0em -0.5em;
}
.sidebar-active {
padding-left: calc(var(--sidebar-width-active) + var(--sidebar-left-margin));
transition: all 0.3s;
}
.sidebar-inactive {
padding-left: calc(
var(--sidebar-width-collapsed) + var(--sidebar-left-margin)
);
transition: all 0.3s;
}
.v_gapped_container {
display: flex;
flex-direction: column;
gap: var(--default-gap);
}
mark {
background-color: #fff5cc;
padding: 0;
}
</style>