|
48 | 48 |
|
49 | 49 | <div class="form-floating mb-3 uploadCard"> |
50 | 50 | <h4> |
51 | | - {{ tc("posts.form.imageupload", Object.keys(files).length) }} |
| 51 | + {{ tc("posts.form.fileupload", Object.keys(files).length) }} |
52 | 52 | <small class="text-body-secondary f-4" v-if="Object.keys(files).length > 0"> |
53 | 53 | ({{ convertToHumanReadableFileSize(totalBytesInFiles) }}) |
54 | 54 | </small> |
55 | 55 |
|
56 | | - <span class="tiny">{{ t("posts.form.imageupload_hint") }}</span> |
| 56 | + <span class="tiny">{{ t("posts.form.fileupload_hint") }}</span> |
57 | 57 | </h4> |
58 | 58 | <!-- Hidden file input, used to open the file dialog, when the dropzone is clicked --> |
59 | 59 | <input style="display: none" type="file" id="file" multiple v-on:change="handleFileChange($event)" |
60 | | - accept=".png, .gif, .jpg, .jpeg, .webp,image/png, image/jpeg, image/gif, image/webp" /> |
| 60 | + accept=".png, .gif, .jpg, .jpeg, .webp, .mp3, .wav, image/png, image/jpeg, image/gif, image/webp, audio/mp3, audio/wav" /> |
61 | 61 |
|
62 | | - <div class="imagesPreviewContaier" v-if="Object.keys(files).length"> |
| 62 | + <div class="filesPreviewContainer" v-if="Object.keys(files).length"> |
63 | 63 | <div class="inner"> |
64 | 64 | <Suspense v-for="hash in Object.keys(files).reverse()" v-bind:key="hash"> |
65 | | - <ImagePreview :value="files[hash]" :hash="hash" |
66 | | - @paste="pasteImageFileToMarkdown($event, 'afterCursor')" @delete=" |
67 | | - removeImageFileFromMarkdown(files[hash]); |
| 65 | + <ImagePreview v-if="isImageFile(files[hash])" :value="files[hash]" :hash="hash" |
| 66 | + @paste="pasteFileToMarkdown($event, 'afterCursor')" @delete=" |
| 67 | + removeFileFromMarkdown(files[hash]); |
68 | 68 | delete files[hash]; |
69 | | - " @softdelete="removeImageFileFromMarkdown(files[hash])"> |
| 69 | + " @softdelete="removeFileFromMarkdown(files[hash])"> |
70 | 70 | </ImagePreview> |
| 71 | + <AudioPreview v-else-if="isAudioFile(files[hash])" :value="files[hash]" :hash="hash" |
| 72 | + @paste="pasteFileToMarkdown($event, 'afterCursor')" @delete=" |
| 73 | + removeFileFromMarkdown(files[hash]); |
| 74 | + delete files[hash]; |
| 75 | + " @softdelete="removeFileFromMarkdown(files[hash])"> |
| 76 | + </AudioPreview> |
71 | 77 | </Suspense> |
72 | 78 | </div> |
73 | 79 | </div> |
|
100 | 106 | class="text-primary"> |
101 | 107 | <loading-spinner /> |
102 | 108 | </div> |
103 | | - <mark-down :markdown="md" v-bind:custom-image-urls="files" @loading="loading = $event" |
| 109 | + <mark-down :markdown="md" v-bind:custom-file-urls="files" @loading="loading = $event" |
104 | 110 | :style="loading ? 'opacity:0.2' : 'opacity:1'"></mark-down> |
105 | 111 | </div> |
106 | 112 | </div> |
|
147 | 153 | background-color: #dee2e6; |
148 | 154 | } |
149 | 155 |
|
150 | | -.imagesPreviewContaier { |
| 156 | +.filesPreviewContainer { |
151 | 157 | width: 100%; |
152 | 158 | max-width: 100%; |
153 | 159 | min-width: 100%; |
|
309 | 315 |
|
310 | 316 | <script setup lang="ts"> |
311 | 317 | import AiSummaries from "@client/components/AiSummaries.vue"; |
| 318 | +import AudioPreview from "@client/components/AudioPreview.vue"; |
312 | 319 | import ImagePreview from "@client/components/ImagePreview.vue"; |
313 | 320 | import LoadingSpinner from "@client/components/LoadingSpinner.vue"; |
314 | 321 | import MarkDown from "@client/components/MarkDown.vue"; |
@@ -410,6 +417,26 @@ const removeImageFileFromMarkdown = (file: File) => { |
410 | 417 | }, 0); |
411 | 418 | }; |
412 | 419 |
|
| 420 | +const pasteFileToMarkdown = (markdown: string, insertPosition: SupportedInsertPositionType = "afterCursor") => { |
| 421 | + form.markdown = insertIntoTextarea(markdown, markdownArea.value as unknown as HTMLTextAreaElement, insertPosition); |
| 422 | +}; |
| 423 | +
|
| 424 | +const removeFileFromMarkdown = (file: File) => { |
| 425 | + const strToRemove = `.find((key) => files[key] === file)})`.trim(); |
| 426 | + setTimeout(() => { |
| 427 | + // give the preview time to update |
| 428 | + form.markdown = form.markdown.split(strToRemove).join(""); |
| 429 | + }, 0); |
| 430 | +}; |
| 431 | +
|
| 432 | +const isImageFile = (file: File): boolean => { |
| 433 | + return file.type.startsWith('image/'); |
| 434 | +}; |
| 435 | +
|
| 436 | +const isAudioFile = (file: File): boolean => { |
| 437 | + return file.type.startsWith('audio/'); |
| 438 | +}; |
| 439 | +
|
413 | 440 | const openFileDialog = (): void => { |
414 | 441 | document.getElementById("file")?.click(); |
415 | 442 | }; |
|
0 commit comments