skillbox/client/src/components/ui/WagtailImage.vue

121 lines
2.7 KiB
Vue

<template>
<div class="wagtail-image">
<div
:class="['wagtail-image__background', { loaded: loaded }]"
:style="{ height: backgroundHeight }"
ref="imgElement"
>
<img
:src="props.src"
:srcset="props.srcset"
:alt="props.alt"
class="wagtail-image__image"
:sizes="computedSizes"
loading="eager"
v-show="loaded"
@load="handleLoad"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
export interface Props {
src: string;
alt?: string;
originalWidth: number;
originalHeight: number;
srcset?: string;
}
const props = withDefaults(defineProps<Props>(), {
alt: '',
});
const imgElement = ref(null);
const width = ref(0);
const height = ref(0);
const loaded = ref(false);
const backgroundHeight = ref();
const scaledHeight = ref();
//
const updateDimensions = () => {
if (imgElement.value && imgElement.value.parentElement) {
const { clientWidth, clientHeight } = imgElement.value.parentElement;
width.value = clientWidth;
height.value = clientHeight;
}
calculateBackgroundHeight();
};
const calculateBackgroundHeight = () => {
// calculate the hight of the background so, that you see a gray box of correct height before image is loaded
if (width.value) {
const scalingFactor = width.value / props.originalWidth;
scaledHeight.value = Math.round(props.originalHeight * scalingFactor);
if (width.value) {
backgroundHeight.value = `${scaledHeight.value}px`;
return;
}
}
backgroundHeight.value = '100%';
};
const handleLoad = () => {
loaded.value = true; // Set loaded to true when the image loads
};
const computedSizes = computed(() => {
// the default set of image sizes is [160px, 320px, 800px, 1600px]
let size = '100vw';
if (width.value <= 300) {
size = '160px';
}
if (300 < width.value && width.value <= 600) {
size = '320px';
}
if (600 < width.value && width.value <= 1200) {
size = '800px';
}
return size;
});
onMounted(() => {
updateDimensions();
window.addEventListener('resize', updateDimensions);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', updateDimensions);
});
</script>
<style scoped lang="scss">
@import 'styles/helpers';
.wagtail-image {
overflow: hidden;
height: 100%;
&__background {
max-height: 100%;
background-color: $color-silver-light;
}
&__image {
width: 100%;
max-height: 100%;
object-fit: cover; // Ensures the image covers the allocated area without distorting aspect ratio
object-position: center;
}
}
.wagtail-image__background.loaded {
background-color: transparent;
}
</style>