admin-navigation.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <template lang='pug'>
  2. v-container(fluid, grid-list-lg)
  3. v-layout(row wrap)
  4. v-flex(xs12)
  5. .admin-header
  6. v-icon(size='80', color='grey lighten-2') near_me
  7. .admin-header-title
  8. .headline.primary--text {{$t('navigation.title')}}
  9. .subheading.grey--text {{$t('navigation.subtitle')}}
  10. v-spacer
  11. v-btn(color='success', depressed, @click='save', large)
  12. v-icon(left) check
  13. span {{$t('common:actions.apply')}}
  14. v-container.pa-0.mt-3(fluid, grid-list-lg)
  15. v-layout(row)
  16. v-flex(style='flex: 0 0 350px;')
  17. v-card
  18. v-list.py-2(dense, dark, :class='navTree.length < 1 ? "grey lighten-4" : "primary"')
  19. v-list-tile(v-if='navTree.length < 1')
  20. v-list-tile-avatar: v-icon(color='grey') explore_off
  21. v-list-tile-content
  22. .caption.grey--text {{$t('navigation.emptyList')}}
  23. draggable(v-model='navTree')
  24. template(v-for='navItem in navTree')
  25. v-list-tile(
  26. v-if='navItem.kind === "link"'
  27. :key='navItem.id'
  28. :class='(navItem === current) ? "blue" : ""'
  29. @click='selectItem(navItem)'
  30. )
  31. v-list-tile-avatar: v-icon {{navItem.icon}}
  32. v-list-tile-title {{navItem.label}}
  33. .py-2.clickable(
  34. v-else-if='navItem.kind === "divider"'
  35. :key='navItem.id'
  36. :class='(navItem === current) ? "blue" : ""'
  37. @click='selectItem(navItem)'
  38. )
  39. v-divider
  40. v-subheader.pl-4.clickable(
  41. v-else-if='navItem.kind === "header"'
  42. :key='navItem.id'
  43. :class='(navItem === current) ? "blue" : ""'
  44. @click='selectItem(navItem)'
  45. ) {{navItem.label}}
  46. v-card-chin
  47. v-menu(offset-y, bottom, min-width='200px', style='flex: 1 1;')
  48. v-btn(slot='activator', color='primary', depressed, block)
  49. v-icon(left) add
  50. span {{$t('common:actions.add')}}
  51. v-list
  52. v-list-tile(@click='addItem("link")')
  53. v-list-tile-avatar: v-icon link
  54. v-list-tile-title {{$t('navigation.link')}}
  55. v-list-tile(@click='addItem("header")')
  56. v-list-tile-avatar: v-icon title
  57. v-list-tile-title {{$t('navigation.header')}}
  58. v-list-tile(@click='addItem("divider")')
  59. v-list-tile-avatar: v-icon power_input
  60. v-list-tile-title {{$t('navigation.divider')}}
  61. v-flex
  62. v-card(v-if='current.kind === "link"')
  63. v-toolbar(dense, color='blue', flat, dark)
  64. .subheading {{$t('navigation.edit', { kind: $t('navigation.link') })}}
  65. v-card-text
  66. v-text-field(
  67. outline
  68. background-color='grey lighten-2'
  69. :label='$t("navigation.label")'
  70. prepend-icon='title'
  71. v-model='current.label'
  72. )
  73. v-text-field(
  74. outline
  75. background-color='grey lighten-2'
  76. :label='$t("navigation.icon")'
  77. prepend-icon='casino'
  78. v-model='current.icon'
  79. )
  80. v-select(
  81. outline
  82. background-color='grey lighten-2'
  83. :label='$t("navigation.targetType")'
  84. prepend-icon='near_me'
  85. :items='navTypes'
  86. v-model='current.targetType'
  87. )
  88. v-text-field(
  89. v-if='current.targetType === "external"'
  90. outline
  91. background-color='grey lighten-2'
  92. :label='$t("navigation.target")'
  93. prepend-icon='near_me'
  94. v-model='current.target'
  95. )
  96. v-card-chin
  97. v-spacer
  98. v-btn(color='red', outline, @click='deleteItem(current)')
  99. v-icon(left) delete
  100. span {{$t('navigation.delete', { kind: $t('navigation.link') })}}
  101. v-card(v-else-if='current.kind === "header"')
  102. v-toolbar(dense, color='blue', flat, dark)
  103. .subheading {{$t('navigation.edit', { kind: $t('navigation.header') })}}
  104. v-card-text
  105. v-text-field(
  106. outline
  107. background-color='grey lighten-2'
  108. :label='$t("navigation.label")'
  109. prepend-icon='title'
  110. v-model='current.label'
  111. )
  112. v-card-chin
  113. v-spacer
  114. v-btn(color='red', outline, @click='deleteItem(current)')
  115. v-icon(left) delete
  116. span {{$t('navigation.delete', { kind: $t('navigation.header') })}}
  117. div(v-else-if='current.kind === "divider"')
  118. v-btn.mt-0(color='red', outline, @click='deleteItem(current)')
  119. v-icon(left) delete
  120. span {{$t('navigation.delete', { kind: $t('navigation.divider') })}}
  121. v-card(v-else)
  122. v-card-text.grey--text(v-if='navTree.length > 0') {{$t('navigation.noSelectionText')}}
  123. v-card-text.grey--text(v-else) {{$t('navigation.noItemsText')}}
  124. </template>
  125. <script>
  126. import _ from 'lodash'
  127. import uuid from 'uuid/v4'
  128. import treeSaveMutation from 'gql/admin/navigation/navigation-mutation-save-tree.gql'
  129. import treeQuery from 'gql/admin/navigation/navigation-query-tree.gql'
  130. import draggable from 'vuedraggable'
  131. export default {
  132. components: {
  133. draggable
  134. },
  135. data() {
  136. return {
  137. navTree: [],
  138. current: {}
  139. }
  140. },
  141. computed: {
  142. navTypes() {
  143. return [
  144. { text: this.$t('navigation.navType.external'), value: 'external' },
  145. { text: this.$t('navigation.navType.home'), value: 'home' },
  146. { text: this.$t('navigation.navType.page'), value: 'page' },
  147. { text: this.$t('navigation.navType.searchQuery'), value: 'search' }
  148. ]
  149. }
  150. },
  151. methods: {
  152. addItem(kind) {
  153. let newItem = {
  154. id: uuid(),
  155. kind
  156. }
  157. switch (kind) {
  158. case 'link':
  159. newItem = {
  160. ...newItem,
  161. label: this.$t('navigation.untitled', { kind: this.$t(`navigation.link`) }),
  162. icon: 'chevron_right',
  163. targetType: 'home',
  164. target: '/'
  165. }
  166. break
  167. case 'header':
  168. newItem.label = this.$t('navigation.untitled', { kind: this.$t(`navigation.header`) })
  169. break
  170. }
  171. this.navTree.push(newItem)
  172. this.current = newItem
  173. },
  174. deleteItem(item) {
  175. this.navTree = _.pull(this.navTree, item)
  176. this.current = {}
  177. },
  178. selectItem(item) {
  179. this.current = item
  180. },
  181. async save() {
  182. this.$store.commit(`loadingStart`, 'admin-navigation-save')
  183. try {
  184. await this.$apollo.mutate({
  185. mutation: treeSaveMutation,
  186. variables: {
  187. tree: this.navTree
  188. }
  189. })
  190. } catch (err) {
  191. this.$store.commit('showNotification', {
  192. message: this.$t('navigation.saveSuccess'),
  193. style: 'success',
  194. icon: 'check'
  195. })
  196. }
  197. this.$store.commit(`loadingStop`, 'admin-navigation-save')
  198. }
  199. },
  200. apollo: {
  201. navTree: {
  202. query: treeQuery,
  203. fetchPolicy: 'network-only',
  204. update: (data) => _.cloneDeep(data.navigation.tree),
  205. watchLoading (isLoading) {
  206. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-navigation-tree')
  207. }
  208. }
  209. }
  210. }
  211. </script>
  212. <style lang='scss' scoped>
  213. .clickable {
  214. cursor: pointer;
  215. &:hover {
  216. background-color: rgba(mc('blue', '500'), .25);
  217. }
  218. }
  219. </style>