NodesHistory.vue 5.0 KB

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