@designcrowd/library.brand-page 5.6.2 → 5.6.3
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.
- package/lib/src/clients/user-media-client.d.ts +2 -1
- package/lib/src/clients/user-media-client.js +19 -5
- package/lib/src/css/library.brand-page-brandCrowd.min.css +32 -4
- package/lib/src/css/library.brand-page-brandPage.min.css +32 -4
- package/lib/src/css/library.brand-page-designCom.min.css +32 -4
- package/lib/src/css/library.brand-page-preview.min.css +32 -4
- package/lib/src/index.mjs +8517 -8427
- package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +4 -0
- package/lib/src/shared/my-uploads/MyMedia.mixin.js +24 -5
- package/lib/src/shared/my-uploads/MyUploads.mixin.js +1 -1
- package/lib/src/shared/my-uploads/models.d.ts +1 -0
- package/package.json +1 -1
- package/src/clients/user-media-client.ts +32 -15
- package/src/shared/my-uploads/MyMedia.mixin.ts +36 -8
- package/src/shared/my-uploads/MyMedia.vue +9 -10
- package/src/shared/my-uploads/MyMediaSelectionItem.vue +137 -0
- package/src/shared/my-uploads/MyUploads.mixin.ts +1 -0
- package/src/shared/my-uploads/models.ts +1 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PropType } from 'vue';
|
|
2
2
|
import type { UserMediaItemWithDimensions } from './models';
|
|
3
|
+
import { UserMediaClient } from '../../clients/user-media-client';
|
|
3
4
|
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
4
5
|
isDeleteEnabled: {
|
|
5
6
|
type: BooleanConstructor;
|
|
@@ -61,6 +62,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
61
62
|
isDeleting: boolean;
|
|
62
63
|
selectedDeleteMediaItem: UserMediaItemWithDimensions | null;
|
|
63
64
|
userMedia: UserMediaItemWithDimensions[];
|
|
65
|
+
userMediaClient: UserMediaClient | null;
|
|
64
66
|
loading: boolean;
|
|
65
67
|
}, {
|
|
66
68
|
filteredUserMedia(): UserMediaItemWithDimensions[];
|
|
@@ -74,6 +76,8 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
74
76
|
onMediaDeleteConfirmClick(image: UserMediaItemWithDimensions): Promise<void>;
|
|
75
77
|
deleteSelectedDeleteMediaItem(): Promise<void>;
|
|
76
78
|
isSvg(imageUrl: string | undefined): boolean;
|
|
79
|
+
onMediaStatusUpdatedToDone(data: any): Promise<void>;
|
|
80
|
+
isImageUploaded(image: any): boolean;
|
|
77
81
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
78
82
|
isDeleteEnabled: {
|
|
79
83
|
type: BooleanConstructor;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UI_EVENTS } from '../../brand-page-maker/constants';
|
|
2
2
|
import { computed, defineComponent } from 'vue';
|
|
3
|
-
import { getInstance as getUserMediaClientInstance } from '../../clients/user-media-client';
|
|
3
|
+
import { getInstance as getUserMediaClientInstance, UserMediaClient, } from '../../clients/user-media-client';
|
|
4
4
|
import { preloadImage } from '../../brand-page/utils';
|
|
5
5
|
import { useUiStore } from '../../brand-page-maker/stores';
|
|
6
6
|
import { MEDIA_TYPES } from '../../brand-page/models/brand-page-context.model';
|
|
@@ -33,6 +33,7 @@ export default defineComponent({
|
|
|
33
33
|
isDeleting: false,
|
|
34
34
|
selectedDeleteMediaItem: null,
|
|
35
35
|
userMedia: [],
|
|
36
|
+
userMediaClient: null,
|
|
36
37
|
loading: false,
|
|
37
38
|
};
|
|
38
39
|
},
|
|
@@ -51,6 +52,7 @@ export default defineComponent({
|
|
|
51
52
|
},
|
|
52
53
|
},
|
|
53
54
|
async mounted() {
|
|
55
|
+
this.userMediaClient = getUserMediaClientInstance(this.endpoints);
|
|
54
56
|
await this.loadUserMedia();
|
|
55
57
|
if (window) {
|
|
56
58
|
window.addEventListener(UI_EVENTS.refreshUserMediaEvent, this.onRefreshMedia);
|
|
@@ -64,8 +66,7 @@ export default defineComponent({
|
|
|
64
66
|
methods: {
|
|
65
67
|
async loadUserMedia() {
|
|
66
68
|
this.loading = true;
|
|
67
|
-
const
|
|
68
|
-
const images = await userMediaClient.getUserMediaAsync(this.supportedFileExtensions, true, this.mediaType);
|
|
69
|
+
const images = await this.userMediaClient.getUserMediaAsync(this.supportedFileExtensions, true, this.mediaType);
|
|
69
70
|
if (Array.isArray(images)) {
|
|
70
71
|
await Promise.all(images.map(async (x) => {
|
|
71
72
|
const image = await preloadImage(x.thumbnailUrl || x.url);
|
|
@@ -114,8 +115,7 @@ export default defineComponent({
|
|
|
114
115
|
}
|
|
115
116
|
this.isDeleting = true;
|
|
116
117
|
try {
|
|
117
|
-
const
|
|
118
|
-
const deleted = await userMediaClient.deleteUserMediaByUserMediaToken(this.selectedDeleteMediaItem.media.token);
|
|
118
|
+
const deleted = await this.userMediaClient.deleteUserMediaByUserMediaToken(this.selectedDeleteMediaItem.media.token);
|
|
119
119
|
if (deleted) {
|
|
120
120
|
this.selectedDeleteMediaItem = null;
|
|
121
121
|
await this.onRefreshMedia();
|
|
@@ -128,5 +128,24 @@ export default defineComponent({
|
|
|
128
128
|
isSvg(imageUrl) {
|
|
129
129
|
return imageUrl?.endsWith('.svg') || false;
|
|
130
130
|
},
|
|
131
|
+
async onMediaStatusUpdatedToDone(data) {
|
|
132
|
+
const newMedia = this.userMedia.map((m) => {
|
|
133
|
+
if (m.media.token === data.media.token) {
|
|
134
|
+
return {
|
|
135
|
+
imagePreviewSrc: data.thumbnailUrl,
|
|
136
|
+
imageSrc: data.url,
|
|
137
|
+
...data,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return m;
|
|
141
|
+
});
|
|
142
|
+
this.userMedia = newMedia;
|
|
143
|
+
},
|
|
144
|
+
isImageUploaded(image) {
|
|
145
|
+
if (image.media && image.media.status) {
|
|
146
|
+
return image.media.status === 'done';
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
},
|
|
131
150
|
},
|
|
132
151
|
});
|
|
@@ -137,7 +137,7 @@ export default defineComponent({
|
|
|
137
137
|
async onDropzoneImageUploaderSuccess(file) {
|
|
138
138
|
const { mediaToken, name, type } = file;
|
|
139
139
|
if (this.userMediaClient) {
|
|
140
|
-
await this.userMediaClient.insertUserMediaAsync(mediaToken, name, type, true, undefined, this.mediaType);
|
|
140
|
+
await this.userMediaClient.insertUserMediaAsync(mediaToken, name, type, true, undefined, this.mediaType, true);
|
|
141
141
|
}
|
|
142
142
|
this.dropzoneImageUploaderRef?.removeAllFiles();
|
|
143
143
|
// Dispatch the refresh event in the dropzone success event handler
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ export class UserMediaClient {
|
|
|
24
24
|
|
|
25
25
|
try {
|
|
26
26
|
const response = await axios.get<PolicyData>(
|
|
27
|
-
`${this.endpoints.userPolicyDataEndpoint}?isPublic=${isPublic}`,
|
|
27
|
+
`${this.endpoints.userPolicyDataEndpoint}?isPublic=${isPublic}&isUpload=true`,
|
|
28
28
|
);
|
|
29
29
|
|
|
30
30
|
if (response.status !== 200) {
|
|
@@ -56,19 +56,21 @@ export class UserMediaClient {
|
|
|
56
56
|
isPublic: boolean,
|
|
57
57
|
relatedAssetToken: string | undefined,
|
|
58
58
|
mediaType: string,
|
|
59
|
+
hasTriggeredProcessing: boolean,
|
|
59
60
|
): Promise<UserMediaItem | undefined> {
|
|
60
61
|
try {
|
|
61
|
-
const
|
|
62
|
-
`${this.endpoints.createUserMediaEndpoint}/${mediaToken}
|
|
63
|
-
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
const reqUrl = hasTriggeredProcessing
|
|
63
|
+
? `${this.endpoints.createUserMediaEndpoint}/${mediaToken}?hasTriggeredProcessing=${hasTriggeredProcessing}`
|
|
64
|
+
: `${this.endpoints.createUserMediaEndpoint}/${mediaToken}`;
|
|
65
|
+
|
|
66
|
+
const response = await axios.put<UserMediaItem>(reqUrl, {
|
|
67
|
+
mediaToken,
|
|
68
|
+
mimeType: type,
|
|
69
|
+
name,
|
|
70
|
+
isPublic,
|
|
71
|
+
relatedAssetToken,
|
|
72
|
+
mediaType,
|
|
73
|
+
});
|
|
72
74
|
|
|
73
75
|
return response.data;
|
|
74
76
|
} catch (e) {
|
|
@@ -118,6 +120,7 @@ export class UserMediaClient {
|
|
|
118
120
|
true,
|
|
119
121
|
relatedAssetToken,
|
|
120
122
|
file.mediaType,
|
|
123
|
+
false,
|
|
121
124
|
);
|
|
122
125
|
|
|
123
126
|
return newMedia?.url;
|
|
@@ -132,9 +135,7 @@ export class UserMediaClient {
|
|
|
132
135
|
|
|
133
136
|
file.mediaToken = mediaToken;
|
|
134
137
|
|
|
135
|
-
const key = `${this.policyData.keyPrefix}${
|
|
136
|
-
file.mediaToken
|
|
137
|
-
}${getExtensionFromMimeType(file.type)}`;
|
|
138
|
+
const key = `${this.policyData.keyPrefix}${file.mediaToken}`;
|
|
138
139
|
|
|
139
140
|
file.key = key;
|
|
140
141
|
formData.append('key', key);
|
|
@@ -178,6 +179,22 @@ export class UserMediaClient {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
|
|
182
|
+
async getUserMediaByTokenAsync(
|
|
183
|
+
mediaToken: string,
|
|
184
|
+
): Promise<UserMediaItem | undefined> {
|
|
185
|
+
try {
|
|
186
|
+
const response = await axios.get(
|
|
187
|
+
`${this.endpoints.getAllUserMediaEndpoint}/${mediaToken}?isPublic=true`,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
return response.data;
|
|
191
|
+
} catch (e) {
|
|
192
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
193
|
+
console.error(e);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
181
198
|
async deleteUserMediaByUserMediaToken(
|
|
182
199
|
userMediaToken: string,
|
|
183
200
|
): Promise<boolean> {
|
|
@@ -2,7 +2,10 @@ import { UI_EVENTS } from '../../brand-page-maker/constants';
|
|
|
2
2
|
import type { PropType } from 'vue';
|
|
3
3
|
import { computed, defineComponent } from 'vue';
|
|
4
4
|
import type { UserMediaItemWithDimensions } from './models';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getInstance as getUserMediaClientInstance,
|
|
7
|
+
UserMediaClient,
|
|
8
|
+
} from '../../clients/user-media-client';
|
|
6
9
|
import { preloadImage } from '../../brand-page/utils';
|
|
7
10
|
import { useUiStore } from '../../brand-page-maker/stores';
|
|
8
11
|
import { MEDIA_TYPES } from '../../brand-page/models/brand-page-context.model';
|
|
@@ -37,6 +40,7 @@ export default defineComponent({
|
|
|
37
40
|
isDeleting: false as boolean,
|
|
38
41
|
selectedDeleteMediaItem: null as UserMediaItemWithDimensions | null,
|
|
39
42
|
userMedia: [] as UserMediaItemWithDimensions[],
|
|
43
|
+
userMediaClient: null as UserMediaClient | null,
|
|
40
44
|
loading: false,
|
|
41
45
|
};
|
|
42
46
|
},
|
|
@@ -56,6 +60,8 @@ export default defineComponent({
|
|
|
56
60
|
},
|
|
57
61
|
},
|
|
58
62
|
async mounted() {
|
|
63
|
+
this.userMediaClient = getUserMediaClientInstance(this.endpoints);
|
|
64
|
+
|
|
59
65
|
await this.loadUserMedia();
|
|
60
66
|
|
|
61
67
|
if (window) {
|
|
@@ -76,8 +82,7 @@ export default defineComponent({
|
|
|
76
82
|
methods: {
|
|
77
83
|
async loadUserMedia() {
|
|
78
84
|
this.loading = true;
|
|
79
|
-
const
|
|
80
|
-
const images = await userMediaClient.getUserMediaAsync(
|
|
85
|
+
const images = await this.userMediaClient.getUserMediaAsync(
|
|
81
86
|
this.supportedFileExtensions,
|
|
82
87
|
true,
|
|
83
88
|
this.mediaType,
|
|
@@ -142,11 +147,10 @@ export default defineComponent({
|
|
|
142
147
|
this.isDeleting = true;
|
|
143
148
|
|
|
144
149
|
try {
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
150
|
+
const deleted =
|
|
151
|
+
await this.userMediaClient.deleteUserMediaByUserMediaToken(
|
|
152
|
+
this.selectedDeleteMediaItem.media.token,
|
|
153
|
+
);
|
|
150
154
|
|
|
151
155
|
if (deleted) {
|
|
152
156
|
this.selectedDeleteMediaItem = null;
|
|
@@ -161,5 +165,29 @@ export default defineComponent({
|
|
|
161
165
|
isSvg(imageUrl: string | undefined): boolean {
|
|
162
166
|
return imageUrl?.endsWith('.svg') || false;
|
|
163
167
|
},
|
|
168
|
+
|
|
169
|
+
async onMediaStatusUpdatedToDone(data) {
|
|
170
|
+
const newMedia = this.userMedia.map((m) => {
|
|
171
|
+
if (m.media.token === data.media.token) {
|
|
172
|
+
return {
|
|
173
|
+
imagePreviewSrc: data.thumbnailUrl,
|
|
174
|
+
imageSrc: data.url,
|
|
175
|
+
...data,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return m;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
this.userMedia = newMedia as UserMediaItemWithDimensions[];
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
isImageUploaded(image) {
|
|
186
|
+
if (image.media && image.media.status) {
|
|
187
|
+
return image.media.status === 'done';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return true;
|
|
191
|
+
},
|
|
164
192
|
},
|
|
165
193
|
});
|
|
@@ -25,15 +25,12 @@
|
|
|
25
25
|
class="c-media-btn tw-p-0 tw-border-none tw-cursor-pointer"
|
|
26
26
|
@click="setSelectedMediaItem(image)"
|
|
27
27
|
>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'tw-bg-grayscale-600': isSvg(image.url),
|
|
35
|
-
'tw-bg-white': !isSvg(image.url),
|
|
36
|
-
}"
|
|
28
|
+
<!-- new image item here -->
|
|
29
|
+
<app-media-selection-item
|
|
30
|
+
:image-test-tag="`user-media-${idx}`"
|
|
31
|
+
:item="image"
|
|
32
|
+
:media-client="userMediaClient"
|
|
33
|
+
@on-media-done="onMediaStatusUpdatedToDone"
|
|
37
34
|
/>
|
|
38
35
|
</button>
|
|
39
36
|
<!-- End media image -->
|
|
@@ -70,7 +67,7 @@
|
|
|
70
67
|
<!-- End media delete confirmation -->
|
|
71
68
|
<!-- Start media delete button -->
|
|
72
69
|
<button
|
|
73
|
-
v-else-if="isDeleteEnabled"
|
|
70
|
+
v-else-if="isDeleteEnabled && isImageUploaded(image)"
|
|
74
71
|
class="tw-absolute tw-bottom-15 tw-right-2 tw-bg-white tw-rounded tw-p-1 tw-border-none tw-cursor-pointer"
|
|
75
72
|
@click="onMediaDeleteButtonClick(image)"
|
|
76
73
|
>
|
|
@@ -93,12 +90,14 @@
|
|
|
93
90
|
<script>
|
|
94
91
|
import { Button, Icon, Loader } from '@designcrowd/fe-shared-lib';
|
|
95
92
|
import MyMediaMixin from './MyMedia.mixin.ts';
|
|
93
|
+
import MyMediaSelectionItem from './MyMediaSelectionItem.vue';
|
|
96
94
|
|
|
97
95
|
export default {
|
|
98
96
|
components: {
|
|
99
97
|
Button,
|
|
100
98
|
Icon,
|
|
101
99
|
Loader,
|
|
100
|
+
appMediaSelectionItem: MyMediaSelectionItem,
|
|
102
101
|
},
|
|
103
102
|
mixins: [MyMediaMixin],
|
|
104
103
|
setup(props, context) {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<img
|
|
3
|
+
v-if="isDone"
|
|
4
|
+
:data-test-tag="props.imageTestTag"
|
|
5
|
+
:src="previewSrc"
|
|
6
|
+
alt=""
|
|
7
|
+
class="c-media-btn__img hover:!tw-shadow-[0_0_0_3px] hover:!tw-shadow-info-500"
|
|
8
|
+
:class="{
|
|
9
|
+
'tw-bg-grayscale-600': isSvg(previewSrc),
|
|
10
|
+
'tw-bg-white': !isSvg(previewSrc),
|
|
11
|
+
}"
|
|
12
|
+
/>
|
|
13
|
+
<div v-else class="tw-w-full tw-h-full">
|
|
14
|
+
<div
|
|
15
|
+
v-if="error"
|
|
16
|
+
class="tw-flex tw-h-full tw-justify-center tw-items-center"
|
|
17
|
+
>
|
|
18
|
+
<Icon
|
|
19
|
+
name="error"
|
|
20
|
+
size="lg"
|
|
21
|
+
color="secondary-300"
|
|
22
|
+
classes="tw-self-center"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
<div v-else class="tw-flex tw-h-full tw-justify-center tw-items-center">
|
|
26
|
+
<Loader />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { ref, onMounted, defineProps, defineEmits } from 'vue';
|
|
33
|
+
import { Icon, Loader } from '@designcrowd/fe-shared-lib';
|
|
34
|
+
import type { UserMediaClient } from 'src/clients/user-media-client';
|
|
35
|
+
import type { UserMediaItemWithDimensions } from './models';
|
|
36
|
+
|
|
37
|
+
const MAX_POLL = 5;
|
|
38
|
+
const EXTRA_WAIT_TIME_EVERY_10_POLL = 2000;
|
|
39
|
+
const POLL_WAIT = 5000;
|
|
40
|
+
|
|
41
|
+
const props = defineProps<{
|
|
42
|
+
imageTestTag: string;
|
|
43
|
+
item: UserMediaItemWithDimensions;
|
|
44
|
+
mediaClient: UserMediaClient;
|
|
45
|
+
}>();
|
|
46
|
+
|
|
47
|
+
const emit = defineEmits<{
|
|
48
|
+
(e: string, payload: any): void;
|
|
49
|
+
}>();
|
|
50
|
+
|
|
51
|
+
const isDone = ref(false);
|
|
52
|
+
const previewSrc = ref<string>('');
|
|
53
|
+
const error = ref(false);
|
|
54
|
+
const currentPoll = ref(0);
|
|
55
|
+
|
|
56
|
+
function isSvg(imageUrl: string | null): boolean {
|
|
57
|
+
return imageUrl?.endsWith('.svg') || false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function checkStatusAsync(): Promise<boolean> {
|
|
61
|
+
currentPoll.value += 1;
|
|
62
|
+
|
|
63
|
+
const data = await props.mediaClient.getUserMediaByTokenAsync(
|
|
64
|
+
props.item.media.token,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (data) {
|
|
68
|
+
const status = data.media.status;
|
|
69
|
+
|
|
70
|
+
if (status === 'inprogress') {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (status === 'done') {
|
|
75
|
+
emit('on-media-done', data);
|
|
76
|
+
previewSrc.value = data.thumbnailUrl ?? data.url ?? '';
|
|
77
|
+
isDone.value = true;
|
|
78
|
+
} else if (status === 'failed') {
|
|
79
|
+
error.value = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function handleProgressAsync() {
|
|
87
|
+
let repeat = true;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
do {
|
|
91
|
+
repeat = await checkStatusAsync();
|
|
92
|
+
|
|
93
|
+
if (currentPoll.value >= MAX_POLL) {
|
|
94
|
+
error.value = true;
|
|
95
|
+
repeat = false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// For every 10th poll, add extra wait time
|
|
99
|
+
const everyTenth = Math.floor(9 / 10);
|
|
100
|
+
const timeToWait = POLL_WAIT + everyTenth * EXTRA_WAIT_TIME_EVERY_10_POLL;
|
|
101
|
+
|
|
102
|
+
await new Promise((r) => setTimeout(r, timeToWait));
|
|
103
|
+
} while (repeat);
|
|
104
|
+
} catch {
|
|
105
|
+
error.value = true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
onMounted(() => {
|
|
110
|
+
const status = props.item.media.status;
|
|
111
|
+
|
|
112
|
+
if (status === 'inprogress') {
|
|
113
|
+
handleProgressAsync();
|
|
114
|
+
} else if (status === 'failed') {
|
|
115
|
+
error.value = true;
|
|
116
|
+
} else {
|
|
117
|
+
// If it's already done or has no status, just set up the image
|
|
118
|
+
previewSrc.value = props.item.thumbnailUrl ?? props.item.url ?? '';
|
|
119
|
+
isDone.value = true;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<style scoped>
|
|
125
|
+
.c-media-btn__img {
|
|
126
|
+
@apply tw-transition-shadow tw-duration-200 tw-ease-out tw-w-full tw-h-full tw-rounded-md tw-object-cover;
|
|
127
|
+
}
|
|
128
|
+
.c-media-btn__img:hover {
|
|
129
|
+
box-shadow: 0 0 0 3px rgb(0, 151, 215);
|
|
130
|
+
}
|
|
131
|
+
.tw-w-full {
|
|
132
|
+
width: 100%;
|
|
133
|
+
}
|
|
134
|
+
.tw-h-full {
|
|
135
|
+
height: 100%;
|
|
136
|
+
}
|
|
137
|
+
</style>
|