PostScrubber.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <div class='post_scrubber'>
  3. <div class='post_scrubber__label post_scrubber__label--first' @click='$emit("input", 0)'>First post</div>
  4. <div class='post_scrubber__line' ref='line' @click='lineClick'></div>
  5. <div
  6. class='post_scrubber__dragger'
  7. :style='{
  8. "top": draggerYCoord + "px"
  9. }'
  10. @mousedown.prevent.stop='setDragging(true)'
  11. @mouseup.prevent.stop='setDragging(false)'
  12. ></div>
  13. <div
  14. class='post_scrubber__dragger_info'
  15. :style='{
  16. "top": draggerYCoord + "px"
  17. }'
  18. >
  19. Post <strong>{{currentPost}}</strong> out of {{posts}}
  20. </div>
  21. <div class='post_scrubber__label post_scrubber__label--last' @click='$emit("input", posts-1)'>Latest post</div>
  22. </div>
  23. </template>
  24. <script>
  25. export default {
  26. name: 'PostScrubber',
  27. props: ['posts', 'value'],
  28. data () {
  29. return {
  30. clientY: 0,
  31. lineTop: 0,
  32. lineHeight: 0,
  33. dragging: false
  34. }
  35. },
  36. computed: {
  37. draggerYCoord () {
  38. if(!this.clientY || !this.lineTop) return 0
  39. let top = this.clientY - this.lineTop
  40. if(top < 0) {
  41. return 0
  42. } else if(top > this.lineHeight) {
  43. return this.lineHeight
  44. } else {
  45. return top
  46. }
  47. },
  48. currentPost () {
  49. let postDivision = this.lineHeight / this.posts
  50. let postNumber = Math.floor(this.draggerYCoord/ postDivision)
  51. let retPostNumber
  52. if(postNumber === this.posts) {
  53. retPostNumber = postNumber
  54. } else {
  55. retPostNumber = postNumber + 1
  56. }
  57. return retPostNumber
  58. }
  59. },
  60. methods: {
  61. setDragging (val) {
  62. this.dragging = val
  63. if(!val) {
  64. this.$emit('input', this.currentPost-1)
  65. }
  66. },
  67. lineClick (e) {
  68. this.clientY = e.clientY
  69. },
  70. setCurrentPost () {
  71. let postNumber = +this.value
  72. let postDivision = this.lineHeight / this.posts
  73. if(postNumber+1 === this.posts) {
  74. this.clientY = this.lineTop + this.lineHeight
  75. } else {
  76. this.clientY = this.lineTop + postDivision * postNumber
  77. }
  78. }
  79. },
  80. watch: {
  81. value: 'setCurrentPost'
  82. },
  83. mounted () {
  84. let lineRect = this.$refs.line.getBoundingClientRect()
  85. this.lineTop = lineRect.top
  86. this.lineHeight = lineRect.height
  87. this.setCurrentPost()
  88. window.addEventListener('mousemove', e => {
  89. if(this.dragging) {
  90. this.clientY = e.clientY
  91. }
  92. })
  93. window.addEventListener('mouseup', e => {
  94. if(this.dragging) {
  95. this.$emit('input', this.currentPost-1)
  96. }
  97. this.dragging = false
  98. })
  99. }
  100. }
  101. </script>
  102. <style lang='scss' scoped>
  103. @import '../assets/scss/variables.scss';
  104. .post_scrubber {
  105. height: 10rem;
  106. position: fixed;
  107. right: calc(10% + 7.5rem);
  108. margin-top: 6.5rem;
  109. @at-root #{&}__line {
  110. height: 100%;
  111. background-color: $color__gray--darker;
  112. border-radius: 1rem;
  113. width: 0.125rem;
  114. }
  115. @at-root #{&}__dragger {
  116. background-color: $color__blue--primary;
  117. width: 0.5rem;
  118. border-radius: 1rem;
  119. height: 1.5rem;
  120. position: absolute;
  121. top: 0;
  122. left: calc( (0.5rem - 0.125rem) / -2);
  123. margin-top: calc(-1.5rem / 2 );
  124. cursor: pointer;
  125. transition: background-color 0.2s;
  126. &:hover {
  127. background-color: $color__blue--darker;
  128. }
  129. &:active {
  130. background-color: $color__blue--darkest;
  131. }
  132. }
  133. @at-root #{&}__label {
  134. position: absolute;
  135. color: $color__blue--primary;
  136. cursor: pointer;
  137. left: -0.25rem;
  138. width: 10rem;
  139. @at-root #{&}--first {
  140. top: -2.25rem;
  141. }
  142. @at-root #{&}--last {
  143. bottom: -2.25rem;
  144. }
  145. }
  146. @at-root #{&}__dragger_info {
  147. position: absolute;
  148. width: 10rem;
  149. margin-top: calc(-1.5rem / 2 - 0.125rem);
  150. pointer-events: none;
  151. background-color: #fff;
  152. left: 1rem;
  153. font-size: 0.9rem;
  154. border-radius: 0.125rem;
  155. padding: 0.25rem;
  156. @extend .shadow_border;
  157. }
  158. }
  159. </style>