121 lines
2.7 KiB
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>
|