diff --git a/aleksis/core/assets/components/app/AccountMenu.vue b/aleksis/core/assets/components/app/AccountMenu.vue new file mode 100644 index 0000000000000000000000000000000000000000..d70de72bca3ca9e2ee7e54980398ed55a3f228e6 --- /dev/null +++ b/aleksis/core/assets/components/app/AccountMenu.vue @@ -0,0 +1,73 @@ +<template> + <v-menu offset-y> + <template #activator="{ on, attrs }"> + <v-avatar v-bind="attrs" v-on="on"> + <img + v-if=" + systemProperties.sitePreferences.accountPersonPreferPhoto && + whoAmI.person.photo && + whoAmI.person.photo.url + " + :src="whoAmI.person.photo.url" + :alt="whoAmI.person.fullName" + :title="whoAmI.person.fullName" + /> + <img + v-else-if="whoAmI.person.avatarUrl" + :src="whoAmI.person.avatarUrl" + :alt="whoAmI.person.fullName + '(' + $t('person.avatar') + ')'" + :title="whoAmI.person.fullName + '(' + $t('person.avatar') + ')'" + /> + <v-icon v-else>mdi-person</v-icon> + </v-avatar> + </template> + <v-list> + <v-subheader> + {{ + $t( + whoAmI && whoAmI.isImpersonate + ? "person.impersonation.impersonating" + : "person.logged_in_as" + ) + }} + {{ whoAmI.person.fullName ? whoAmI.person.fullName : whoAmI.username }} + </v-subheader> + <v-list-item + v-if="whoAmI && whoAmI.isImpersonate" + :to="{ name: 'impersonate.stop', query: { next: $route.path } }" + > + <v-list-item-icon> + <v-icon> mdi-stop </v-icon> + </v-list-item-icon> + <v-list-item-title> + {{ $t("person.impersonation.stop") }} + </v-list-item-title> + </v-list-item> + <div v-for="menuItem in accountMenu" :key="menuItem.name"> + <v-divider v-if="menuItem.divider"></v-divider> + <v-list-item + :to="{ name: menuItem.name }" + :target="menuItem.newTab ? '_blank' : '_self'" + > + <v-list-item-icon> + <v-icon v-if="menuItem.icon">{{ menuItem.icon }}</v-icon> + </v-list-item-icon> + <v-list-item-title>{{ $t(menuItem.titleKey) }} </v-list-item-title> + </v-list-item> + </div> + </v-list> + </v-menu> +</template> + +<script> +export default { + name: "AccountMenu", + props: { + accountMenu: Array, + systemProperties: Object, + whoAmI: Object, + }, +}; +</script> + +<style></style> diff --git a/aleksis/core/assets/components/app/App.vue b/aleksis/core/assets/components/app/App.vue index baf2e69d7d22eef7f1e218926475d99f2340eca3..9c114d06c93947d41e07d1973627c373540063de 100644 --- a/aleksis/core/assets/components/app/App.vue +++ b/aleksis/core/assets/components/app/App.vue @@ -9,84 +9,11 @@ <v-app v-cloak> <splash v-if="$apollo.loading && !systemProperties" splash /> <div v-else> - <v-navigation-drawer app v-model="drawer"> - <v-list nav dense shaped> - <v-list-item class="logo"> - <a - id="logo-container" - @click="$router.push({ name: 'dashboard' })" - class="brand-logo" - > - <brand-logo - :site-preferences="systemProperties.sitePreferences" - /> - </a> - </v-list-item> - <v-list-item class="search"> - <sidenav-search /> - </v-list-item> - <v-list-item-group :value="$route.name" v-if="sideNavMenu"> - <div v-for="menuItem in sideNavMenu" :key="menuItem.name"> - <v-list-group - v-if="menuItem.subMenu.length > 0" - href="#!" - :prepend-icon="menuItem.icon" - :value="$route.matched.slice(-2).shift().name === menuItem.name" - > - <template #activator> - <v-list-item-title - >{{ $t(menuItem.titleKey) }} - </v-list-item-title> - </template> - <v-list-item - v-for="subMenuItem in menuItem.subMenu" - exact - :to="{ name: subMenuItem.name }" - :target="subMenuItem.newTab ? '_blank' : '_self'" - :key="subMenuItem.name" - :value="subMenuItem.name" - > - <v-list-item-icon> - <v-icon v-if="subMenuItem.icon" - >{{ subMenuItem.icon }} - </v-icon> - </v-list-item-icon> - <v-list-item-title - >{{ $t(subMenuItem.titleKey) }} - </v-list-item-title> - </v-list-item> - </v-list-group> - <v-list-item - v-else - exact - :to="{ name: menuItem.name }" - :target="menuItem.newTab ? '_blank' : '_self'" - :value="menuItem.name" - > - <v-list-item-icon> - <v-icon v-if="menuItem.icon">{{ menuItem.icon }}</v-icon> - </v-list-item-icon> - <v-list-item-title>{{ - $t(menuItem.titleKey) - }}</v-list-item-title> - </v-list-item> - </div> - </v-list-item-group> - <v-list-item v-else> - <v-skeleton-loader class="ma-2" type="list-item-avatar" /> - </v-list-item> - </v-list> - - <template #append> - <div class="pa-4 d-flex justify-center align-center"> - <v-spacer /> - <language-form - :available-languages="systemProperties.availableLanguages" - /> - <v-spacer /> - </div> - </template> - </v-navigation-drawer> + <side-nav + v-model="drawer" + :system-properties="systemProperties" + :side-nav-menu="sideNavMenu" + ></side-nav> <v-app-bar app :color="$vuetify.theme.dark ? undefined : 'primary white--text'" @@ -120,74 +47,11 @@ </v-btn> <div v-if="whoAmI && whoAmI.isAuthenticated" class="d-flex"> <notification-list v-if="!whoAmI.person.isDummy" /> - <v-menu offset-y> - <template #activator="{ on, attrs }"> - <v-avatar v-bind="attrs" v-on="on"> - <img - v-if=" - systemProperties.sitePreferences.accountPersonPreferPhoto && - whoAmI.person.photo && - whoAmI.person.photo.url - " - :src="whoAmI.person.photo.url" - :alt="whoAmI.person.fullName" - :title="whoAmI.person.fullName" - /> - <img - v-else-if="whoAmI.person.avatarUrl" - :src="whoAmI.person.avatarUrl" - :alt=" - whoAmI.person.fullName + '(' + $t('person.avatar') + ')' - " - :title=" - whoAmI.person.fullName + '(' + $t('person.avatar') + ')' - " - /> - <v-icon v-else>mdi-person</v-icon> - </v-avatar> - </template> - <v-list> - <v-subheader> - {{ - $t( - whoAmI && whoAmI.isImpersonate - ? "person.impersonation.impersonating" - : "person.logged_in_as" - ) - }} - {{ - whoAmI.person.fullName - ? whoAmI.person.fullName - : whoAmI.username - }} - </v-subheader> - <v-list-item - v-if="whoAmI && whoAmI.isImpersonate" - :to="{ name: 'impersonate.stop', query: { next: $route.path } }" - > - <v-list-item-icon> - <v-icon> mdi-stop </v-icon> - </v-list-item-icon> - <v-list-item-title> - {{ $t("person.impersonation.stop") }} - </v-list-item-title> - </v-list-item> - <div v-for="menuItem in accountMenu" :key="menuItem.name"> - <v-divider v-if="menuItem.divider"></v-divider> - <v-list-item - :to="{ name: menuItem.name }" - :target="menuItem.newTab ? '_blank' : '_self'" - > - <v-list-item-icon> - <v-icon v-if="menuItem.icon">{{ menuItem.icon }}</v-icon> - </v-list-item-icon> - <v-list-item-title - >{{ $t(menuItem.titleKey) }} - </v-list-item-title> - </v-list-item> - </div> - </v-list> - </v-menu> + <account-menu + :account-menu="accountMenu" + :system-properties="systemProperties" + :who-am-i="whoAmI" + ></account-menu> </div> </v-app-bar> <v-main> @@ -342,12 +206,11 @@ <script> import BroadcastChannelNotification from "./BroadcastChannelNotification.vue"; -import LanguageForm from "./LanguageForm.vue"; +import AccountMenu from "./AccountMenu.vue"; import NotificationList from "../notifications/NotificationList.vue"; -import SidenavSearch from "./SidenavSearch.vue"; import CeleryProgressBottom from "../celery_progress/CeleryProgressBottom.vue"; import Splash from "./Splash.vue"; -import BrandLogo from "./BrandLogo.vue"; +import SideNav from "./SideNav.vue"; import SnackbarItem from "./SnackbarItem.vue"; import gqlWhoAmI from "./whoAmI.graphql"; @@ -411,13 +274,12 @@ export default { }, name: "App", components: { - BrandLogo, + AccountMenu, BroadcastChannelNotification, - LanguageForm, NotificationList, - SidenavSearch, CeleryProgressBottom, Splash, + SideNav, SnackbarItem, }, mixins: [useRegisterSWMixin, offlineMixin, menusMixin], diff --git a/aleksis/core/assets/components/app/SideNav.vue b/aleksis/core/assets/components/app/SideNav.vue new file mode 100644 index 0000000000000000000000000000000000000000..e3452851ffa0f79768c02163177acc98e63114da --- /dev/null +++ b/aleksis/core/assets/components/app/SideNav.vue @@ -0,0 +1,95 @@ +<template> + <v-navigation-drawer app> + <v-list nav dense shaped> + <v-list-item class="logo"> + <a + id="logo-container" + @click="$router.push({ name: 'dashboard' })" + class="brand-logo" + > + <brand-logo :site-preferences="systemProperties.sitePreferences" /> + </a> + </v-list-item> + <v-list-item class="search"> + <sidenav-search /> + </v-list-item> + <v-list-item-group :value="$route.name" v-if="sideNavMenu"> + <div v-for="menuItem in sideNavMenu" :key="menuItem.name"> + <v-list-group + v-if="menuItem.subMenu.length > 0" + href="#!" + :prepend-icon="menuItem.icon" + :value="$route.matched.slice(-2).shift().name === menuItem.name" + > + <template #activator> + <v-list-item-title + >{{ $t(menuItem.titleKey) }} + </v-list-item-title> + </template> + <v-list-item + v-for="subMenuItem in menuItem.subMenu" + exact + :to="{ name: subMenuItem.name }" + :target="subMenuItem.newTab ? '_blank' : '_self'" + :key="subMenuItem.name" + :value="subMenuItem.name" + > + <v-list-item-icon> + <v-icon v-if="subMenuItem.icon">{{ subMenuItem.icon }} </v-icon> + </v-list-item-icon> + <v-list-item-title + >{{ $t(subMenuItem.titleKey) }} + </v-list-item-title> + </v-list-item> + </v-list-group> + <v-list-item + v-else + exact + :to="{ name: menuItem.name }" + :target="menuItem.newTab ? '_blank' : '_self'" + :value="menuItem.name" + > + <v-list-item-icon> + <v-icon v-if="menuItem.icon">{{ menuItem.icon }}</v-icon> + </v-list-item-icon> + <v-list-item-title>{{ $t(menuItem.titleKey) }}</v-list-item-title> + </v-list-item> + </div> + </v-list-item-group> + <template v-else> + <v-skeleton-loader class="ma-2" type="list-item-avatar@5" /> + </template> + </v-list> + + <template #append> + <div class="pa-4 d-flex justify-center align-center"> + <v-spacer /> + <language-form + :available-languages="systemProperties.availableLanguages" + /> + <v-spacer /> + </div> + </template> + </v-navigation-drawer> +</template> + +<script> +import BrandLogo from "./BrandLogo.vue"; +import LanguageForm from "./LanguageForm.vue"; +import SidenavSearch from "./SidenavSearch.vue"; + +export default { + name: "SideNav", + components: { + BrandLogo, + LanguageForm, + SidenavSearch, + }, + props: { + sideNavMenu: Array, + systemProperties: Object, + }, +}; +</script> + +<style scoped></style>