1<template> 2 <div> 3 <div class="nav-container" :class="{ open: isNavigationOpen }"> 4 <nav ref="nav" :aria-label="$t('appNavigation.primaryNavigation')"> 5 <b-nav vertical> 6 <b-nav-item to="/"> 7 <icon-overview /> 8 {{ $t('appNavigation.overview') }} 9 </b-nav-item> 10 11 <li class="nav-item"> 12 <b-button v-b-toggle.health-menu variant="link"> 13 <icon-health /> 14 {{ $t('appNavigation.health') }} 15 <icon-expand class="icon-expand" /> 16 </b-button> 17 <b-collapse id="health-menu" tag="ul" class="nav-item__nav"> 18 <b-nav-item to="/health/event-logs"> 19 {{ $t('appNavigation.eventLogs') }} 20 </b-nav-item> 21 <b-nav-item to="/health/hardware-status"> 22 {{ $t('appNavigation.hardwareStatus') }} 23 </b-nav-item> 24 <b-nav-item to="/health/sensors"> 25 {{ $t('appNavigation.sensors') }} 26 </b-nav-item> 27 </b-collapse> 28 </li> 29 30 <li class="nav-item"> 31 <b-button v-b-toggle.control-menu variant="link"> 32 <icon-control /> 33 {{ $t('appNavigation.control') }} 34 <icon-expand class="icon-expand" /> 35 </b-button> 36 <b-collapse id="control-menu" tag="ul" class="nav-item__nav"> 37 <b-nav-item to="/control/manage-power-usage"> 38 {{ $t('appNavigation.managePowerUsage') }} 39 </b-nav-item> 40 <b-nav-item to="/control/reboot-bmc"> 41 {{ $t('appNavigation.rebootBmc') }} 42 </b-nav-item> 43 <b-nav-item to="/control/serial-over-lan"> 44 {{ $t('appNavigation.serialOverLan') }} 45 </b-nav-item> 46 <b-nav-item to="/control/server-led"> 47 {{ $t('appNavigation.serverLed') }} 48 </b-nav-item> 49 <b-nav-item to="/control/server-power-operations"> 50 {{ $t('appNavigation.serverPowerOperations') }} 51 </b-nav-item> 52 </b-collapse> 53 </li> 54 55 <li class="nav-item"> 56 <b-button v-b-toggle.configuration-menu variant="link"> 57 <icon-configuration /> 58 {{ $t('appNavigation.configuration') }} 59 <icon-expand class="icon-expand" /> 60 </b-button> 61 <b-collapse id="configuration-menu" tag="ul" class="nav-item__nav"> 62 <b-nav-item to="/configuration/date-time-settings"> 63 {{ $t('appNavigation.dateTimeSettings') }} 64 </b-nav-item> 65 <b-nav-item href="javascript:void(0)"> 66 {{ $t('appNavigation.firmware') }} 67 </b-nav-item> 68 <b-nav-item to="/configuration/network-settings"> 69 {{ $t('appNavigation.networkSettings') }} 70 </b-nav-item> 71 <b-nav-item href="javascript:void(0)"> 72 {{ $t('appNavigation.snmpSettings') }} 73 </b-nav-item> 74 </b-collapse> 75 </li> 76 77 <li class="nav-item"> 78 <b-button v-b-toggle.access-control-menu variant="link"> 79 <icon-access-control /> 80 {{ $t('appNavigation.accessControl') }} 81 <icon-expand class="icon-expand" /> 82 </b-button> 83 <b-collapse id="access-control-menu" tag="ul" class="nav-item__nav"> 84 <b-nav-item to="/access-control/ldap"> 85 {{ $t('appNavigation.ldap') }} 86 </b-nav-item> 87 <b-nav-item to="/access-control/local-user-management"> 88 {{ $t('appNavigation.localUserManagement') }} 89 </b-nav-item> 90 <b-nav-item to="/access-control/ssl-certificates"> 91 {{ $t('appNavigation.sslCertificates') }} 92 </b-nav-item> 93 </b-collapse> 94 </li> 95 </b-nav> 96 </nav> 97 </div> 98 <transition name="fade"> 99 <div 100 v-if="isNavigationOpen" 101 id="nav-overlay" 102 class="nav-overlay" 103 @click="toggleIsOpen" 104 ></div> 105 </transition> 106 </div> 107</template> 108 109<script> 110import IconAnalytics from '@carbon/icons-vue/es/analytics/16'; 111import IconDataCheck from '@carbon/icons-vue/es/data--check/16'; 112import IconSettingsAdjust from '@carbon/icons-vue/es/settings--adjust/16'; 113import IconSettings from '@carbon/icons-vue/es/settings/16'; 114import IconPassword from '@carbon/icons-vue/es/password/16'; 115import IconChevronUp from '@carbon/icons-vue/es/chevron--up/16'; 116 117export default { 118 name: 'AppNavigation', 119 components: { 120 iconOverview: IconAnalytics, 121 iconHealth: IconDataCheck, 122 iconControl: IconSettingsAdjust, 123 iconConfiguration: IconSettings, 124 iconAccessControl: IconPassword, 125 iconExpand: IconChevronUp 126 }, 127 data() { 128 return { 129 isNavigationOpen: false 130 }; 131 }, 132 watch: { 133 $route: function() { 134 this.isNavigationOpen = false; 135 }, 136 isNavigationOpen: function(isNavigationOpen) { 137 this.$root.$emit('change:isNavigationOpen', isNavigationOpen); 138 } 139 }, 140 mounted() { 141 this.$root.$on('toggle:navigation', () => this.toggleIsOpen()); 142 }, 143 methods: { 144 toggleIsOpen() { 145 this.isNavigationOpen = !this.isNavigationOpen; 146 } 147 } 148}; 149</script> 150 151<style scoped lang="scss"> 152@import 'src/assets/styles/helpers'; 153 154svg { 155 fill: currentColor; 156 height: 1.2rem; 157 width: 1.2rem; 158 margin-left: 0 !important; //!important overriding button specificity 159 vertical-align: text-bottom; 160 &:not(.icon-expand) { 161 margin-right: $spacer; 162 } 163} 164 165.nav { 166 padding-top: $spacer / 4; 167 @include media-breakpoint-up($responsive-layout-bp) { 168 padding-top: $spacer; 169 } 170} 171 172.nav-item__nav { 173 list-style: none; 174 padding-left: 0; 175 margin-left: 0; 176 177 .nav-item { 178 outline: none; 179 } 180 181 .nav-link { 182 padding-left: $spacer * 4; 183 outline: none; 184 185 &:not(.nav-link--current) { 186 font-weight: normal; 187 } 188 } 189} 190 191.btn-link { 192 width: 100%; 193 text-align: left; 194 text-decoration: none !important; 195 border-radius: 0; 196 197 &.collapsed { 198 .icon-expand { 199 transform: rotate(180deg); 200 } 201 } 202} 203 204.icon-expand { 205 float: right; 206 margin-top: $spacer / 4; 207} 208 209.btn-link, 210.nav-link { 211 position: relative; 212 font-weight: $headings-font-weight; 213 padding-left: $spacer; // defining consistent padding for links and buttons 214 padding-right: $spacer; 215 color: $secondary; 216 217 &:hover { 218 background-color: $primary-nav-hover; 219 color: $dark; 220 } 221 222 &:focus { 223 box-shadow: $btn-focus-box-shadow; 224 color: $dark; 225 } 226} 227 228.nav-link--current, 229.nav-link--current:hover, 230.nav-link--current:focus { 231 font-weight: $headings-font-weight; 232 background-color: $secondary; 233 color: $light; 234 cursor: default; 235 236 &::before { 237 content: ''; 238 position: absolute; 239 top: 0; 240 bottom: 0; 241 left: 0; 242 width: 4px; 243 background-color: $primary; 244 } 245} 246 247.nav-container { 248 position: fixed; 249 width: $navigation-width; 250 top: $header-height; 251 bottom: 0; 252 left: 0; 253 z-index: $zindex-fixed; 254 overflow-y: auto; 255 background-color: $container-bgd; 256 transform: translateX(-$navigation-width); 257 transition: transform $exit-easing--productive $duration--moderate-02; 258 @include media-breakpoint-down(md) { 259 z-index: $zindex-fixed + 2; 260 } 261 262 &.open, 263 &:focus-within { 264 transform: translateX(0); 265 transition-timing-function: $entrance-easing--productive; 266 } 267 268 @include media-breakpoint-up($responsive-layout-bp) { 269 transition-duration: $duration--fast-01; 270 transform: translateX(0); 271 } 272} 273 274.nav-overlay { 275 position: fixed; 276 top: $header-height; 277 bottom: 0; 278 left: 0; 279 right: 0; 280 z-index: $zindex-fixed + 1; 281 background-color: $black; 282 opacity: 0.5; 283 284 &.fade-enter-active { 285 transition: opacity $duration--moderate-02 $entrance-easing--productive; 286 } 287 288 &.fade-leave-active { 289 transition: opacity $duration--fast-02 $exit-easing--productive; 290 } 291 292 &.fade-enter, 293 &.fade-leave-to { 294 opacity: 0; 295 } 296 297 @include media-breakpoint-up($responsive-layout-bp) { 298 display: none; 299 } 300} 301</style> 302