diff options
author | Andrey V.Kosteltsev <AKosteltsev@IBS.RU> | 2022-07-04 23:59:32 +0300 |
---|---|---|
committer | Andrey V.Kosteltsev <AKosteltsev@IBS.RU> | 2022-07-04 23:59:32 +0300 |
commit | 8047ae3d83ba0718fb7a42907036157e5c680b85 (patch) | |
tree | 600b017fe3a75ab4d1577eb9367afe8548401f9f /src/components/_sila/AppNavigation | |
parent | 3f4094d08b873e17464a51c817ea7d41177f848d (diff) | |
download | webui-vue-8047ae3d83ba0718fb7a42907036157e5c680b85.tar.xz |
IBS: _sila UI theme
Diffstat (limited to 'src/components/_sila/AppNavigation')
-rw-r--r-- | src/components/_sila/AppNavigation/AppNavigation.vue | 255 | ||||
-rw-r--r-- | src/components/_sila/AppNavigation/AppNavigationMixin.js | 182 | ||||
-rw-r--r-- | src/components/_sila/AppNavigation/index.js | 2 |
3 files changed, 439 insertions, 0 deletions
diff --git a/src/components/_sila/AppNavigation/AppNavigation.vue b/src/components/_sila/AppNavigation/AppNavigation.vue new file mode 100644 index 00000000..acfabe76 --- /dev/null +++ b/src/components/_sila/AppNavigation/AppNavigation.vue @@ -0,0 +1,255 @@ +<template> + <div> + <div class="nav-container" :class="{ open: isNavigationOpen }"> + <nav ref="nav" :aria-label="$t('appNavigation.primaryNavigation')"> + <b-nav vertical class="mb-4"> + <template v-for="(navItem, index) in navigationItems"> + <!-- Navigation items with no children --> + <b-nav-item + v-if="!navItem.children" + :key="index" + :to="navItem.route" + :data-test-id="`nav-item-${navItem.id}`" + > + <component :is="navItem.icon" /> + {{ navItem.label }} + </b-nav-item> + + <!-- Navigation items with children --> + <li v-else :key="index" class="nav-item"> + <b-button + v-b-toggle="`${navItem.id}`" + variant="link" + :data-test-id="`nav-button-${navItem.id}`" + > + <component :is="navItem.icon" /> + {{ navItem.label }} + <icon-expand class="icon-expand" /> + </b-button> + <b-collapse :id="navItem.id" tag="ul" class="nav-item__nav"> + <li class="nav-item"> + <router-link + v-for="(subNavItem, i) of navItem.children" + :key="i" + :to="subNavItem.route" + :data-test-id="`nav-item-${subNavItem.id}`" + class="nav-link" + > + {{ subNavItem.label }} + </router-link> + </li> + </b-collapse> + </li> + </template> + </b-nav> + </nav> + </div> + <transition name="fade"> + <div + v-if="isNavigationOpen" + id="nav-overlay" + class="nav-overlay" + @click="toggleIsOpen" + ></div> + </transition> + </div> +</template> + +<script> +//Do not change Mixin import. +//Exact match alias set to support +//dotenv customizations. +import AppNavigationMixin from './AppNavigationMixin'; + +export default { + name: 'AppNavigation', + mixins: [AppNavigationMixin], + data() { + return { + isNavigationOpen: false, + }; + }, + watch: { + $route: function () { + this.isNavigationOpen = false; + }, + isNavigationOpen: function (isNavigationOpen) { + this.$root.$emit('change-is-navigation-open', isNavigationOpen); + }, + }, + mounted() { + this.$root.$on('toggle-navigation', () => this.toggleIsOpen()); + }, + methods: { + toggleIsOpen() { + this.isNavigationOpen = !this.isNavigationOpen; + }, + }, +}; +</script> + +<style scoped lang="scss"> +svg { + fill: currentColor; + height: 1.2rem; + width: 1.2rem; + margin-left: 0 !important; //!important overriding button specificity + vertical-align: text-bottom; + &:not(.icon-expand) { + margin-right: $spacer; + } +} + +.nav { + padding-top: $spacer / 4; + @include media-breakpoint-up($responsive-layout-bp) { + padding-top: $spacer; + } +} + +.nav-item__nav { + list-style: none; + padding-left: 0; + margin-left: 0; + + .nav-item { + outline: none; + } + + .nav-link { + padding-left: $spacer * 4; + outline: none; + + &:not(.nav-link--current) { + font-weight: normal; + } + } +} + +.btn-link { + display: inline-block; + width: 100%; + text-align: left; + text-decoration: none !important; + border-radius: 0; + + &.collapsed { + .icon-expand { + transform: rotate(180deg); + } + } +} + +.icon-expand { + float: right; + margin-top: $spacer / 4; +} + +.btn-link, +.nav-link { + position: relative; + font-weight: $headings-font-weight; + padding-left: $spacer; // defining consistent padding for links and buttons + padding-right: $spacer; + color: theme-color('secondary'); + + &:hover { + background-color: theme-color-level(dark, -10.5); + color: theme-color('dark'); + } + + &:focus { + background-color: theme-color-level(light, 0); + box-shadow: inset 0 0 0 2px theme-color('primary'); + color: theme-color('dark'); + outline: 0; + } + + &:active { + background-color: theme-color('secondary'); + color: $white; + } +} + +.nav-link--current { + font-weight: $headings-font-weight; + background-color: theme-color('secondary'); + color: theme-color('light'); + cursor: default; + box-shadow: none; + + &::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 4px; + background-color: theme-color('primary'); + } + + &:hover, + &:focus { + background-color: theme-color('secondary'); + color: theme-color('light'); + } +} + +.nav-container { + position: fixed; + width: $navigation-width; + top: $header-height; + bottom: 0; + left: 0; + z-index: $zindex-fixed; + overflow-y: auto; + background-color: theme-color('light'); + transform: translateX(-$navigation-width); + transition: transform $exit-easing--productive $duration--moderate-02; + border-right: 1px solid theme-color-level('light', 2.85); + + @include media-breakpoint-down(md) { + z-index: $zindex-fixed + 2; + } + + &.open, + &:focus-within { + transform: translateX(0); + transition-timing-function: $entrance-easing--productive; + } + + @include media-breakpoint-up($responsive-layout-bp) { + transition-duration: $duration--fast-01; + transform: translateX(0); + } +} + +.nav-overlay { + position: fixed; + top: $header-height; + bottom: 0; + left: 0; + right: 0; + z-index: $zindex-fixed + 1; + background-color: $black; + opacity: 0.5; + + &.fade-enter-active { + transition: opacity $duration--moderate-02 $entrance-easing--productive; + } + + &.fade-leave-active { + transition: opacity $duration--fast-02 $exit-easing--productive; + } + + &.fade-enter, // Remove this vue2 based only class when switching to vue3 + &.fade-enter-from, // This is vue3 based only class modified from 'fade-enter' + &.fade-leave-to { + opacity: 0; + } + + @include media-breakpoint-up($responsive-layout-bp) { + display: none; + } +} +</style> diff --git a/src/components/_sila/AppNavigation/AppNavigationMixin.js b/src/components/_sila/AppNavigation/AppNavigationMixin.js new file mode 100644 index 00000000..bbbbb1ee --- /dev/null +++ b/src/components/_sila/AppNavigation/AppNavigationMixin.js @@ -0,0 +1,182 @@ +import IconDashboard from '@carbon/icons-vue/es/dashboard/16'; +import IconTextLinkAnalysis from '@carbon/icons-vue/es/text-link--analysis/16'; +import IconDataCheck from '@carbon/icons-vue/es/data--check/16'; +import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16'; +import IconSettings from '@carbon/icons-vue/es/settings/16'; +import IconSecurity from '@carbon/icons-vue/es/security/16'; +import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16'; +import IconDataBase from '@carbon/icons-vue/es/data--base--alt/16'; + +const AppNavigationMixin = { + components: { + iconOverview: IconDashboard, + iconLogs: IconTextLinkAnalysis, + iconHealth: IconDataCheck, + iconControl: IconSettingsAdjust, + iconSettings: IconSettings, + iconSecurityAndAccess: IconSecurity, + iconExpand: IconChevronUp, + iconResourceManagement: IconDataBase, + }, + data() { + return { + navigationItems: [ + { + id: 'overview', + label: this.$t('appNavigation.overview'), + route: '/', + icon: 'iconOverview', + }, + { + id: 'logs', + label: this.$t('appNavigation.logs'), + icon: 'iconLogs', + children: [ + { + id: 'event-logs', + label: this.$t('appNavigation.eventLogs'), + route: '/logs/event-logs', + }, + { + id: 'post-code-logs', + label: this.$t('appNavigation.postCodeLogs'), + route: '/logs/post-code-logs', + }, + ], + }, + { + id: 'hardware-status', + label: this.$t('appNavigation.hardwareStatus'), + icon: 'iconHealth', + children: [ + { + id: 'inventory', + label: this.$t('appNavigation.inventory'), + route: '/hardware-status/inventory', + }, + { + id: 'sensors', + label: this.$t('appNavigation.sensors'), + route: '/hardware-status/sensors', + }, + ], + }, + { + id: 'operations', + label: this.$t('appNavigation.operations'), + icon: 'iconControl', + children: [ + { + id: 'factory-reset', + label: this.$t('appNavigation.factoryReset'), + route: '/operations/factory-reset', + }, + { + id: 'kvm', + label: this.$t('appNavigation.kvm'), + route: '/operations/kvm', + }, + { + id: 'key-clear', + label: this.$t('appNavigation.keyClear'), + route: '/operations/key-clear', + }, + { + id: 'firmware', + label: this.$t('appNavigation.firmware'), + route: '/operations/firmware', + }, + { + id: 'reboot-bmc', + label: this.$t('appNavigation.rebootBmc'), + route: '/operations/reboot-bmc', + }, + { + id: 'serial-over-lan', + label: this.$t('appNavigation.serialOverLan'), + route: '/operations/serial-over-lan', + }, + { + id: 'server-power-operations', + label: this.$t('appNavigation.serverPowerOperations'), + route: '/operations/server-power-operations', + }, + { + id: 'virtual-media', + label: this.$t('appNavigation.virtualMedia'), + route: '/operations/virtual-media', + }, + ], + }, + { + id: 'settings', + label: this.$t('appNavigation.settings'), + icon: 'iconSettings', + children: [ + { + id: 'date-time', + label: this.$t('appNavigation.dateTime'), + route: '/settings/date-time', + }, + { + id: 'network', + label: this.$t('appNavigation.network'), + route: '/settings/network', + }, + { + id: 'power-restore-policy', + label: this.$t('appNavigation.powerRestorePolicy'), + route: '/settings/power-restore-policy', + }, + ], + }, + { + id: 'security-and-access', + label: this.$t('appNavigation.securityAndAccess'), + icon: 'iconSecurityAndAccess', + children: [ + { + id: 'sessions', + label: this.$t('appNavigation.sessions'), + route: '/security-and-access/sessions', + }, + { + id: 'ldap', + label: this.$t('appNavigation.ldap'), + route: '/security-and-access/ldap', + }, + { + id: 'user-management', + label: this.$t('appNavigation.userManagement'), + route: '/security-and-access/user-management', + }, + { + id: 'policies', + label: this.$t('appNavigation.policies'), + route: '/security-and-access/policies', + }, + { + id: 'certificates', + label: this.$t('appNavigation.certificates'), + route: '/security-and-access/certificates', + }, + ], + }, + { + id: 'resource-management', + label: this.$t('appNavigation.resourceManagement'), + icon: 'iconResourceManagement', + children: [ + { + id: 'power', + label: this.$t('appNavigation.power'), + route: '/resource-management/power', + }, + ], + }, + ], + }; + }, +}; + +export default AppNavigationMixin; diff --git a/src/components/_sila/AppNavigation/index.js b/src/components/_sila/AppNavigation/index.js new file mode 100644 index 00000000..88fe8eb6 --- /dev/null +++ b/src/components/_sila/AppNavigation/index.js @@ -0,0 +1,2 @@ +import AppNavigation from './AppNavigation'; +export default AppNavigation; |