feat: optimización de imágenes (WebP y AppImage), Lazy Load y LCP (Fase 1 y 2)

This commit is contained in:
2026-03-21 15:08:05 -05:00
parent a89bf59bdf
commit 64c3bbb1d7
8 changed files with 137 additions and 20 deletions

View File

@ -0,0 +1,88 @@
<template>
<div class="app-image-wrapper" :class="{ 'is-loading': !isLoaded, [wrapperClass]: !!wrapperClass }">
<img
:src="resolvedSrc"
:alt="alt"
:loading="priority ? 'eager' : 'lazy'"
:fetchpriority="priority ? 'high' : 'auto'"
decoding="async"
@load="handleLoad"
@error="handleError"
class="app-image-content"
:class="{ 'is-loaded': isLoaded, [imgClass]: !!imgClass }"
/>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { getImageUrl } from '@/utils/imageUrl'
const props = withDefaults(defineProps<{
src?: string | null;
alt?: string;
type?: 'taxi' | 'shuttle' | 'business' | 'coupon';
priority?: boolean;
errorFallback?: string;
wrapperClass?: string;
imgClass?: string;
}>(), {
priority: false,
wrapperClass: '',
imgClass: ''
});
const isLoaded = ref(false)
const isError = ref(false)
const resolvedSrc = computed(() => {
if (isError.value && props.errorFallback) return props.errorFallback
return getImageUrl(props.src, props.type)
})
function handleLoad() {
isLoaded.value = true
}
function handleError(e: Event) {
isError.value = true
isLoaded.value = true
}
</script>
<style scoped>
.app-image-wrapper {
position: relative;
overflow: hidden;
display: inline-flex;
justify-content: center;
align-items: center;
background-color: transparent;
}
.app-image-wrapper.is-loading {
background: linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%);
background-size: 200% 100%;
animation: pulse 1.5s infinite;
}
.app-image-content {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.app-image-content.is-loaded {
opacity: 1;
}
@media (prefers-color-scheme: dark) {
.app-image-wrapper.is-loading {
background: linear-gradient(90deg, #1f2937 25%, #374151 50%, #1f2937 75%);
}
}
@keyframes pulse {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</style>