NodesHistory.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <template>
  2. <footer class="nodes-history no-events-container" v-if="history.length">
  3. <b-dropdown
  4. variant="outline-dark"
  5. dropup no-flip no-caret
  6. boundary="main"
  7. class="no-events-container"
  8. @shown="scrollToEnd"
  9. @hide="shown = false"
  10. >
  11. <template #button-content>
  12. <span class="collapse-icon" :class="{ collapsed: shown }">></span>
  13. {{ $t('history') }}
  14. </template>
  15. <b-dropdown-text class="dropdown-item-arrow left">
  16. <b-button variant="link" @click="onArrowClick('left')" :disabled="leftDisabled">&lt;</b-button>
  17. </b-dropdown-text>
  18. <b-dropdown-item-button
  19. v-for="node in history" :key="'history-' + node.id"
  20. @click="onOpenNode(node)"
  21. >
  22. <div
  23. class="font-weight-bold"
  24. :class="'text-' + (node.variant === 'depart' ? 'black' : node.variant)"
  25. >
  26. {{ $t('variants.' + node.variant) }}
  27. </div>
  28. <node-view-title
  29. :node="node.type === 'ref' ? node : node.parents[0]"
  30. edition block
  31. tag="div"
  32. />
  33. </b-dropdown-item-button>
  34. <b-dropdown-text style="width: 70px;" aria-hidden="true" class="ml-auto" />
  35. <b-dropdown-text class="dropdown-item-arrow right">
  36. <b-button variant="link" @click="onArrowClick('right')" :disabled="rightDisabled">&gt;</b-button>
  37. </b-dropdown-text>
  38. </b-dropdown>
  39. </footer>
  40. </template>
  41. <script>
  42. import { mapGetters } from 'vuex'
  43. import { getRelation } from '@/store/utils'
  44. import { NodeViewTitle } from '@/components/nodes'
  45. export default {
  46. name: 'NodesHistory',
  47. components: {
  48. NodeViewTitle
  49. },
  50. data () {
  51. return {
  52. leftDisabled: false,
  53. rightDisabled: false,
  54. shown: false
  55. }
  56. },
  57. computed: {
  58. ...mapGetters(['history'])
  59. },
  60. methods: {
  61. onOpenNode (node) {
  62. this.$store.dispatch('OPEN_NODE', getRelation(node))
  63. },
  64. updateBtnDir () {
  65. const container = this.$el.querySelector('.dropdown-menu')
  66. this.leftDisabled = container.scrollLeft < 5
  67. this.rightDisabled = container.scrollLeft + container.offsetWidth + 5 > container.scrollWidth
  68. },
  69. scrollToEnd () {
  70. const container = this.$el.querySelector('.dropdown-menu')
  71. container.scrollTo({ left: container.scrollWidth })
  72. this.updateBtnDir()
  73. this.shown = true
  74. },
  75. onArrowClick (dir) {
  76. const container = this.$el.querySelector('.dropdown-menu')
  77. const width = container.offsetWidth
  78. const items = Array.from(container.querySelectorAll('.dropdown-item'))
  79. let left = 0
  80. if (dir === 'right') {
  81. const nextItem = items.find(item => {
  82. return item.offsetLeft + 300 > container.scrollLeft + width
  83. })
  84. if (nextItem) {
  85. left = nextItem.offsetLeft + 370 - width
  86. }
  87. } else {
  88. const nextItem = items.reverse().find(item => {
  89. return item.offsetLeft < container.scrollLeft
  90. })
  91. if (nextItem) {
  92. left = nextItem.offsetLeft - 70
  93. }
  94. }
  95. container.scrollTo({ left, behavior: 'smooth' })
  96. setTimeout(this.updateBtnDir, 500)
  97. }
  98. }
  99. }
  100. </script>
  101. <style lang="scss">
  102. .nodes-history {
  103. margin: 0;
  104. .dropdown {
  105. width: 100%;
  106. @include media-breakpoint-up($size-bp) {
  107. height: 100%;
  108. display: block;
  109. }
  110. }
  111. .dropdown-toggle {
  112. background-color: $white;
  113. border-radius: 0 !important;
  114. padding: .5rem;
  115. font-weight: $font-weight-bold;
  116. text-align: left;
  117. border-bottom: 0;
  118. @include media-breakpoint-up($size-bp) {
  119. position: absolute !important;
  120. bottom: 0;
  121. right: 2rem;
  122. z-index: 1035;
  123. }
  124. }
  125. .dropdown-menu {
  126. margin-left: 0;
  127. margin-bottom: 0 !important;
  128. max-width: 100vw;
  129. @include media-breakpoint-down($size-bp-down) {
  130. width: 100vw;
  131. max-height: calc(100vh - 38px);
  132. overflow-y: auto;
  133. border-bottom: 0;
  134. border-left: 0;
  135. border-right: 0;
  136. }
  137. @include media-breakpoint-up($size-bp) {
  138. width: 100vw;
  139. transform: none !important;
  140. top: 70% !important;
  141. border-left: 0;
  142. border-right: 0;
  143. overflow-x: auto;
  144. -webkit-overflow-scrolling: touch;
  145. overflow-y: hidden;
  146. scrollbar-width: none;
  147. &.show {
  148. display: flex;
  149. }
  150. }
  151. .dropdown-item {
  152. padding: $node-view-spacer-sm-x !important;
  153. color: $black;
  154. white-space: normal;
  155. &:hover {
  156. background-color: $white;
  157. }
  158. @include media-breakpoint-up($size-bp) {
  159. width: 300px;
  160. }
  161. }
  162. .dropdown-item-arrow {
  163. display: none;
  164. position: sticky;
  165. background-color: $white;
  166. &.left {
  167. left: 0;
  168. }
  169. &.right {
  170. right: 0;
  171. }
  172. .b-dropdown-text {
  173. height: 100%;
  174. padding: 0;
  175. .btn {
  176. padding: 0;
  177. height: 100%;
  178. text-decoration: none;
  179. font-size: 3.5rem;
  180. width: 70px;
  181. }
  182. }
  183. @include media-breakpoint-up($size-bp) {
  184. display: block;
  185. }
  186. }
  187. .edition {
  188. font-size: .7rem;
  189. margin-top: .15rem;
  190. }
  191. }
  192. @include media-breakpoint-up($size-bp) {
  193. position: absolute;
  194. top: 0;
  195. left: 0;
  196. width: 100%;
  197. height: 100%;
  198. }
  199. .collapse-icon {
  200. margin-right: .25rem;
  201. font-weight: 700;
  202. }
  203. }
  204. </style>