xref: /openbmc/webui-vue/src/layouts/AppLayout.vue (revision 96d9a6aa)
1<template>
2  <div class="app-container">
3    <app-header ref="focusTarget" class="app-header" @refresh="refresh" />
4    <app-navigation class="app-navigation" />
5    <page-container class="app-content">
6      <router-view ref="routerView" :key="routerKey" />
7      <!-- Scroll to top button -->
8      <button-back-to-top />
9    </page-container>
10  </div>
11</template>
12
13<script>
14import AppHeader from '@/components/AppHeader';
15import AppNavigation from '@/components/AppNavigation';
16import PageContainer from '@/components/Global/PageContainer';
17import ButtonBackToTop from '@/components/Global/ButtonBackToTop';
18
19export default {
20  name: 'App',
21  components: {
22    AppHeader,
23    AppNavigation,
24    PageContainer,
25    ButtonBackToTop,
26  },
27  data() {
28    return {
29      routerKey: 0,
30    };
31  },
32  watch: {
33    $route: function () {
34      // $nextTick = DOM updated
35      this.$nextTick(function () {
36        // Get the focusTarget DOM element
37        let focusTarget = this.$refs.focusTarget.$el;
38
39        // Make focustarget programmatically focussable
40        focusTarget.setAttribute('tabindex', '-1');
41
42        // Focus element
43        focusTarget.focus();
44
45        // Remove tabindex from focustarget
46        // Reason: https://axesslab.com/skip-links/#update-3-a-comment-from-gov-uk
47        focusTarget.removeAttribute('tabindex');
48      });
49    },
50  },
51  methods: {
52    refresh() {
53      // Changing the component :key value will trigger
54      // a component re-rendering and 'refresh' the view
55      this.routerKey += 1;
56    },
57  },
58};
59</script>
60
61<style lang="scss" scoped>
62.app-container {
63  display: grid;
64  grid-template-columns: 100%;
65  grid-template-rows: auto;
66  grid-template-areas:
67    'header'
68    'content';
69
70  @include media-breakpoint-up($responsive-layout-bp) {
71    grid-template-columns: $navigation-width 1fr;
72    grid-template-areas:
73      'header header'
74      'navigation content';
75  }
76}
77
78.app-header {
79  grid-area: header;
80  position: sticky;
81  top: 0;
82  z-index: $zindex-fixed + 1;
83}
84
85.app-navigation {
86  grid-area: navigation;
87}
88
89.app-content {
90  grid-area: content;
91  background-color: $white;
92}
93</style>
94