Layout.vue 4.5 KB
Newer Older
E
Evan You 已提交
1
<template>
E
Evan You 已提交
2
  <div class="theme-container"
3
    :class="pageClasses"
E
Evan You 已提交
4 5
    @touchstart="onTouchStart"
    @touchend="onTouchEnd">
E
tweaks  
Evan You 已提交
6
    <Navbar v-if="shouldShowNavbar" @toggle-sidebar="toggleSidebar"/>
7
    <div class="sidebar-mask" @click="toggleSidebar(false)"></div>
8 9 10 11
    <Sidebar :items="sidebarItems" @toggle-sidebar="toggleSidebar">
      <slot name="sidebar-top" slot="top"/>
      <slot name="sidebar-bottom" slot="bottom"/>
    </Sidebar>
E
Evan You 已提交
12 13 14 15
    <div class="custom-layout" v-if="$page.frontmatter.layout">
      <component :is="$page.frontmatter.layout"/>
    </div>
    <Home v-else-if="$page.frontmatter.home"/>
16 17 18 19
    <Page v-else :sidebar-items="sidebarItems">
      <slot name="page-top" slot="top"/>
      <slot name="page-bottom" slot="bottom"/>
    </Page>
E
Evan You 已提交
20 21 22 23
  </div>
</template>

<script>
24
import Vue from 'vue'
E
Evan You 已提交
25
import nprogress from 'nprogress'
E
Evan You 已提交
26
import Home from './Home.vue'
E
Evan You 已提交
27
import Navbar from './Navbar.vue'
E
Evan You 已提交
28
import Page from './Page.vue'
E
Evan You 已提交
29
import Sidebar from './Sidebar.vue'
30
import { pathToComponentName } from '@app/util'
E
Evan You 已提交
31
import { resolveSidebarItems } from './util'
E
Evan You 已提交
32

E
Evan You 已提交
33
export default {
E
Evan You 已提交
34
  components: { Home, Page, Sidebar, Navbar },
E
Evan You 已提交
35 36 37 38 39
  data () {
    return {
      isSidebarOpen: false
    }
  },
E
Evan You 已提交
40

E
tweaks  
Evan You 已提交
41 42 43
  computed: {
    shouldShowNavbar () {
      const { themeConfig } = this.$site
44 45
      const { frontmatter } = this.$page
      if (frontmatter.navbar === false) return false
E
tweaks  
Evan You 已提交
46
      return (
47
        this.$title ||
E
tweaks  
Evan You 已提交
48 49
        themeConfig.logo ||
        themeConfig.repo ||
50 51
        themeConfig.nav ||
        this.$themeLocaleConfig.nav
E
tweaks  
Evan You 已提交
52 53 54 55 56 57
      )
    },
    shouldShowSidebar () {
      const { themeConfig } = this.$site
      const { frontmatter } = this.$page
      return (
E
Evan You 已提交
58 59
        !frontmatter.layout &&
        !frontmatter.home &&
60 61
        frontmatter.sidebar !== false &&
        this.sidebarItems.length
E
tweaks  
Evan You 已提交
62
      )
E
Evan You 已提交
63 64 65 66 67
    },
    sidebarItems () {
      return resolveSidebarItems(
        this.$page,
        this.$route,
68 69
        this.$site,
        this.$localePath
E
Evan You 已提交
70
      )
71 72 73 74 75 76 77 78 79 80 81
    },
    pageClasses() {
      const userPageClass = this.$page.frontmatter.pageClass
      return [
        {
          'no-navbar': !this.shouldShowNavbar,
          'sidebar-open': this.isSidebarOpen,
          'no-sidebar': !this.shouldShowSidebar,
        },
        userPageClass
      ]
E
tweaks  
Evan You 已提交
82 83 84
    }
  },

E
Evan You 已提交
85 86
  created () {
    if (this.$ssrContext) {
87
      this.$ssrContext.title = this.$title
88 89
      this.$ssrContext.lang = this.$lang
      this.$ssrContext.description = this.$page.description || this.$description
E
Evan You 已提交
90
    }
91

E
Evan You 已提交
92 93
  },

E
Evan You 已提交
94
  mounted () {
E
Evan You 已提交
95 96 97
    // update title / meta tags
    this.currentMetaTags = []
    const updateMeta = () => {
98
      document.title = this.$title
99 100 101 102 103 104 105 106 107
      document.documentElement.lang = this.$lang
      const meta = [
        {
          name: 'description',
          content: this.$description
        },
        ...(this.$page.frontmatter.meta || [])
      ]
      this.currentMetaTags = updateMetaTags(meta, this.currentMetaTags)
E
Evan You 已提交
108 109 110 111 112
    }
    this.$watch('$page', updateMeta)
    updateMeta()

    // configure progress bar
E
Evan You 已提交
113 114 115
    nprogress.configure({ showSpinner: false })

    this.$router.beforeEach((to, from, next) => {
116
      if (to.path !== from.path && !Vue.component(pathToComponentName(to.path))) {
E
Evan You 已提交
117 118
        nprogress.start()
      }
E
Evan You 已提交
119 120 121 122 123
      next()
    })

    this.$router.afterEach(() => {
      nprogress.done()
E
Evan You 已提交
124
      this.isSidebarOpen = false
E
Evan You 已提交
125
    })
E
Evan You 已提交
126
  },
E
Evan You 已提交
127 128 129 130 131

  beforeDestroy () {
    updateMetaTags(null, this.currentMetaTags)
  },

E
Evan You 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
  methods: {
    toggleSidebar (to) {
      this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
    },
    // side swipe
    onTouchStart (e) {
      this.touchStart = {
        x: e.changedTouches[0].clientX,
        y: e.changedTouches[0].clientY
      }
    },
    onTouchEnd (e) {
      const dx = e.changedTouches[0].clientX - this.touchStart.x
      const dy = e.changedTouches[0].clientY - this.touchStart.y
      if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
        if (dx > 0 && this.touchStart.x <= 80) {
          this.toggleSidebar(true)
        } else {
          this.toggleSidebar(false)
        }
      }
    }
E
Evan You 已提交
154 155
  }
}
E
Evan You 已提交
156

157
function updateMetaTags (meta, current) {
E
Evan You 已提交
158 159 160 161 162
  if (current) {
    current.forEach(c => {
      document.head.removeChild(c)
    })
  }
163 164
  if (meta) {
    return meta.map(m => {
E
Evan You 已提交
165 166 167 168 169 170 171 172 173
      const tag = document.createElement('meta')
      Object.keys(m).forEach(key => {
        tag.setAttribute(key, m[key])
      })
      document.head.appendChild(tag)
      return tag
    })
  }
}
E
Evan You 已提交
174 175
</script>

E
Evan You 已提交
176
<style src="prismjs/themes/prism-tomorrow.css"></style>
E
Evan You 已提交
177
<style src="./styles/theme.styl" lang="stylus"></style>