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