nav-sidebar.vue 7.4 KB
Newer Older
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 5 6 7 8 9 10
      v-btn(
        depressed
        :color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
        style='min-width:0;'
        @click='goHome'
        :aria-label='$t(`common:header.home`)'
        )
NGPixel's avatar
NGPixel committed
11
        v-icon(size='20') mdi-home
12 13 14 15 16 17 18
      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`)'
        )
NGPixel's avatar
NGPixel committed
19
        v-icon(left) mdi-file-tree
20
        .body-2.text-none {{$t('common:sidebar.browse')}}
21 22 23 24 25 26 27
      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`)'
        )
NGPixel's avatar
NGPixel committed
28
        v-icon(left) mdi-navigation
29
        .body-2.text-none {{$t('common:sidebar.mainMenu')}}
NGPixel's avatar
NGPixel committed
30 31 32
    v-divider
    //-> Custom Navigation
    v-list.py-2(v-if='currentMode === `custom`', dense, :class='color', :dark='dark')
33 34
      template(v-for='item of items')
        v-list-item(
35 36 37 38
          v-if='item.k === `link`'
          :href='item.t'
          :target='item.y === `externalblank` ? `_blank` : `_self`'
          :rel='item.y === `externalblank` ? `noopener` : ``'
39
          )
NGPixel's avatar
NGPixel committed
40
          v-list-item-avatar(size='24', tile)
41 42
            v-icon(v-if='item.c.match(/fa[a-z] fa-/)', size='19') {{ item.c }}
            v-icon(v-else) {{ item.c }}
43 44 45
          v-list-item-title {{ item.l }}
        v-divider.my-2(v-else-if='item.k === `divider`')
        v-subheader.pl-4(v-else-if='item.k === `header`') {{ item.l }}
NGPixel's avatar
NGPixel committed
46 47 48 49 50 51 52 53
    //-> Browse
    v-list.py-2(v-else-if='currentMode === `browse`', dense, :class='color', :dark='dark')
      template(v-if='currentParent.id > 0')
        v-list-item(v-for='(item, idx) of parents', :key='`parent-` + item.id', @click='fetchBrowseItems(item)', style='min-height: 30px;')
          v-list-item-avatar(size='18', :style='`padding-left: ` + (idx * 8) + `px; width: auto; margin: 0 5px 0 0;`')
            v-icon(small) mdi-folder-open
          v-list-item-title {{ item.title }}
        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 56 57
          v-list-item-avatar(size='24')
            v-icon mdi-text-box
          v-list-item-title {{ currentParent.title }}
58
        v-subheader.pl-4 {{$t('common:sidebar.currentDirectory')}}
NGPixel's avatar
NGPixel committed
59 60 61 62 63
      template(v-for='item of currentItems')
        v-list-item(v-if='item.isFolder', :key='`childfolder-` + item.id', @click='fetchBrowseItems(item)')
          v-list-item-avatar(size='24')
            v-icon mdi-folder
          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')
NGPixel's avatar
NGPixel committed
65
          v-list-item-avatar(size='24')
66
            v-icon mdi-text-box
NGPixel's avatar
NGPixel committed
67
          v-list-item-title {{ item.title }}
68 69 70
</template>

<script>
NGPixel's avatar
NGPixel committed
71 72 73 74
import _ from 'lodash'
import gql from 'graphql-tag'
import { get } from 'vuex-pathify'

75 76
/* global siteLangs */

77 78 79 80 81 82 83 84 85
export default {
  props: {
    color: {
      type: String,
      default: 'primary'
    },
    dark: {
      type: Boolean,
      default: true
Nick's avatar
Nick committed
86 87 88 89
    },
    items: {
      type: Array,
      default: () => []
NGPixel's avatar
NGPixel committed
90
    },
NGPixel's avatar
NGPixel committed
91 92 93
    navMode: {
      type: String,
      default: 'MIXED'
94 95 96
    }
  },
  data() {
NGPixel's avatar
NGPixel committed
97
    return {
98
      currentMode: 'custom',
NGPixel's avatar
NGPixel committed
99 100 101 102 103
      currentItems: [],
      currentParent: {
        id: 0,
        title: '/ (root)'
      },
104 105
      parents: [],
      loadedCache: []
NGPixel's avatar
NGPixel committed
106 107 108 109 110 111 112 113 114
    }
  },
  computed: {
    path: get('page/path'),
    locale: get('page/locale')
  },
  methods: {
    switchMode (mode) {
      this.currentMode = mode
115
      window.localStorage.setItem('navPref', mode)
116 117
      if (mode === `browse` && this.loadedCache.length < 1) {
        this.loadFromCurrentPath()
NGPixel's avatar
NGPixel committed
118 119 120 121 122 123
      }
    },
    async fetchBrowseItems (item) {
      this.$store.commit(`loadingStart`, 'browse-load')
      if (!item) {
        item = this.currentParent
124 125 126 127 128 129 130 131
      }

      if (this.loadedCache.indexOf(item.id) < 0) {
        this.currentItems = []
      }

      if (item.id === 0) {
        this.parents = []
NGPixel's avatar
NGPixel committed
132
      } else {
133 134 135 136 137
        const flushRightIndex = _.findIndex(this.parents, ['id', item.id])
        if (flushRightIndex >= 0) {
          this.parents = _.take(this.parents, flushRightIndex)
        }
        if (this.parents.length < 1) {
NGPixel's avatar
NGPixel committed
138 139
          this.parents.push(this.currentParent)
        }
140
        this.parents.push(item)
NGPixel's avatar
NGPixel committed
141
      }
142 143 144

      this.currentParent = item

NGPixel's avatar
NGPixel committed
145 146
      const resp = await this.$apollo.query({
        query: gql`
147
          query ($parent: Int, $locale: String!) {
NGPixel's avatar
NGPixel committed
148
            pages {
149
              tree(parent: $parent, mode: ALL, locale: $locale) {
NGPixel's avatar
NGPixel committed
150 151 152 153 154 155
                id
                path
                title
                isFolder
                pageId
                parent
156
                locale
NGPixel's avatar
NGPixel committed
157 158 159 160 161 162 163 164 165 166
              }
            }
          }
        `,
        fetchPolicy: 'cache-first',
        variables: {
          parent: item.id,
          locale: this.locale
        }
      })
167
      this.loadedCache = _.union(this.loadedCache, [item.id])
NGPixel's avatar
NGPixel committed
168
      this.currentItems = _.get(resp, 'data.pages.tree', [])
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
      this.$store.commit(`loadingStop`, 'browse-load')
    },
    async loadFromCurrentPath() {
      this.$store.commit(`loadingStart`, 'browse-load')
      const resp = await this.$apollo.query({
        query: gql`
          query ($path: String, $locale: String!) {
            pages {
              tree(path: $path, mode: ALL, locale: $locale, includeAncestors: true) {
                id
                path
                title
                isFolder
                pageId
                parent
184
                locale
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
              }
            }
          }
        `,
        fetchPolicy: 'cache-first',
        variables: {
          path: this.path,
          locale: this.locale
        }
      })
      const items = _.get(resp, 'data.pages.tree', [])
      const curPage = _.find(items, ['pageId', this.$store.get('page/id')])
      if (!curPage) {
        console.warn('Could not find current page in page tree listing!')
        return
      }

      let curParentId = curPage.parent
      let invertedAncestors = []
      while (curParentId) {
        const curParent = _.find(items, ['id', curParentId])
        if (!curParent) {
          break
        }
        invertedAncestors.push(curParent)
        curParentId = curParent.parent
      }

      this.parents = [this.currentParent, ...invertedAncestors.reverse()]
      this.currentParent = _.last(this.parents)

      this.loadedCache = [curPage.parent]
      this.currentItems = _.filter(items, ['parent', curPage.parent])
NGPixel's avatar
NGPixel committed
218
      this.$store.commit(`loadingStop`, 'browse-load')
219 220 221
    },
    goHome () {
      window.location.assign(siteLangs.length > 0 ? `/${this.locale}/home` : '/')
NGPixel's avatar
NGPixel committed
222 223 224
    }
  },
  mounted () {
225
    this.currentParent.title = `/ ${this.$t('common:sidebar.root')}`
226 227
    if (this.navMode === 'TREE') {
      this.currentMode = 'browse'
228 229
    } else if (this.navMode === 'STATIC') {
      this.currentMode = 'custom'
230
    } else {
231 232 233 234
      this.currentMode = window.localStorage.getItem('navPref') || 'custom'
    }
    if (this.currentMode === 'browse') {
      this.loadFromCurrentPath()
NGPixel's avatar
NGPixel committed
235
    }
236 237 238
  }
}
</script>