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