Add responsive layout

The main navigation will be collapsed until the viewport
minimum width reaches the Bootstrap defined 'lg' breakpoint
(defaults to 992px).

- Adding motion variables and updating some CSS values to
  use existing Sass variables

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: Id159b84da6adf55fdb15842b0e33b1ede4eeceb4
diff --git a/src/assets/styles/_motion.scss b/src/assets/styles/_motion.scss
new file mode 100644
index 0000000..55a3eed
--- /dev/null
+++ b/src/assets/styles/_motion.scss
@@ -0,0 +1,14 @@
+$duration--fast-01: 70ms; //Micro-interactions such as button and toggle
+$duration--fast-02: 110ms; //Micro-interactions such as fade
+$duration--moderate-01: 150ms; //Micro-interactions, small expansion, short distance movements
+$duration--moderate-02: 240ms; //Expansion, system communication, toast
+$duration--slow-01: 400ms; //Large expansion, important system notifications
+$duration--slow-02: 700ms; //Background dimming
+
+// https://www.carbondesignsystem.com/guidelines/motion/basics/#easing
+$standard-easing--productive: cubic-bezier(0.2, 0, 0.38, 0.9);
+$standard-easing--expressive: cubic-bezier(0.4, 0.14, 0.3, 1);
+$entrance-easing--productive: cubic-bezier(0, 0, 0.38, 0.9);
+$entrance-easing--expressive: cubic-bezier(0, 0, 0.3, 1);
+$exit-easing--productive: cubic-bezier(0.2, 0, 1, 0.9);
+$exit-easing--expressive: cubic-bezier(0.4, 0.14, 1, 1);
\ No newline at end of file
diff --git a/src/assets/styles/_obmc-custom.scss b/src/assets/styles/_obmc-custom.scss
index 2e36019..aff3752 100644
--- a/src/assets/styles/_obmc-custom.scss
+++ b/src/assets/styles/_obmc-custom.scss
@@ -1,10 +1,14 @@
 $enable-rounded: false;
 $enable-validation-icons: false;
+$responsive-layout-bp: lg;
+$header-height: 56px;
+$navigation-width: 300px;
 
 // Required
 @import "~bootstrap/scss/functions";
 @import "./functions";
 @import "./colors";
+@import "./motion";
 @import "~bootstrap/scss/variables";
 @import "~bootstrap/scss/mixins";
 
diff --git a/src/components/AppHeader/AppHeader.vue b/src/components/AppHeader/AppHeader.vue
index e155a65..3919176 100644
--- a/src/components/AppHeader/AppHeader.vue
+++ b/src/components/AppHeader/AppHeader.vue
@@ -4,8 +4,21 @@
       Skip to content
     </a>
     <header id="page-header">
-      <b-navbar toggleable="lg" variant="dark" type="dark">
+      <b-navbar variant="dark" type="dark">
         <!-- Left aligned nav items -->
+        <b-button
+          class="nav-trigger"
+          aria-hidden="true"
+          title="Open navigation"
+          type="button"
+          variant="link"
+          :aria-expanded="isNavigationOpen"
+          :class="{ 'nav-open': isNavigationOpen }"
+          @click="toggleNavigation"
+        >
+          <icon-close v-if="isNavigationOpen" />
+          <icon-menu v-if="!isNavigationOpen" />
+        </b-button>
         <b-navbar-nav>
           <b-nav-text>BMC System Management</b-nav-text>
         </b-navbar-nav>
@@ -37,11 +50,19 @@
 
 <script>
 import IconAvatar from '@carbon/icons-vue/es/user--avatar/20';
+import IconClose from '@carbon/icons-vue/es/close/20';
+import IconMenu from '@carbon/icons-vue/es/menu/20';
 import IconRenew from '@carbon/icons-vue/es/renew/20';
 import StatusIcon from '../Global/StatusIcon';
+
 export default {
   name: 'AppHeader',
-  components: { IconAvatar, IconRenew, StatusIcon },
+  components: { IconAvatar, IconClose, IconMenu, IconRenew, StatusIcon },
+  data() {
+    return {
+      isNavigationOpen: false
+    };
+  },
   computed: {
     hostStatus() {
       return this.$store.getters['global/hostStatus'];
@@ -77,6 +98,12 @@
     this.getHostInfo();
     this.getEvents();
   },
+  mounted() {
+    this.$root.$on(
+      'change:isNavigationOpen',
+      isNavigationOpen => (this.isNavigationOpen = isNavigationOpen)
+    );
+  },
   methods: {
     getHostInfo() {
       this.$store.dispatch('global/getHostStatus');
@@ -89,6 +116,9 @@
     },
     logout() {
       this.$store.dispatch('authentication/logout');
+    },
+    toggleNavigation() {
+      this.$root.$emit('toggle:navigation');
     }
   }
 };
@@ -99,11 +129,11 @@
   position: absolute;
   top: -60px;
   left: 0.5rem;
-  z-index: 10;
-  transition: 150ms cubic-bezier(0.4, 0.14, 1, 1);
+  z-index: $zindex-popover;
+  transition: $duration--moderate-01 $exit-easing--expressive;
   &:focus {
     top: 0.5rem;
-    transition-timing-function: cubic-bezier(0, 0, 0.3, 1);
+    transition-timing-function: $entrance-easing--expressive;
   }
 }
 .navbar-dark {
@@ -113,8 +143,36 @@
   }
 }
 .nav-item {
+  fill: $light;
+}
+
+.navbar {
+  padding: 0;
+  height: $header-height;
+  overflow: hidden;
+}
+
+.navbar-nav {
+  padding: 0 $spacer;
+}
+
+.nav-trigger {
+  fill: $white;
+  width: $header-height;
+  height: $header-height;
+  transition: none;
+
   svg {
-    fill: $light;
+    margin: 0;
+  }
+
+  &:hover {
+    fill: $white;
+    background-color: $gray-900;
+  }
+
+  @include media-breakpoint-up($responsive-layout-bp) {
+    display: none;
   }
 }
 </style>
diff --git a/src/components/AppNavigation/AppNavigation.vue b/src/components/AppNavigation/AppNavigation.vue
index 28f4c71..2847e66 100644
--- a/src/components/AppNavigation/AppNavigation.vue
+++ b/src/components/AppNavigation/AppNavigation.vue
@@ -1,59 +1,78 @@
 <template>
-  <b-nav vertical>
-    <b-nav-item to="/"><icon-overview />Overview</b-nav-item>
+  <div>
+    <div class="nav-container" :class="{ open: isNavigationOpen }">
+      <nav ref="nav">
+        <b-nav vertical>
+          <b-nav-item to="/"><icon-overview />Overview</b-nav-item>
 
-    <li class="nav-item">
-      <b-button v-b-toggle.health-menu variant="link">
-        <icon-health />Health
-        <icon-expand class="icon-expand" />
-      </b-button>
-      <b-collapse id="health-menu" tag="ul" class="nav-item__nav">
-        <b-nav-item href="javascript:void(0)">Event Log</b-nav-item>
-        <b-nav-item href="javascript:void(0)">Hardware Status</b-nav-item>
-        <b-nav-item href="javascript:void(0)">Sensors</b-nav-item>
-      </b-collapse>
-    </li>
+          <li class="nav-item">
+            <b-button v-b-toggle.health-menu variant="link">
+              <icon-health />Health
+              <icon-expand class="icon-expand" />
+            </b-button>
+            <b-collapse id="health-menu" tag="ul" class="nav-item__nav">
+              <b-nav-item href="javascript:void(0)">Event Log</b-nav-item>
+              <b-nav-item href="javascript:void(0)">Hardware Status</b-nav-item>
+              <b-nav-item href="javascript:void(0)">Sensors</b-nav-item>
+            </b-collapse>
+          </li>
 
-    <li class="nav-item">
-      <b-button v-b-toggle.control-menu variant="link">
-        <icon-control />Control
-        <icon-expand class="icon-expand" />
-      </b-button>
-      <b-collapse id="control-menu" tag="ul" class="nav-item__nav">
-        <b-nav-item href="javascript:void(0)">Manage power usage</b-nav-item>
-        <b-nav-item href="javascript:void(0)">Server LED</b-nav-item>
-        <b-nav-item href="javascript:void(0)">
-          Server power operations
-        </b-nav-item>
-      </b-collapse>
-    </li>
+          <li class="nav-item">
+            <b-button v-b-toggle.control-menu variant="link">
+              <icon-control />Control
+              <icon-expand class="icon-expand" />
+            </b-button>
+            <b-collapse id="control-menu" tag="ul" class="nav-item__nav">
+              <b-nav-item href="javascript:void(0)">
+                Manage power usage
+              </b-nav-item>
+              <b-nav-item href="javascript:void(0)">Server LED</b-nav-item>
+              <b-nav-item href="javascript:void(0)">
+                Server power operations
+              </b-nav-item>
+            </b-collapse>
+          </li>
 
-    <li class="nav-item">
-      <b-button v-b-toggle.configuration-menu variant="link">
-        <icon-configuration />Configuration
-        <icon-expand class="icon-expand" />
-      </b-button>
-      <b-collapse id="configuration-menu" tag="ul" class="nav-item__nav">
-        <b-nav-item href="javascript:void(0)">Firmware</b-nav-item>
-        <b-nav-item href="javascript:void(0)">Network settings</b-nav-item>
-        <b-nav-item href="javascript:void(0)">SNMP settings</b-nav-item>
-      </b-collapse>
-    </li>
+          <li class="nav-item">
+            <b-button v-b-toggle.configuration-menu variant="link">
+              <icon-configuration />Configuration
+              <icon-expand class="icon-expand" />
+            </b-button>
+            <b-collapse id="configuration-menu" tag="ul" class="nav-item__nav">
+              <b-nav-item href="javascript:void(0)">Firmware</b-nav-item>
+              <b-nav-item href="javascript:void(0)">
+                Network settings
+              </b-nav-item>
+              <b-nav-item href="javascript:void(0)">SNMP settings</b-nav-item>
+            </b-collapse>
+          </li>
 
-    <li class="nav-item">
-      <b-button v-b-toggle.access-control-menu variant="link">
-        <icon-access-control />Access Control
-        <icon-expand class="icon-expand" />
-      </b-button>
-      <b-collapse id="access-control-menu" tag="ul" class="nav-item__nav">
-        <b-nav-item href="javascript:void(0)">LDAP</b-nav-item>
-        <b-nav-item to="/access-control/local-user-management">
-          Local user management
-        </b-nav-item>
-        <b-nav-item href="javascript:void(0)">SSL Certificates</b-nav-item>
-      </b-collapse>
-    </li>
-  </b-nav>
+          <li class="nav-item">
+            <b-button v-b-toggle.access-control-menu variant="link">
+              <icon-access-control />Access Control
+              <icon-expand class="icon-expand" />
+            </b-button>
+            <b-collapse id="access-control-menu" tag="ul" class="nav-item__nav">
+              <b-nav-item href="javascript:void(0)">LDAP</b-nav-item>
+              <b-nav-item to="/access-control/local-user-management">
+                Local user management
+              </b-nav-item>
+              <b-nav-item href="javascript:void(0)">
+                SSL Certificates
+              </b-nav-item>
+            </b-collapse>
+          </li>
+        </b-nav>
+      </nav>
+    </div>
+    <transition name="fade">
+      <div
+        v-if="isNavigationOpen"
+        class="nav-overlay"
+        @click="toggleIsOpen"
+      ></div>
+    </transition>
+  </div>
 </template>
 
 <script>
@@ -73,6 +92,27 @@
     iconConfiguration: IconSettings,
     iconAccessControl: IconPassword,
     iconExpand: IconChevronUp
+  },
+  data() {
+    return {
+      isNavigationOpen: false
+    };
+  },
+  watch: {
+    $route: function() {
+      this.isNavigationOpen = false;
+    },
+    isNavigationOpen: function(isNavigationOpen) {
+      this.$root.$emit('change:isNavigationOpen', isNavigationOpen);
+    }
+  },
+  mounted() {
+    this.$root.$on('toggle:navigation', () => this.toggleIsOpen());
+  },
+  methods: {
+    toggleIsOpen() {
+      this.isNavigationOpen = !this.isNavigationOpen;
+    }
   }
 };
 </script>
@@ -88,7 +128,6 @@
 }
 
 .nav {
-  min-height: 100%;
   padding-top: $spacer;
 }
 
@@ -155,4 +194,55 @@
     background-color: $primary;
   }
 }
+
+.nav-container {
+  position: fixed;
+  width: $navigation-width;
+  top: $header-height;
+  bottom: 0;
+  left: 0;
+  z-index: $zindex-fixed;
+  overflow-y: auto;
+  background-color: $gray-200;
+  transform: translateX(-$navigation-width);
+  transition: transform $exit-easing--productive $duration--moderate-02;
+
+  &.open {
+    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,
+  &.fade-leave-to {
+    opacity: 0;
+  }
+
+  @include media-breakpoint-up($responsive-layout-bp) {
+    display: none;
+  }
+}
 </style>
diff --git a/src/components/Global/PageContainer.vue b/src/components/Global/PageContainer.vue
index 8efbf7b..8396bd5 100644
--- a/src/components/Global/PageContainer.vue
+++ b/src/components/Global/PageContainer.vue
@@ -1,5 +1,5 @@
 <template>
-  <main id="main-content">
+  <main id="main-content" class="page-container">
     <slot />
   </main>
 </template>
@@ -12,12 +12,14 @@
 
 <style lang="scss" scoped>
 main {
+  width: 100%;
+  height: 100%;
   padding-top: $spacer * 1.5;
   padding-bottom: $spacer * 3;
-  padding-left: $spacer * 2;
+  padding-left: $spacer;
   padding-right: $spacer;
-  background-color: $gray-100;
-  height: 100%;
-  min-height: calc(100vh - 60px /*header height*/);
+  @include media-breakpoint-up($responsive-layout-bp) {
+    padding-left: $spacer * 2;
+  }
 }
 </style>
diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue
index 33faa38..8edc338 100644
--- a/src/layouts/AppLayout.vue
+++ b/src/layouts/AppLayout.vue
@@ -1,18 +1,10 @@
 <template>
-  <div>
-    <app-header ref="focusTarget" @refresh="refresh" />
-    <b-container fluid class="page-container">
-      <b-row no-gutters>
-        <b-col tag="nav" cols="12" md="3" lg="2">
-          <app-navigation />
-        </b-col>
-        <b-col cols="12" md="9" lg="10">
-          <page-container>
-            <router-view ref="routerView" :key="routerKey" />
-          </page-container>
-        </b-col>
-      </b-row>
-    </b-container>
+  <div class="app-container">
+    <app-header ref="focusTarget" class="app-header" @refresh="refresh" />
+    <app-navigation class="app-navigation" />
+    <page-container class="app-content">
+      <router-view ref="routerView" :key="routerKey" />
+    </page-container>
   </div>
 </template>
 
@@ -62,10 +54,35 @@
 </script>
 
 <style lang="scss" scoped>
-.page-container {
-  margin-right: 0;
-  margin-left: 0;
-  padding-right: 0;
-  padding-left: 0;
+.app-container {
+  display: grid;
+  grid-template-columns: 100%;
+  grid-template-rows: auto;
+  grid-template-areas:
+    'header'
+    'content';
+
+  @include media-breakpoint-up($responsive-layout-bp) {
+    grid-template-columns: $navigation-width 1fr;
+    grid-template-areas:
+      'header header'
+      'navigation content';
+  }
+}
+
+.app-header {
+  grid-area: header;
+  position: sticky;
+  top: 0;
+  z-index: $zindex-fixed + 1;
+}
+
+.app-navigation {
+  grid-area: navigation;
+}
+
+.app-content {
+  grid-area: content;
+  background-color: $white;
 }
 </style>
diff --git a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
index e71387d..a5ba7ba 100644
--- a/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
+++ b/src/views/AccessControl/LocalUserManagement/LocalUserManagement.vue
@@ -1,8 +1,8 @@
 <template>
-  <b-container class="ml-0">
+  <b-container fluid>
     <page-title />
     <b-row>
-      <b-col lg="10" class="text-right">
+      <b-col xl="9" class="text-right">
         <b-button variant="link" @click="initModalSettings">
           Account policy settings
           <icon-settings />
@@ -14,7 +14,7 @@
       </b-col>
     </b-row>
     <b-row>
-      <b-col lg="10">
+      <b-col xl="9">
         <b-table show-empty :fields="fields" :items="tableItems">
           <template v-slot:cell(actions)="data">
             <b-button
@@ -40,7 +40,7 @@
       </b-col>
     </b-row>
     <b-row>
-      <b-col lg="8">
+      <b-col xl="8">
         <b-button v-b-toggle.collapse-role-table variant="link" class="mt-3">
           View privilege role descriptions
           <icon-chevron />
diff --git a/src/views/Overview/OverviewQuickLinks.vue b/src/views/Overview/OverviewQuickLinks.vue
index 0921cb9..3f52d81 100644
--- a/src/views/Overview/OverviewQuickLinks.vue
+++ b/src/views/Overview/OverviewQuickLinks.vue
@@ -84,7 +84,7 @@
 }
 
 .quicklinks {
-  background: $white;
+  background: $gray-200;
   display: grid;
   grid-gap: 1rem;
   padding: 1rem;
@@ -98,7 +98,7 @@
   }
 }
 
-@include media-breakpoint-up(lg) {
+@include media-breakpoint-up(xl) {
   .quicklinks {
     grid-template-columns: repeat(4, 1fr);
   }