Layout.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. <template>
  2. <div
  3. class="theme-container"
  4. :class="pageClasses"
  5. @touchstart="onTouchStart"
  6. @touchend="onTouchEnd"
  7. >
  8. <Navbar
  9. v-if="shouldShowNavbar"
  10. @toggle-sidebar="toggleSidebar"
  11. />
  12. <div
  13. class="sidebar-mask"
  14. @click="toggleSidebar(false)"
  15. ></div>
  16. <Sidebar
  17. :items="sidebarItems"
  18. @toggle-sidebar="toggleSidebar"
  19. >
  20. <template #top>
  21. <slot name="sidebar-top" />
  22. </template>
  23. <template #bottom>
  24. <slot name="sidebar-bottom"/>
  25. </template>
  26. </Sidebar>
  27. <Home v-if="$page.frontmatter.home"/>
  28. <Page
  29. v-else
  30. :sidebar-items="sidebarItems"
  31. >
  32. <template #top>
  33. <slot name="page-top"/>
  34. </template>
  35. <template #bottom>
  36. <slot name="page-bottom"/>
  37. </template>
  38. </Page>
  39. </div>
  40. </template>
  41. <script>
  42. import Home from '@theme/components/Home.vue'
  43. import Navbar from '@theme/components/Navbar.vue'
  44. import Page from '@theme/components/Page.vue'
  45. import Sidebar from '@theme/components/Sidebar.vue'
  46. import { resolveSidebarItems } from '../util'
  47. export default {
  48. components: { Home, Page, Sidebar, Navbar },
  49. data () {
  50. return {
  51. isSidebarOpen: false
  52. }
  53. },
  54. computed: {
  55. shouldShowNavbar () {
  56. const { themeConfig } = this.$site
  57. const { frontmatter } = this.$page
  58. if (
  59. frontmatter.navbar === false
  60. || themeConfig.navbar === false) {
  61. return false
  62. }
  63. return (
  64. this.$title
  65. || themeConfig.logo
  66. || themeConfig.repo
  67. || themeConfig.nav
  68. || this.$themeLocaleConfig.nav
  69. )
  70. },
  71. shouldShowSidebar () {
  72. const { frontmatter } = this.$page
  73. return (
  74. !frontmatter.home
  75. && frontmatter.sidebar !== false
  76. && this.sidebarItems.length
  77. )
  78. },
  79. sidebarItems () {
  80. return resolveSidebarItems(
  81. this.$page,
  82. this.$page.regularPath,
  83. this.$site,
  84. this.$localePath
  85. )
  86. },
  87. pageClasses () {
  88. const userPageClass = this.$page.frontmatter.pageClass
  89. return [
  90. {
  91. 'no-navbar': !this.shouldShowNavbar,
  92. 'sidebar-open': this.isSidebarOpen,
  93. 'no-sidebar': !this.shouldShowSidebar
  94. },
  95. userPageClass
  96. ]
  97. }
  98. },
  99. mounted () {
  100. this.$router.afterEach(() => {
  101. this.isSidebarOpen = false
  102. })
  103. },
  104. methods: {
  105. toggleSidebar (to) {
  106. this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
  107. this.$emit('toggle-sidebar', this.isSidebarOpen)
  108. },
  109. // side swipe
  110. onTouchStart (e) {
  111. this.touchStart = {
  112. x: e.changedTouches[0].clientX,
  113. y: e.changedTouches[0].clientY
  114. }
  115. },
  116. onTouchEnd (e) {
  117. const dx = e.changedTouches[0].clientX - this.touchStart.x
  118. const dy = e.changedTouches[0].clientY - this.touchStart.y
  119. if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
  120. if (dx > 0 && this.touchStart.x <= 80) {
  121. this.toggleSidebar(true)
  122. } else {
  123. this.toggleSidebar(false)
  124. }
  125. }
  126. }
  127. }
  128. }
  129. </script>