feat(template-card): add media placeholder and smooth video fade-in
add gradient background media placeholder for empty states update video to use 0.18s ease opacity fade-in transition add videoReady state to track when video is ready to display adjust z-indexes for correct media layer stacking fix video rendering condition and add state reset watchers update template media container background color
This commit is contained in:
@@ -4,10 +4,12 @@
|
|||||||
:class="{ 'is-active': active }"
|
:class="{ 'is-active': active }"
|
||||||
>
|
>
|
||||||
<view class="template-media">
|
<view class="template-media">
|
||||||
|
<view class="template-media-placeholder" />
|
||||||
<image v-if="templatePosterUrl" class="template-image" :src="templatePosterUrl" mode="aspectFill" />
|
<image v-if="templatePosterUrl" class="template-image" :src="templatePosterUrl" mode="aspectFill" />
|
||||||
<video
|
<video
|
||||||
v-else-if="templateVideoUrl && playing && !videoLoadFailed"
|
v-if="templateVideoUrl && playing && !videoLoadFailed"
|
||||||
class="template-video"
|
class="template-video"
|
||||||
|
:class="{ 'is-ready': videoReady }"
|
||||||
:src="templateVideoUrl"
|
:src="templateVideoUrl"
|
||||||
autoplay
|
autoplay
|
||||||
muted
|
muted
|
||||||
@@ -18,6 +20,8 @@
|
|||||||
:show-fullscreen-btn="false"
|
:show-fullscreen-btn="false"
|
||||||
:enable-progress-gesture="false"
|
:enable-progress-gesture="false"
|
||||||
object-fit="cover"
|
object-fit="cover"
|
||||||
|
@play="handleVideoReady"
|
||||||
|
@timeupdate="handleVideoReady"
|
||||||
@error="handleVideoError"
|
@error="handleVideoError"
|
||||||
/>
|
/>
|
||||||
<view class="template-media-shade" />
|
<view class="template-media-shade" />
|
||||||
@@ -57,6 +61,7 @@ const emit = defineEmits(["select"]);
|
|||||||
|
|
||||||
const VIDEO_EXT_REGEXP = /\.(mp4|mov|webm|m4v)(?:[?#].*)?$/i;
|
const VIDEO_EXT_REGEXP = /\.(mp4|mov|webm|m4v)(?:[?#].*)?$/i;
|
||||||
const videoLoadFailed = ref(false);
|
const videoLoadFailed = ref(false);
|
||||||
|
const videoReady = ref(false);
|
||||||
|
|
||||||
const templateMediaUrl = computed(() => {
|
const templateMediaUrl = computed(() => {
|
||||||
return props.template.templateContentUrl || props.template.coverPhotoUrl || "";
|
return props.template.templateContentUrl || props.template.coverPhotoUrl || "";
|
||||||
@@ -75,13 +80,26 @@ const templatePosterUrl = computed(() => {
|
|||||||
return templateMediaUrl.value;
|
return templateMediaUrl.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleVideoReady = () => {
|
||||||
|
videoReady.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
const handleVideoError = () => {
|
const handleVideoError = () => {
|
||||||
|
videoReady.value = false;
|
||||||
videoLoadFailed.value = true;
|
videoLoadFailed.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(templateVideoUrl, () => {
|
watch(templateVideoUrl, () => {
|
||||||
|
videoReady.value = false;
|
||||||
videoLoadFailed.value = false;
|
videoLoadFailed.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(() => props.playing, (playing) => {
|
||||||
|
videoReady.value = false;
|
||||||
|
if (playing) {
|
||||||
|
videoLoadFailed.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -42,18 +42,45 @@
|
|||||||
flex: 0 0 var(--template-card-media-height, 358px);
|
flex: 0 0 var(--template-card-media-height, 358px);
|
||||||
height: var(--template-card-media-height, 358px);
|
height: var(--template-card-media-height, 358px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #0f7069;
|
background: #0a4d46;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.template-media-placeholder,
|
||||||
.template-image,
|
.template-image,
|
||||||
.template-video {
|
.template-video {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.template-media-placeholder {
|
||||||
|
background:
|
||||||
|
radial-gradient(
|
||||||
|
90% 48% at 50% 30%,
|
||||||
|
rgba(255, 255, 255, 0.12),
|
||||||
|
rgba(255, 255, 255, 0) 70%
|
||||||
|
),
|
||||||
|
linear-gradient(160deg, #17383a 0%, #0f7069 58%, #0a4d46 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-image {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.template-video {
|
.template-video {
|
||||||
|
z-index: 2;
|
||||||
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
transition: opacity 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-video.is-ready {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.template-media-shade {
|
.template-media-shade {
|
||||||
@@ -62,6 +89,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
z-index: 3;
|
||||||
background:
|
background:
|
||||||
radial-gradient(
|
radial-gradient(
|
||||||
92% 45% at 50% 28%,
|
92% 45% at 50% 28%,
|
||||||
|
|||||||
Reference in New Issue
Block a user