chore: lazy thumbnail loading & animations

This commit is contained in:
2024-08-01 19:22:43 +02:00
parent b49517aded
commit 27b23ccc95
2 changed files with 73 additions and 10 deletions
+9 -10
View File
@@ -11,15 +11,11 @@
</div> </div>
<span> <span>
<img <VehicleThumbnail
v-for="(thumbnailImage, imageIndex) in images" v-for="(thumbnailImage, imageIndex) in images"
:data-mouseover="vehicleName" :vehicle-name="vehicleName"
data-tooltip-type="VehiclePreviewTooltip" :img-name="thumbnailImage"
:data-tooltip-content="vehicleName" :fallback-name="imagesFallbacks[imageIndex]"
:src="`https://static.spythere.eu/thumbnails/v2/${thumbnailImage}.png`"
@error="onImageError($event, imagesFallbacks[imageIndex])"
@click.stop="() => {}"
height="60"
/> />
</span> </span>
</li> </li>
@@ -30,8 +26,11 @@
<script lang="ts"> <script lang="ts">
import { PropType, defineComponent } from 'vue'; import { PropType, defineComponent } from 'vue';
import { useApiStore } from '../../store/apiStore'; import { useApiStore } from '../../store/apiStore';
import VehicleThumbnail from './VehicleThumbnail.vue';
export default defineComponent({ export default defineComponent({
components: { VehicleThumbnail },
props: { props: {
trainStockList: { trainStockList: {
type: Array as PropType<string[]>, type: Array as PropType<string[]>,
@@ -143,7 +142,7 @@ export default defineComponent({
else { else {
let fallbackVehicleImage = 'unknown_cargo'; let fallbackVehicleImage = 'unknown_cargo';
if (/^(EP|EU)/.test(vehicleName)) fallbackVehicleImage = 'unknown_train'; if (/^(EP|EU|ET|201E)/.test(vehicleName)) fallbackVehicleImage = 'unknown_train';
else if (/^(SM42)/.test(vehicleName)) fallbackVehicleImage = 'unknown_SM42'; else if (/^(SM42)/.test(vehicleName)) fallbackVehicleImage = 'unknown_SM42';
else if (/(\d{3}a|(Bau|Gor)\d{2}|304C)_/.test(vehicleName)) else if (/(\d{3}a|(Bau|Gor)\d{2}|304C)_/.test(vehicleName))
fallbackVehicleImage = 'unknown_passenger'; fallbackVehicleImage = 'unknown_passenger';
@@ -160,7 +159,7 @@ export default defineComponent({
}, },
methods: { methods: {
onImageError(event: Event, fallbackImage: string) { onImageError(event: Event, fallbackImage: string) {
(event.target as HTMLImageElement).src = `/images/${fallbackImage}.png`; (event.target as HTMLImageElement).src = `/images/${fallbackImage}.png`;
} }
} }
@@ -0,0 +1,64 @@
<template>
<div class="vehicle-thumbnail">
<img
ref="imgRef"
:src="`https://static.spythere.eu/thumbnails/v2/${imgName}.png`"
height="60"
loading="lazy"
:data-mouseover="vehicleName"
:data-tooltip-content="vehicleName"
:data-load-status="imgStatus"
data-tooltip-type="VehiclePreviewTooltip"
@error="onImageError"
@load="onImageLoad"
/>
</div>
</template>
<script setup lang="ts">
import { onMounted, Ref, ref } from 'vue';
const props = defineProps({
vehicleName: { type: String, required: true },
imgName: { type: String, required: true },
fallbackName: { type: String, required: true },
placeholderName: String
});
const imgRef = ref(null) as Ref<HTMLElement | null>;
// const imgState = ref('loading') as Ref<'loading' | 'loaded' | 'error'>;
const imgStatus = ref('loading');
function onImageError(event: Event) {
console.log('error');
(event.target as HTMLImageElement).src = `/images/${props.fallbackName}.png`;
imgStatus.value = 'error';
// imgState.value = 'error';
}
function onImageLoad() {
if (imgStatus.value != 'error') {
imgStatus.value = 'loaded';
}
imgRef.value!.style.opacity = '1';
}
</script>
<style lang="scss" scoped>
.vehicle-thumbnail {
position: relative;
}
img {
opacity: 0;
transition: opacity 100ms ease-in-out;
&[data-load-status='loading'] {
min-height: 60px;
min-width: 150px;
}
}
</style>