|
27 | 27 | {{ $t('tasks.comment_image') }} |
28 | 28 | </h1> |
29 | 29 |
|
30 | | - <div class="flexrow buttons attachment-modal-buttons"> |
| 30 | + <div class="attachment-upload-zone"> |
31 | 31 | <file-upload |
32 | 32 | ref="fileField" |
33 | | - class="flexrow-item" |
34 | 33 | :label="$t('main.select_file')" |
35 | 34 | :accept="extensions" |
36 | 35 | :multiple="true" |
37 | 36 | :is-primary="false" |
38 | 37 | @fileselected="onFileSelected" |
39 | 38 | hide-file-names |
40 | 39 | /> |
41 | | - <p class="flexrow-item mt1" v-if="isMovie"> |
42 | | - {{ $t('main.or') }} |
43 | | - </p> |
44 | | - <p class="flexrow-item" v-if="isMovie"> |
45 | | - <button |
46 | | - :class="{ |
47 | | - button: true, |
48 | | - 'is-loading': isAnnotationLoading |
49 | | - }" |
50 | | - @click="$emit('add-snapshots')" |
51 | | - > |
52 | | - {{ $t('main.attach_snapshots') }} |
53 | | - </button> |
54 | | - </p> |
| 40 | + </div> |
| 41 | + |
| 42 | + <div class="snapshot-actions" v-if="isMovie || isPicture"> |
| 43 | + <button |
| 44 | + :class="{ |
| 45 | + button: true, |
| 46 | + 'snapshot-button': true, |
| 47 | + 'is-loading': snapshotLoading === 'standard' |
| 48 | + }" |
| 49 | + :disabled="snapshotLoading && snapshotLoading !== 'standard'" |
| 50 | + @click="$emit('add-snapshots')" |
| 51 | + > |
| 52 | + {{ $t('main.attach_snapshots') }} |
| 53 | + </button> |
| 54 | + <button |
| 55 | + :class="{ |
| 56 | + button: true, |
| 57 | + 'snapshot-button': true, |
| 58 | + 'is-loading': snapshotLoading === 'label' |
| 59 | + }" |
| 60 | + :disabled="snapshotLoading && snapshotLoading !== 'label'" |
| 61 | + @click="$emit('add-snapshots-with-label')" |
| 62 | + > |
| 63 | + {{ $t('main.attach_snapshots_with_label') }} |
| 64 | + </button> |
55 | 65 | </div> |
56 | 66 |
|
57 | 67 | <h3 class="subtitle has-text-centered" v-if="forms.length > 0"> |
@@ -118,16 +128,24 @@ const props = defineProps({ |
118 | 128 | isError: { type: Boolean, default: false }, |
119 | 129 | isLoading: { type: Boolean, default: false }, |
120 | 130 | isMovie: { type: Boolean, default: false }, |
| 131 | + isPicture: { type: Boolean, default: false }, |
121 | 132 | title: { type: String, default: '' } |
122 | 133 | }) |
123 | 134 |
|
124 | | -const emit = defineEmits(['add-snapshots', 'cancel', 'confirm']) |
| 135 | +const emit = defineEmits([ |
| 136 | + 'add-snapshots', |
| 137 | + 'add-snapshots-with-label', |
| 138 | + 'cancel', |
| 139 | + 'confirm' |
| 140 | +]) |
125 | 141 |
|
126 | 142 | useModal(toRef(props, 'active'), emit) |
127 | 143 |
|
128 | 144 | const fileField = ref(null) |
129 | 145 | const forms = ref([]) |
130 | | -const isAnnotationLoading = ref(false) |
| 146 | +// Tracks which snapshot button is currently extracting: |
| 147 | +// 'standard', 'label', or null when idle. |
| 148 | +const snapshotLoading = ref(null) |
131 | 149 | const isDraggingFile = ref(false) |
132 | 150 |
|
133 | 151 | const onFileSelected = newForms => { |
@@ -195,11 +213,11 @@ onBeforeUnmount(() => { |
195 | 213 |
|
196 | 214 | defineExpose({ |
197 | 215 | addFiles, |
198 | | - showAnnotationLoading: () => { |
199 | | - isAnnotationLoading.value = true |
| 216 | + showAnnotationLoading: (kind = 'standard') => { |
| 217 | + snapshotLoading.value = kind |
200 | 218 | }, |
201 | 219 | hideAnnotationLoading: () => { |
202 | | - isAnnotationLoading.value = false |
| 220 | + snapshotLoading.value = null |
203 | 221 | } |
204 | 222 | }) |
205 | 223 | </script> |
@@ -264,6 +282,57 @@ h3.subtitle { |
264 | 282 | flex-wrap: wrap; |
265 | 283 | } |
266 | 284 |
|
| 285 | +.attachment-upload-zone { |
| 286 | + border: 2px dashed var(--border); |
| 287 | + border-radius: 10px; |
| 288 | + margin: 1em 0; |
| 289 | + padding: 1.5em; |
| 290 | + text-align: center; |
| 291 | + transition: |
| 292 | + border-color 0.2s ease, |
| 293 | + background 0.2s ease; |
| 294 | +
|
| 295 | + &:hover { |
| 296 | + background: var(--background-hover, rgba(255, 255, 255, 0.03)); |
| 297 | + border-color: var(--background-selectable, $purple-strong); |
| 298 | + } |
| 299 | +
|
| 300 | + // Strip Bulma's button background off the file-upload label so the |
| 301 | + // dropzone's outline is the single visual container — the text sits |
| 302 | + // directly on the dashed area, no inner button chip. |
| 303 | + :deep(.dropbox) { |
| 304 | + background: transparent; |
| 305 | + border: 0; |
| 306 | + justify-content: center; |
| 307 | + padding: 0; |
| 308 | + } |
| 309 | +
|
| 310 | + :deep(.dropbox label.button) { |
| 311 | + background: transparent; |
| 312 | + border: 0; |
| 313 | + color: var(--text); |
| 314 | + cursor: pointer; |
| 315 | + font-weight: 500; |
| 316 | +
|
| 317 | + &:hover { |
| 318 | + background: transparent; |
| 319 | + color: var(--background-selectable, $purple-strong); |
| 320 | + } |
| 321 | + } |
| 322 | +} |
| 323 | +
|
| 324 | +.snapshot-actions { |
| 325 | + display: flex; |
| 326 | + flex-direction: column; |
| 327 | + gap: 0.5em; |
| 328 | + margin-bottom: 1em; |
| 329 | +} |
| 330 | +
|
| 331 | +.snapshot-button { |
| 332 | + width: 100%; |
| 333 | + margin-left: 0; |
| 334 | +} |
| 335 | +
|
267 | 336 | .drop-mask { |
268 | 337 | align-items: center; |
269 | 338 | background: rgba(0.1, 0, 0, 0.5); |
|
0 commit comments