ThreadNew.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <template>
  2. <div class='route_container thread_new'>
  3. <div class='h1'>Post new thread</div>
  4. <div class='thread_meta_info'>
  5. <div class='thread_meta_info__text'>Enter the thread title and the category to post it in</div>
  6. <select-button v-model='selectedCategory' :options='categories'></select-button>
  7. <fancy-input
  8. placeholder='Thread title'
  9. v-model='name'
  10. :error='errors.name'
  11. style='margin-left: 0.5rem; display: inline-block;'
  12. large='true'
  13. width='15rem'
  14. ></fancy-input>
  15. </div>
  16. <div class='editor' :class='{"editor--focus": focusInput}'>
  17. <div class='editor__input'>
  18. <div class='editor__format_bar'>
  19. editor
  20. </div>
  21. <input-editor-core
  22. v-model='editor'
  23. :error='errors.content'
  24. @mentions='setMentions'
  25. @focus='setFocusInput(true)'
  26. @blur='setFocusInput(false)'
  27. ></input-editor-core>
  28. </div>
  29. <div class='editor__preview'>
  30. <div class='editor__format_bar editor__format_bar--preview'>
  31. preview
  32. </div>
  33. <input-editor-preview :value='editor' :mentions='mentions'></input-editor-preview>
  34. </div>
  35. </div>
  36. <loading-button class='button--green submit' :loading='loading' @click='postThread'>Post thread</loading-button>
  37. </div>
  38. </template>
  39. <script>
  40. import InputEditorCore from '../InputEditorCore'
  41. import InputEditorPreview from '../InputEditorPreview'
  42. import FancyInput from '../FancyInput'
  43. import SelectButton from '../SelectButton'
  44. import LoadingButton from '../LoadingButton'
  45. import AjaxErrorHandler from '../../assets/js/errorHandler'
  46. export default {
  47. name: 'ThreadNew',
  48. components: {
  49. InputEditorCore,
  50. InputEditorPreview,
  51. SelectButton,
  52. FancyInput,
  53. LoadingButton
  54. },
  55. data () {
  56. return {
  57. selectedCategory: this.$store.state.category.selectedCategory,
  58. editor: '',
  59. mentions: [],
  60. name: '',
  61. loading: false,
  62. focusInput: false,
  63. errors: {
  64. content: '',
  65. name: ''
  66. }
  67. }
  68. },
  69. computed: {
  70. categories () {
  71. return this.$store.getters.categoriesWithoutAll
  72. }
  73. },
  74. methods: {
  75. postThread () {
  76. if(!this.editor.trim().length) {
  77. this.errors.content = 'Cannot be blank'
  78. return;
  79. }
  80. this.errors.content = ''
  81. this.errors.name = ''
  82. this.loading = true
  83. this.axios.post('/api/v1/thread', {
  84. name: this.name,
  85. category: this.selectedCategory
  86. }).then(res => {
  87. return this.axios.post('/api/v1/post', {
  88. threadId: res.data.id,
  89. content: this.editor,
  90. mentions: this.mentions
  91. })
  92. }).then(res => {
  93. this.loading = false
  94. this.$router.push(`/thread/${res.data.Thread.slug}/${res.data.Thread.id}`)
  95. }).catch(e => {
  96. this.loading = false
  97. AjaxErrorHandler(this.$store)(e, (error, errors) => {
  98. let path = error.path
  99. if(this.errors[path] !== undefined) {
  100. this.errors[path] = error.message
  101. } else {
  102. errors.push(error.message)
  103. }
  104. })
  105. })
  106. },
  107. setFocusInput (val) {
  108. this.focusInput = val
  109. },
  110. setMentions (mentions) {
  111. this.mentions = mentions
  112. }
  113. },
  114. watch: {
  115. '$store.state.username' (username) {
  116. if(!username) {
  117. this.$router.push('/')
  118. }
  119. }
  120. },
  121. mounted () {
  122. this.$store.dispatch('setTitle', 'new thread')
  123. },
  124. beforeRouteEnter (to, from, next) {
  125. next(vm => {
  126. if(!vm.$store.state.username) {
  127. vm.$store.commit('setAccountModalState', true);
  128. next('/')
  129. }
  130. })
  131. }
  132. }
  133. </script>
  134. <style lang='scss'>
  135. @import '../../assets/scss/variables.scss';
  136. .thread_new {
  137. margin-top: 1rem;
  138. }
  139. .thread_meta_info {
  140. background-color: #fff;
  141. @extend .shadow_border;
  142. border-radius: 0.25rem;
  143. padding: 1rem;
  144. margin: 1rem 0;
  145. @at-root #{&}__text {
  146. margin-bottom: 0.5rem;
  147. }
  148. }
  149. .submit {
  150. margin-top: 1rem;
  151. }
  152. .editor {
  153. display: flex;
  154. background-color: #fff;
  155. border-radius: 0.25rem;
  156. border: 0.125rem solid $color__gray--darker;
  157. transition: color 0.2s;
  158. @at-root #{&}--focus {
  159. border-color: $color__gray--darkest;
  160. }
  161. @at-root #{&}__format_bar {
  162. height: 2.5rem;
  163. background-color: $color__gray--primary;
  164. display: flex;
  165. padding-right: 1rem;
  166. padding-bottom: 0.25rem;
  167. justify-content: flex-end;
  168. align-items: center;
  169. font-variant: small-caps;
  170. }
  171. @at-root #{&}__input {
  172. width: 50%;
  173. position: relative;
  174. .input_editor_core__format_bar {
  175. left: 0rem;
  176. }
  177. .input_editor_core textarea {
  178. height: 14rem;
  179. }
  180. }
  181. @at-root #{&}__preview {
  182. border-left: 0.125rem solid $color__gray--darker;
  183. width: 50%;
  184. .input_editor_preview__markdownHTML {
  185. height: 14.2rem;
  186. }
  187. }
  188. }
  189. </style>