You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
7.4 KiB

  1. <template lang="pug">
  2. div
  3. .pa-3.d-flex(v-if='navMode === `MIXED`', :class='$vuetify.theme.dark ? `grey darken-5` : `blue darken-3`')
  4. v-btn(
  5. depressed
  6. :color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
  7. style='min-width:0;'
  8. @click='goHome'
  9. :aria-label='$t(`common:header.home`)'
  10. )
  11. v-icon(size='20') mdi-home
  12. v-btn.ml-3(
  13. v-if='currentMode === `custom`'
  14. depressed
  15. :color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
  16. style='flex: 1 1 100%;'
  17. @click='switchMode(`browse`)'
  18. )
  19. v-icon(left) mdi-file-tree
  20. .body-2.text-none {{$t('common:sidebar.browse')}}
  21. v-btn.ml-3(
  22. v-else-if='currentMode === `browse`'
  23. depressed
  24. :color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
  25. style='flex: 1 1 100%;'
  26. @click='switchMode(`custom`)'
  27. )
  28. v-icon(left) mdi-navigation
  29. .body-2.text-none {{$t('common:sidebar.mainMenu')}}
  30. v-divider
  31. //-> Custom Navigation
  32. v-list.py-2(v-if='currentMode === `custom`', dense, :class='color', :dark='dark')
  33. template(v-for='item of items')
  34. v-list-item(
  35. v-if='item.k === `link`'
  36. :href='item.t'
  37. :target='item.y === `externalblank` ? `_blank` : `_self`'
  38. :rel='item.y === `externalblank` ? `noopener` : ``'
  39. )
  40. v-list-item-avatar(size='24', tile)
  41. v-icon(v-if='item.c.match(/fa[a-z] fa-/)', size='19') {{ item.c }}
  42. v-icon(v-else) {{ item.c }}
  43. v-list-item-title {{ item.l }}
  44. v-divider.my-2(v-else-if='item.k === `divider`')
  45. v-subheader.pl-4(v-else-if='item.k === `header`') {{ item.l }}
  46. //-> Browse
  47. v-list.py-2(v-else-if='currentMode === `browse`', dense, :class='color', :dark='dark')
  48. template(v-if='currentParent.id > 0')
  49. v-list-item(v-for='(item, idx) of parents', :key='`parent-` + item.id', @click='fetchBrowseItems(item)', style='min-height: 30px;')
  50. v-list-item-avatar(size='18', :style='`padding-left: ` + (idx * 8) + `px; width: auto; margin: 0 5px 0 0;`')
  51. v-icon(small) mdi-folder-open
  52. v-list-item-title {{ item.title }}
  53. v-divider.mt-2
  54. v-list-item.mt-2(v-if='currentParent.pageId > 0', :href='`/` + currentParent.locale + `/` + currentParent.path', :key='`directorypage-` + currentParent.id', :input-value='path === currentParent.path')
  55. v-list-item-avatar(size='24')
  56. v-icon mdi-text-box
  57. v-list-item-title {{ currentParent.title }}
  58. v-subheader.pl-4 {{$t('common:sidebar.currentDirectory')}}
  59. template(v-for='item of currentItems')
  60. v-list-item(v-if='item.isFolder', :key='`childfolder-` + item.id', @click='fetchBrowseItems(item)')
  61. v-list-item-avatar(size='24')
  62. v-icon mdi-folder
  63. v-list-item-title {{ item.title }}
  64. v-list-item(v-else, :href='`/` + item.locale + `/` + item.path', :key='`childpage-` + item.id', :input-value='path === item.path')
  65. v-list-item-avatar(size='24')
  66. v-icon mdi-text-box
  67. v-list-item-title {{ item.title }}
  68. </template>
  69. <script>
  70. import _ from 'lodash'
  71. import gql from 'graphql-tag'
  72. import { get } from 'vuex-pathify'
  73. /* global siteLangs */
  74. export default {
  75. props: {
  76. color: {
  77. type: String,
  78. default: 'primary'
  79. },
  80. dark: {
  81. type: Boolean,
  82. default: true
  83. },
  84. items: {
  85. type: Array,
  86. default: () => []
  87. },
  88. navMode: {
  89. type: String,
  90. default: 'MIXED'
  91. }
  92. },
  93. data() {
  94. return {
  95. currentMode: 'custom',
  96. currentItems: [],
  97. currentParent: {
  98. id: 0,
  99. title: '/ (root)'
  100. },
  101. parents: [],
  102. loadedCache: []
  103. }
  104. },
  105. computed: {
  106. path: get('page/path'),
  107. locale: get('page/locale')
  108. },
  109. methods: {
  110. switchMode (mode) {
  111. this.currentMode = mode
  112. window.localStorage.setItem('navPref', mode)
  113. if (mode === `browse` && this.loadedCache.length < 1) {
  114. this.loadFromCurrentPath()
  115. }
  116. },
  117. async fetchBrowseItems (item) {
  118. this.$store.commit(`loadingStart`, 'browse-load')
  119. if (!item) {
  120. item = this.currentParent
  121. }
  122. if (this.loadedCache.indexOf(item.id) < 0) {
  123. this.currentItems = []
  124. }
  125. if (item.id === 0) {
  126. this.parents = []
  127. } else {
  128. const flushRightIndex = _.findIndex(this.parents, ['id', item.id])
  129. if (flushRightIndex >= 0) {
  130. this.parents = _.take(this.parents, flushRightIndex)
  131. }
  132. if (this.parents.length < 1) {
  133. this.parents.push(this.currentParent)
  134. }
  135. this.parents.push(item)
  136. }
  137. this.currentParent = item
  138. const resp = await this.$apollo.query({
  139. query: gql`
  140. query ($parent: Int, $locale: String!) {
  141. pages {
  142. tree(parent: $parent, mode: ALL, locale: $locale) {
  143. id
  144. path
  145. title
  146. isFolder
  147. pageId
  148. parent
  149. locale
  150. }
  151. }
  152. }
  153. `,
  154. fetchPolicy: 'cache-first',
  155. variables: {
  156. parent: item.id,
  157. locale: this.locale
  158. }
  159. })
  160. this.loadedCache = _.union(this.loadedCache, [item.id])
  161. this.currentItems = _.get(resp, 'data.pages.tree', [])
  162. this.$store.commit(`loadingStop`, 'browse-load')
  163. },
  164. async loadFromCurrentPath() {
  165. this.$store.commit(`loadingStart`, 'browse-load')
  166. const resp = await this.$apollo.query({
  167. query: gql`
  168. query ($path: String, $locale: String!) {
  169. pages {
  170. tree(path: $path, mode: ALL, locale: $locale, includeAncestors: true) {
  171. id
  172. path
  173. title
  174. isFolder
  175. pageId
  176. parent
  177. locale
  178. }
  179. }
  180. }
  181. `,
  182. fetchPolicy: 'cache-first',
  183. variables: {
  184. path: this.path,
  185. locale: this.locale
  186. }
  187. })
  188. const items = _.get(resp, 'data.pages.tree', [])
  189. const curPage = _.find(items, ['pageId', this.$store.get('page/id')])
  190. if (!curPage) {
  191. console.warn('Could not find current page in page tree listing!')
  192. return
  193. }
  194. let curParentId = curPage.parent
  195. let invertedAncestors = []
  196. while (curParentId) {
  197. const curParent = _.find(items, ['id', curParentId])
  198. if (!curParent) {
  199. break
  200. }
  201. invertedAncestors.push(curParent)
  202. curParentId = curParent.parent
  203. }
  204. this.parents = [this.currentParent, ...invertedAncestors.reverse()]
  205. this.currentParent = _.last(this.parents)
  206. this.loadedCache = [curPage.parent]
  207. this.currentItems = _.filter(items, ['parent', curPage.parent])
  208. this.$store.commit(`loadingStop`, 'browse-load')
  209. },
  210. goHome () {
  211. window.location.assign(siteLangs.length > 0 ? `/${this.locale}/home` : '/')
  212. }
  213. },
  214. mounted () {
  215. this.currentParent.title = `/ ${this.$t('common:sidebar.root')}`
  216. if (this.navMode === 'TREE') {
  217. this.currentMode = 'browse'
  218. } else if (this.navMode === 'STATIC') {
  219. this.currentMode = 'custom'
  220. } else {
  221. this.currentMode = window.localStorage.getItem('navPref') || 'custom'
  222. }
  223. if (this.currentMode === 'browse') {
  224. this.loadFromCurrentPath()
  225. }
  226. }
  227. }
  228. </script>