2
0

nav-sidebar.vue 7.1 KB

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