Search.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <template>
  2. <div class='route_container'>
  3. <h1>Search results for '{{$route.params.q}}'</h1>
  4. <transition name='fade' mode='out-in'>
  5. <div class='search__results' key='results' v-if='posts && posts.length'>
  6. <scroll-load
  7. :loading='loading'
  8. @loadNext='loadNextPage'
  9. >
  10. <thread-post
  11. class='search__post'
  12. v-for='post in posts'
  13. :key='post.id'
  14. :post='post'
  15. :show-thread='true'
  16. :click-for-post='true'
  17. ></thread-post>
  18. <thread-post-placeholder
  19. class='search__post'
  20. v-if='loading'
  21. v-for='n in next'
  22. :key='n'
  23. ></thread-post-placeholder>
  24. </scroll-load>
  25. </div>
  26. <div
  27. class='overlay_message search__overlay_message'
  28. v-else-if='posts && !posts.length'
  29. key='no results'
  30. >
  31. <span class='fa fa-exclamation-circle'></span>
  32. No results found
  33. </div>
  34. <div
  35. class='search__results'
  36. key='loading'
  37. v-else
  38. >
  39. <thread-post-placeholder class='search__post'
  40. ></thread-post-placeholder>
  41. </div>
  42. </transition>
  43. </div>
  44. </template>
  45. <script>
  46. import LoadingIcon from '../LoadingIcon'
  47. import ScrollLoad from '../ScrollLoad'
  48. import ThreadPost from '../ThreadPost'
  49. import ThreadPostPlaceholder from '../ThreadPostPlaceholder'
  50. import AjaxErrorHandler from '../../assets/js/errorHandler'
  51. import logger from '../../assets/js/logger'
  52. export default {
  53. name: 'Search',
  54. components: {
  55. LoadingIcon,
  56. ThreadPost,
  57. ScrollLoad,
  58. ThreadPostPlaceholder
  59. },
  60. data () {
  61. return {
  62. posts: null,
  63. next: 0,
  64. offset: 0,
  65. loading: false,
  66. postsLoaded: false
  67. }
  68. },
  69. methods: {
  70. //Delay of 300ms so that you won't see
  71. //a flash of placeholders when it's not necessary
  72. setDelayedPostsNull () {
  73. this.postsLoaded = false
  74. setTimeout(() => {
  75. if(!this.postsLoaded) {
  76. this.posts = null
  77. }
  78. }, 300)
  79. },
  80. getResults () {
  81. this.$store.dispatch('setTitle', 'Search | ' + this.$route.params.q)
  82. this.setDelayedPostsNull()
  83. this.axios
  84. .get('/api/v1/search?q=' + this.$route.params.q)
  85. .then(res => {
  86. this.posts = res.data.posts
  87. this.next = res.data.next
  88. this.offset = res.data.offset
  89. this.postsLoaded = true
  90. })
  91. .catch(AjaxErrorHandler(this.$store))
  92. },
  93. loadNextPage () {
  94. if(this.next === 0) return
  95. this.loading = true
  96. this.axios
  97. .get(
  98. `/api/v1/search?q=${this.$route.params.q}&offset=${this.offset}`
  99. )
  100. .then(res => {
  101. this.posts.push(...res.data.posts)
  102. this.next = res.data.next
  103. this.offset = res.data.offset
  104. this.loading = false
  105. this.postsLoaded = true
  106. })
  107. .catch(e => {
  108. this.loading = false
  109. this.postsLoaded = true
  110. AjaxErrorHandler(this.$store)(e)
  111. })
  112. }
  113. },
  114. watch: {
  115. '$route.params': 'getResults'
  116. },
  117. mounted () {
  118. this.$store.dispatch('setTitle', 'Search | ' + this.$route.params.q)
  119. this.getResults()
  120. logger('search')
  121. }
  122. }
  123. </script>
  124. <style lang='scss' scoped>
  125. @import '../../assets/scss/variables.scss';
  126. .search {
  127. @at-root #{&}__post {
  128. background-color: #fff;
  129. padding-left: 0.75rem;
  130. margin-bottom: 1rem;
  131. border: none;
  132. transition: box-shadow 0.2s;
  133. @extend .shadow_border;
  134. &:hover {
  135. @extend .shadow_border--hover;
  136. }
  137. }
  138. @at-root #{&}__overlay_message {
  139. margin-top: 5rem;
  140. @at-root #{&}--loading span {
  141. margin-bottom: 1rem;
  142. }
  143. }
  144. }
  145. </style>