vue-intergrall-plugins 0.0.4 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,78 +1,81 @@
1
1
  <template>
2
- <div class="text-footer-container" v-on-clickaway="away" v-if="textId">
2
+ <div class="text-footer-container" v-on-clickaway="away" v-if="textId" @drop.stop="dropFile" @dragenter.prevent @dragover.prevent>
3
3
  <div class="text-footer" :class="cssStyle.width ? cssStyle.width: ''" :style="`background-color: ${cssStyle.backgroundColor}`">
4
- <emojis-text-footer :ref="`${this.textId}`" :emojiId="`${this.textId}`" v-if="buttons.hasEmojis && !audioFile" :down="emojiSettings.openEmojisFrom == 'top' ? false : true" :small="emojiSettings.smallEmojis" @insert-emoji="insertEmoji"></emojis-text-footer>
4
+ <EmojisTextFooter
5
+ v-show="buttons.hasEmojis && !audioFile"
6
+ :ref="`${this.textId}`"
7
+ :emojiId="`${this.textId}`"
8
+ :down="emojiSettings.openEmojisFrom == 'top' ? false : true"
9
+ :small="emojiSettings.smallEmojis"
10
+ @insert-emoji="insertEmoji"
11
+ />
5
12
  <transition name="fade">
6
- <req-loader v-if="isSending" />
13
+ <Loader v-if="isSending" />
7
14
  </transition>
8
- <textarea v-if="!audioFile" :id="`text-footer-${this.textId}`" @input="sendFinalMessage" v-model="message" @keydown.up="toggleHSM" @keydown.down="toggleHSM" @keydown.esc="closeEmojis" @keydown.enter="sendMessageHandler" :disabled="textareaSettings.disabled" :placeholder="textareaSettings.placeholderMessage" @paste="pasteImage" class="js-autoresize"></textarea>
15
+ <textarea
16
+ class="js-autoresize"
17
+ v-if="!audioFile"
18
+ v-model="message"
19
+ :id="`text-footer-${this.textId}`"
20
+ :disabled="textareaSettings.disabled"
21
+ :placeholder="textareaSettings.placeholderMessage"
22
+ @input="sendFinalMessage"
23
+ @keydown.up="toggleHSM"
24
+ @keydown.down="toggleHSM"
25
+ @keydown.esc="closeEmojis"
26
+ @keydown.enter="sendMessageHandler"
27
+ @paste="pasteImage"
28
+ ></textarea>
9
29
  <div class="text-footer-audio" v-else>
10
30
  <audio :src="audioSource" controls="controls"></audio>
11
31
  <span class="delete-audio" title="Cancelar" @click="deleteAudio">
12
32
  <fa-icon :icon="['fas', 'times']" />
13
33
  </span>
14
34
  </div>
15
- <span class="max-characters no-width" :class="{'d-none' : audioFile}" v-if="textareaSettings.maxCharacters" v-text="`(${this.remainingCharacters})`"></span>
35
+ <RemainingCharacters
36
+ :class="{'d-none' : audioFile}"
37
+ :message="message"
38
+ :maxCharacters="textareaSettings.maxCharacters"
39
+ />
16
40
  <div class="text-footer-actions" v-if="buttons.hasSendButton">
17
41
  <span class="text-footer-actions--btn" :title="dictionary.title_enviar_msg" @click="sendMessageHandler">
18
42
  <fa-icon :icon="['fas', 'paper-plane']" />
19
43
  </span>
20
44
  </div>
21
45
  <div v-if="buttons.hasFiles || buttons.hasAudio" class="text-footer-actions" :class="{'outside-buttons' : cssStyle.outsideButtons && !audioFile}">
22
- <span v-if="buttons.hasAudio && !audioFile" class="text-footer-actions--btn" :class="{'audio-activated' : isRecording}" @click="toggleAudioRecorder">
23
- <fa-icon :icon="['fas', 'microphone']" />
24
- </span>
25
- <span v-if="buttons.hasFiles && !audioFile" class="text-footer-actions--btn" :class="{'files-activated' : openFiles}" :title="dictionary.title_selecionar_anexo" @click="toggleFiles">
26
- <fa-icon :icon="['fas', 'paperclip']" />
27
- </span>
46
+ <BtnMic
47
+ v-show="buttons.hasAudio && !audioFile"
48
+ :dictionary="dictionary"
49
+ @set-audio="setAudio"
50
+ :ref="`${textId}-mic`"
51
+ />
52
+ <BtnFiles
53
+ v-show="buttons.hasFiles && !audioFile"
54
+ :textId="textId"
55
+ :dictionary="dictionary"
56
+ :fileSettings="fileSettings"
57
+ :cssStyle="cssStyle"
58
+ :ref="`${textId}-file`"
59
+ @set-file-vars="setFileVars"
60
+ />
28
61
  </div>
29
62
  </div>
30
- <transition name="show">
31
- <div v-if="buttons.hasFiles && openFiles" class="text-footer-files-container" :class="{'horizontal' : cssStyle.outsideButtons}">
32
- <div class="files-btn images" :class="{'margin-bottom' : cssStyle.outsideButtons}" :title="dictionary.title_anexo_img" @click="selectImage">
33
- <fa-icon :icon="['fas', 'image']" />
34
- </div>
35
- <div class="files-btn docs" :title="dictionary.title_anexo_doc" @click="selectDoc">
36
- <fa-icon :icon="['fas', 'file-alt']" />
37
- </div>
38
- <div class="files-pointers d-none">
39
- <input type="file" :id="`file-${textId}`" accept="image/*" @change="fileUpload($event, 'img')" />
40
- <input type="file" :id="`doc-${textId}`" accept="application/*" @change="fileUpload($event, 'doc')" />
41
- </div>
42
- </div>
43
- </transition>
44
- <transition name="fade">
45
- <div class="text-footer-preview-container" v-if="showFilePreview" :class="{'isDoc' : isDoc && !fileFormatError, 'isImg' : !isDoc && !fileFormatError, 'isError' : fileFormatError}">
46
- <span @click="deleteFile" :title="dictionary.msg_cancelar_anexo" class="text-footer-exclude-file">
47
- <fa-icon :icon="['fas', 'times-circle']" />
48
- </span>
49
- <h3 v-if="file.name" class="text-footer-preview-title">
50
- <fa-icon :icon="['fas', 'file-alt']" v-if="isDoc" />
51
- <fa-icon :icon="['fas', 'image']" v-else />
52
- {{ file.name }}
53
- </h3>
54
- <div class="text-footer-invalid-format" v-if="fileFormatError">
55
- <h3 v-text="dictionary.titulo_msg_formato_invalido"></h3>
56
- <h4 v-text="validFileFormats"></h4>
57
- </div>
58
- <div class="text-footer-image-preview" v-if="imagePreview">
59
- <img :src="imagePreview" :alt="dictionary.alt_previa_img" @click="openImage">
60
- </div>
61
- </div>
62
- </transition>
63
63
  </div>
64
64
  </template>
65
65
 
66
66
  <script>
67
67
  import { setResizeListeners, resetTargets } from "@/services/autoResize"
68
68
  import { mixin as clickaway } from "vue-clickaway"
69
- import { returnMessageWithHexa, formataHoraMensagem } from "@/services/textFormatting"
69
+ import { returnMessageWithHexa } from "@/services/textFormatting"
70
70
 
71
71
  import EmojisTextFooter from "./EmojisTextFooter"
72
- import ReqLoader from "../Loader/ReqLoader"
72
+ import Loader from "../Loader/Loader"
73
+ import RemainingCharacters from "./RemainingCharacters"
74
+ import BtnMic from "./BtnMic"
75
+ import BtnFiles from "./BtnFiles"
73
76
 
74
77
  export default {
75
- components: { EmojisTextFooter, ReqLoader },
78
+ components: { EmojisTextFooter, Loader, BtnMic, BtnFiles, RemainingCharacters },
76
79
  mixins: [ clickaway ],
77
80
  props: {
78
81
  buttons: {
@@ -102,7 +105,7 @@ export default {
102
105
  },
103
106
  fileSettings: {
104
107
  type: Object,
105
- default: () => { return { docsExtensions: "", imagesExtensions: "" } },
108
+ default: () => { return { docsExtensions: "", imagesExtensions: "", multiple: false } },
106
109
  required: false
107
110
  },
108
111
  textId: {
@@ -124,14 +127,6 @@ export default {
124
127
  required: true
125
128
  }
126
129
  },
127
- computed: {
128
- remainingCharacters() {
129
- if(this.message && this.message.length) {
130
- return this.textareaSettings.maxCharacters - this.message.length
131
- }
132
- return this.textareaSettings.maxCharacters
133
- }
134
- },
135
130
  data() {
136
131
  return {
137
132
  message: "",
@@ -141,11 +136,8 @@ export default {
141
136
  imagePreview: "",
142
137
  isDoc: false,
143
138
  fileFormatError: false,
144
- validFileFormats: "",
145
139
  audioFile: "",
146
- audioSource: "",
147
- mediaRecorder: {},
148
- isRecording: false
140
+ audioSource: ""
149
141
  }
150
142
  },
151
143
  created() {
@@ -154,17 +146,12 @@ export default {
154
146
  mounted() {
155
147
  setResizeListeners(this.$el, ".js-autoresize", ".js-parentresize")
156
148
 
157
- this.$root.$on("drop-file", (file, type) => { if(this.buttons.hasFiles) this.fileUpload(file, type, true) })
158
-
159
- this.$root.$on("toggle-msg-formatada", () => { this.toggleHSM() })
160
-
161
- this.$root.$on("textarea-focus", () => { this.focusTextarea() })
162
-
163
- this.$root.$on("resize-footer-template", () => { this.adjustChatHeight() })
164
-
165
- this.$root.$on("clear-footer-message", () => { this.message = "" })
166
-
167
- if(this.cssStyle.outsideButtons) if(this.$root.$refs.chatCorpo) this.$root.$refs.chatCorpo.setOutsideButtons(this.cssStyle.outsideButtons)
149
+ // this.$root.$on("drop-file", (file, type) => { if(this.buttons.hasFiles) this.fileUpload(file, type, true) })
150
+ // this.$root.$on("toggle-msg-formatada", () => { this.toggleHSM() })
151
+ // this.$root.$on("textarea-focus", () => { this.focusTextarea() })
152
+ // this.$root.$on("resize-footer-template", () => { this.adjustChatHeight() })
153
+ // this.$root.$on("clear-footer-message", () => { this.message = "" })
154
+ // if(this.cssStyle.outsideButtons) if(this.$root.$refs.chatCorpo) this.$root.$refs.chatCorpo.setOutsideButtons(this.cssStyle.outsideButtons)
168
155
  },
169
156
  methods: {
170
157
  closeEmojis() {
@@ -176,7 +163,7 @@ export default {
176
163
  }
177
164
  },
178
165
  away() {
179
- this.openFiles = false
166
+ if(this.$refs[`${this.textId}-file`]) this.$refs[`${this.textId}-file`].openFiles = false
180
167
  },
181
168
  setDefaultMessage(msg) {
182
169
  this.message = msg
@@ -205,7 +192,12 @@ export default {
205
192
  if(this.textareaSettings.disabled) return false
206
193
 
207
194
  if(this.fileFormatError) {
208
- this.$toasted.global.formatoInvalido()
195
+ this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido })
196
+ const str = {
197
+ img: this.fileSettings.imagesExtensions.split("|").join(", "),
198
+ doc: this.fileSettings.docsExtensions.split("|").join(", ")
199
+ }
200
+ this.$toasted.global.showValidFormats({ msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}` })
209
201
  return false
210
202
  }
211
203
 
@@ -249,7 +241,7 @@ export default {
249
241
 
250
242
  const messageAux = this.formatMessage(this.message)
251
243
  if(this.verifyMessage()){
252
- if(messageAux.message || this.showFilePreview || this.audioFile) {
244
+ if(messageAux || this.showFilePreview || this.audioFile) {
253
245
  this.$emit("send-message", messageAux)
254
246
  const objMessage = this.returnObjectMessage(messageAux)
255
247
  this.$emit("obj-message", objMessage)
@@ -266,166 +258,115 @@ export default {
266
258
  },
267
259
  resetFooterData() {
268
260
  if(this.audioFile) this.deleteAudio()
269
- if(this.showFilePreview) this.deleteFile()
261
+ if(this.showFilePreview) this.$refs[`${this.textId}-file`].deleteFile()
270
262
  this.message = ""
271
263
  this.sendFinalMessage()
272
264
  resetTargets(this.$el, ".js-autoresize", ".js-parentresize", "38px")
273
265
  this.focusTextarea()
274
266
  },
275
- activeFormatHourMessage() {
276
- return formataHoraMensagem(false)
277
- },
278
267
  returnObjectMessage(message) {
279
268
  return {
280
269
  message,
281
- data: this.$store.getters.getDataServer ? this.$store.getters.getDataServer.slice(0, 10) : '',
282
- hora: this.activeFormatHourMessage(),
283
- anexo: this.showFilePreview ? this.file : false,
284
- imgAnexo: this.imagePreview,
270
+ attachment: this.showFilePreview ? this.file : false,
285
271
  isDoc: this.isDoc,
286
- audio: this.audioFile ? this.audioFile : false,
287
- audioAnexo: this.audioSource,
288
- seq: null
272
+ imagePreview: this.imagePreview,
273
+ isAudio: this.audioFile ? true : false,
274
+ audioAttachment: this.audioSource
289
275
  }
290
276
  },
291
- toggleFiles() {
292
- this.openFiles = !this.openFiles
277
+ setFileVars(fileObj) {
278
+ const { file, showFilePreview, imagePreview, isDoc, fileFormatError } = fileObj;
279
+
280
+ this.file = file
281
+ this.showFilePreview = showFilePreview
282
+ this.imagePreview = imagePreview ? imagePreview : ""
283
+ this.isDoc = isDoc
284
+ this.fileFormatError = fileFormatError
293
285
  },
294
- selectImage() {
295
- if(this.$store.getters.getChatBlocker) return this.toggleFiles()
296
- const fileInput = document.querySelector(`#file-${this.textId}`)
297
- if(fileInput) fileInput.click()
298
- if(!fileInput) if (!document.querySelector(".toasted.toasted-primary.error")) this.$toasted.global.defaultError()
286
+ openImage(imagePreview) {
287
+ this.$emit("open-image", imagePreview)
299
288
  },
300
- selectDoc() {
301
- if(this.$store.getters.getChatBlocker) return this.toggleFiles()
302
- const fileInput = document.querySelector(`#doc-${this.textId}`)
303
- if(fileInput) fileInput.click()
304
- if(!fileInput) if (!document.querySelector(".toasted.toasted-primary.error")) this.$toasted.global.defaultError()
289
+ setAudio(audioObj) {
290
+ const { audioFile, audioSource } = audioObj
291
+ this.audioFile = audioFile
292
+ this.audioSource = audioSource
305
293
  },
306
- isFileValid(type) {
307
- const extensions = type === "img" ? this.fileSettings.imagesExtensions : this.fileSettings.docsExtensions
308
- const regex = new RegExp("("+extensions+")", "i")
309
-
310
- if(regex.test(this.file.name)) return true
311
-
312
- this.$toasted.global.formatoInvalido()
313
- return false
294
+ deleteAudio() {
295
+ this.$refs[`${this.textId}-mic`].deleteMediaRecorder()
296
+ this.audioFile = ""
297
+ this.audioSource = ""
314
298
  },
315
- fileUpload(event, type, externalCall) {
316
- this.openFiles = false
317
- if(this.showFilePreview) this.deleteFile()
299
+ returnFileType(file, stopAlert) {
300
+ const imgRegex = new RegExp("\.("+this.fileSettings.imagesExtensions+")", "i")
301
+ if(imgRegex.test(file.name)) return "img"
318
302
 
319
- const fileReader = new FileReader()
303
+ const docRegex = new RegExp("\.("+this.fileSettings.docsExtensions+")", "i")
304
+ if(docRegex.test(file.name)) return "doc"
320
305
 
321
- this.file = !externalCall ? event.target.files || event.dataTransfer.files : event
322
-
323
- if(!this.file.length) {
324
- this.file = []
325
- return
306
+ if(!stopAlert) return
307
+ if (!document.querySelector(".toasted.toasted-primary.error")) this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido })
308
+ const str = {
309
+ img: this.fileSettings.imagesExtensions.split("|").join(", "),
310
+ doc: this.fileSettings.docsExtensions.split("|").join(", ")
326
311
  }
312
+ this.$toasted.global.showValidFormats({ msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}` })
313
+ return false
314
+ },
315
+ filesHandler(files) {
316
+ const fileType = this.returnFileType(files[0], true)
317
+ let invalidFile = false
318
+ files.forEach(file => {
319
+ const singleFileType = this.returnFileType(file, true)
320
+ if(!singleFileType) {
321
+ invalidFile = true
322
+ file.invalid = true
323
+ }
324
+ file.imgOrDoc = singleFileType ? singleFileType : ""
325
+ })
327
326
 
328
- this.file = this.file[0]
329
- if(!externalCall) {
330
- const selector = type === "img" ? `#file-${this.textId}` : `#doc-${this.textId}`
331
- document.querySelector(selector).value = ""
332
- }
333
-
334
- this.showFilePreview = true
335
- if(type === "img") {
336
- fileReader.onload = () => { this.imagePreview = fileReader.result }
337
- }
338
-
339
- if(this.isFileValid(type)) {
340
- if(type === "img") fileReader.readAsDataURL(this.file)
341
- if(type === "doc") this.isDoc = true
342
-
343
- this.focusTextarea()
344
- this.fileFormatError = false
327
+ if(!invalidFile) {
328
+ this.$refs[`${this.textId}-file`].fileUpload(files, fileType, true)
345
329
  }else {
346
- this.fileFormatError = true
347
- this.validFileFormats = `${type === "img" ? this.fileSettings.imagesExtensions : this.fileSettings.docsExtensions} ${this.dictionary.msg_extensoes_aceitas}`
330
+ this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido })
331
+ const str = {
332
+ img: this.fileSettings.imagesExtensions.split("|").join(", "),
333
+ doc: this.fileSettings.docsExtensions.split("|").join(", ")
334
+ }
335
+ this.$toasted.global.showValidFormats({ msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}` })
348
336
  }
349
337
  },
350
- deleteFile() {
351
- this.file = []
352
- this.isDoc = false
353
- this.showFilePreview = false
354
- this.imagePreview = ""
355
- this.fileFormatError = false
356
- this.validFileFormats = ""
357
- },
358
- openImage() {
359
- this.$store.dispatch("toggleBlocker", { state: true, origin: "visualizar-imagem" })
360
- this.$store.dispatch("setLinkImagem", this.imagePreview)
361
- },
362
- initAudioRecorder() {
363
- navigator.mediaDevices.getUserMedia({ audio: true })
364
- .then(stream => {
365
- this.mediaRecorder = new MediaRecorder(stream)
366
- const audioChunks = []
367
- this.mediaRecorder.ondataavailable = eventData => { audioChunks.push(eventData.data) }
368
- this.mediaRecorder.onstop = () => {
369
- const blob = new Blob(audioChunks, { type: "audio/mpeg" })
370
- blob.lastModifiedDate = new Date()
371
- blob.name = `im-audio-file-${this.$store.getters.getNomeOpe}-${parseInt(Math.random() * 5000)}`
372
- const reader = new FileReader()
373
- reader.readAsDataURL(blob)
374
- reader.onloadend = () => {
375
- this.audioFile = new File([blob], `${blob.name}.mpeg`, { type: blob.type })
376
- this.audioSource = reader.result
377
- }
378
- stream.getTracks().forEach(track => track.stop())
379
- }
380
-
381
- this.toggleAudioRecorder()
382
- },
383
- error => {
384
- this.$toasted.global.defaultError({ msg: this.dictionary.msg_permitir_audio })
385
- console.error("error audio recorder: ", error)
386
- })
387
- },
388
- toggleAudioRecorder() {
389
- if(!this.mediaRecorder.state) return this.initAudioRecorder()
390
-
391
- this.isRecording = !this.isRecording
392
-
393
- if(this.isRecording) return this.mediaRecorder.start()
394
- return this.mediaRecorder.stop()
395
- },
396
- deleteAudio() {
397
- this.mediaRecorder = {}
398
- this.audioFile = ""
338
+ dropFile(e) {
339
+ try {
340
+ e.stopPropagation()
341
+ e.preventDefault()
342
+ const files = e.dataTransfer.files.length ? e.dataTransfer.files : ""
343
+ this.filesHandler(files)
344
+ }catch(e) {
345
+ console.error("Erro drop file")
346
+ console.error(e)
347
+ }
399
348
  },
400
349
  pasteImage(e) {
401
- if(e.clipboardData.files.length && !this.buttons.hasFiles) {
402
- e.preventDefault()
403
- return
404
- }else if(e.clipboardData.files.length && this.buttons.hasFiles) {
405
- const file = e.clipboardData.files
406
-
407
- let fileType = ""
408
- const imgRegex = new RegExp("("+this.fileSettings.imagesExtensions+")", "i")
409
- if(imgRegex.test(file[0].name)) fileType = "img"
410
-
411
- const docRegex = new RegExp("("+this.fileSettings.docsExtensions+")", "i")
412
- if(docRegex.test(file[0].name)) fileType = "doc"
413
-
414
- if(fileType) {
415
- this.fileUpload(file, fileType, true)
416
- }else {
417
- this.$toasted.global.formatoInvalido()
418
- this.$toasted.global.formatosValidos()
350
+ try {
351
+ if(e.clipboardData.files.length && !this.buttons.hasFiles) {
352
+ e.preventDefault()
353
+ return
354
+ }else if(e.clipboardData.files.length && this.buttons.hasFiles) {
355
+ const files = e.clipboardData.files
356
+ this.filesHandler(files)
419
357
  }
358
+ }catch(e) {
359
+ console.error("Nao foi possivel colar a/o imagem/documento")
360
+ console.error(e)
420
361
  }
421
362
  },
422
363
  },
423
364
  destroyed() {
424
- this.$root.$off("drop-file")
425
- this.$root.$off("toggle-msg-formatada")
426
- this.$root.$off("textarea-focus")
427
- this.$root.$off("clear-footer-message")
428
- this.$root.$off("resize-footer-template")
365
+ // this.$root.$off("drop-file")
366
+ // this.$root.$off("toggle-msg-formatada")
367
+ // this.$root.$off("textarea-focus")
368
+ // this.$root.$off("clear-footer-message")
369
+ // this.$root.$off("resize-footer-template")
429
370
  }
430
371
  }
431
372
  </script>
@@ -504,7 +445,7 @@ ul {
504
445
  z-index: 1;
505
446
  color: #444;
506
447
  position: relative;
507
- top: 28px;
448
+ top: 30px;
508
449
  left: 5px; }
509
450
  .text-footer-container .max-characters.no-width {
510
451
  width: 0; }
@@ -591,7 +532,7 @@ ul {
591
532
  font-size: 1rem; }
592
533
  .text-footer-container .text-footer-files-container {
593
534
  position: absolute;
594
- right: -55px;
535
+ right: 0;
595
536
  top: -55px;
596
537
  padding: 5px;
597
538
  background-color: rgba(0, 0, 0, 0.4);
@@ -601,6 +542,7 @@ ul {
601
542
  justify-content: space-between;
602
543
  z-index: 1; }
603
544
  .text-footer-container .text-footer-files-container.horizontal {
545
+ right: -55px;
604
546
  flex-direction: column; }
605
547
  .text-footer-container .text-footer-files-container .files-btn {
606
548
  transition-duration: 300ms;
@@ -629,29 +571,39 @@ ul {
629
571
  .text-footer-container .text-footer-files-container .files-btn.docs {
630
572
  background-color: #7986cb; }
631
573
  .text-footer-container .text-footer-preview-container {
574
+ cursor: default;
632
575
  position: absolute;
633
- background-color: #AAA;
576
+ left: 0;
577
+ background-color: rgb(225, 225, 225);
634
578
  border-top-left-radius: 5px;
635
579
  border-top-right-radius: 5px; }
636
580
  .text-footer-container .text-footer-preview-container.isDoc {
637
581
  top: -50px;
638
582
  width: 100%;
639
583
  height: 45px; }
640
- .text-footer-container .text-footer-preview-container.isImg {
584
+ .text-footer-container .text-footer-preview-container.isImg, .text-footer-container .text-footer-preview-container.isMultiple {
641
585
  top: -205px;
642
586
  width: 100%;
643
587
  height: 200px; }
644
588
  .text-footer-container .text-footer-preview-container.isImg .text-footer-image-preview {
645
589
  height: 170px; }
646
590
  .text-footer-container .text-footer-preview-container.isError {
647
- top: -155px;
591
+ top: -80px;
648
592
  width: 100%;
649
- height: 150px; }
593
+ height: 75px; }
650
594
  .text-footer-container .text-footer-preview-container .text-footer-exclude-file {
651
595
  position: absolute;
652
596
  top: 5px;
653
597
  right: 5px;
654
- cursor: pointer; }
598
+ cursor: pointer;
599
+ display: flex;
600
+ justify-content: center;
601
+ align-items: center;
602
+ min-width: 1rem;
603
+ min-height: 1rem;
604
+ background-color: #FFF;
605
+ border-radius: 50%;
606
+ }
655
607
  .text-footer-container .text-footer-preview-container .text-footer-exclude-file svg {
656
608
  transition: color 200ms;
657
609
  color: #e9594a; }
@@ -674,6 +626,7 @@ ul {
674
626
  max-height: 98%;
675
627
  padding: 2%; }
676
628
  .text-footer-container .text-footer-preview-container .text-footer-invalid-format {
629
+ color: #222;
677
630
  padding: 10px; }
678
631
  .text-footer-container .text-footer-preview-container .text-footer-invalid-format h3 {
679
632
  font-weight: 500; }
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div class="req-loader-container" :class="{'align-right' : alignRight, 'light-bg' : hasBg}">
3
+ <div class="req-loader" :class="{'big' : size == 'big'}"></div>
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ props: {
10
+ hasBg: {
11
+ type: Boolean,
12
+ required: false
13
+ },
14
+ alignRight: {
15
+ type: Boolean,
16
+ required: false
17
+ },
18
+ size: {
19
+ type: String,
20
+ required: false,
21
+ default: "small"
22
+ }
23
+ }
24
+ }
25
+ </script>
26
+
27
+ <style>
28
+ .req-loader-container {
29
+ position: absolute;
30
+ top: 0;
31
+ left: 0;
32
+ width: 100%;
33
+ height: 100%;
34
+ display: flex;
35
+ justify-content: center;
36
+ align-items: center;
37
+ }
38
+ .req-loader-container.light-bg {
39
+ background-color: rgba(0, 0, 0, 0.3);
40
+ border-radius: inherit;
41
+ }
42
+ .req-loader-container.align-right {
43
+ justify-content: flex-end;
44
+ }
45
+ .req-loader-container.align-right .req-loader {
46
+ margin-right: 15px;
47
+ }
48
+
49
+ .req-loader {
50
+ border: 2px solid #CCC;
51
+ border-top: 2px solid #333;
52
+ border-radius: 50%;
53
+ width: 20px;
54
+ height: 20px;
55
+ min-width: 20px;
56
+ min-height: 20px;
57
+ animation: spin 2s linear infinite;
58
+ }
59
+ .req-loader.big {
60
+ width: 40px;
61
+ height: 40px;
62
+ animation: spin 3s linear infinite;
63
+ }
64
+ .req-loader.slow {
65
+ animation: spin 4s linear infinite;
66
+ }
67
+
68
+ @keyframes spin {
69
+ 0% { transform: rotate(0deg); }
70
+ 100% { transform: rotate(360deg); }
71
+ }
72
+
73
+ </style>