summaryrefslogtreecommitdiff
path: root/src/components/_sila/AppNavigation
diff options
context:
space:
mode:
authorAndrey V.Kosteltsev <AKosteltsev@IBS.RU>2022-07-04 23:59:32 +0300
committerAndrey V.Kosteltsev <AKosteltsev@IBS.RU>2022-07-04 23:59:32 +0300
commit8047ae3d83ba0718fb7a42907036157e5c680b85 (patch)
tree600b017fe3a75ab4d1577eb9367afe8548401f9f /src/components/_sila/AppNavigation
parent3f4094d08b873e17464a51c817ea7d41177f848d (diff)
downloadwebui-vue-8047ae3d83ba0718fb7a42907036157e5c680b85.tar.xz
IBS: _sila UI theme
Diffstat (limited to 'src/components/_sila/AppNavigation')
-rw-r--r--src/components/_sila/AppNavigation/AppNavigation.vue255
-rw-r--r--src/components/_sila/AppNavigation/AppNavigationMixin.js182
-rw-r--r--src/components/_sila/AppNavigation/index.js2
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;