Skip to content

Instantly share code, notes, and snippets.

@naotone
Last active June 3, 2021 02:20
Show Gist options
  • Save naotone/23d36f33fc82daa4ca65bb617cbecde6 to your computer and use it in GitHub Desktop.
Save naotone/23d36f33fc82daa4ca65bb617cbecde6 to your computer and use it in GitHub Desktop.
Vue component for responsive images with Sanity CMS.
<template>
<picture
v-if="devices === '3x'"
:role="role"
>
<source
v-for="(val, key, index) in sizes"
:key="index"
:media="`(min-width: ${val.media}em)`"
:srcset="`
${getSrcSet(val.width)} 1x,
${getSrcSet(val.width, 2)} 2x,
${getSrcSet(val.width, 3)} 3x
`">
<img
:alt="alt"
:src="src"
>
</picture>
<picture
v-else
:role="role"
>
<source
v-for="(val, key, index) in sizes"
:key="index"
:media="`(min-width: ${val.media}em)`"
:srcset="`
${getSrcSet(val.width)} 1x,
${getSrcSet(val.width, 2)} 2x
`">
<img
:alt="alt"
:src="src"
>
</picture>
</template>
<script>
import imageUrlBuilder from '@sanity/image-url';
import sanity from '../sanity';
const builder = imageUrlBuilder(sanity);
export default {
props: {
image: {
type: Object,
required: true,
},
sizes: {
type: Object,
default() {
return {
s: { media: 0, width: 400 },
m: { media: 48, width: 800 },
l: { media: 64, width: 1200 },
};
},
},
alt: {
type: String,
default: 'Missing caption',
},
role: {
type: String,
default: 'img',
},
fit: {
type: String,
default: 'clip',
},
quality: {
type: Number,
default: 82,
},
w: {
type: Number,
default: undefined,
},
h: {
type: Number,
default: undefined,
},
format: {
type: String,
default: undefined,
},
flipHorizontal: {
type: Boolean,
default: false,
},
flipVertical: {
type: Boolean,
default: false,
},
},
computed: {
src() {
return builder
.image(this.image)
.width(this.w)
.height(this.h)
.quality(this.quality)
.fit(this.fit)
.format(this.format);
},
},
methods: {
getSrcSet(w, dpr = 1) {
if (!this.h) {
return builder
.image(this.image)
.width(w * dpr)
.quality(this.quality)
.fit(this.fit)
.format(this.format);
}
return builder
.image(this.image)
.width(w * dpr)
.height(this.getHeightFromWidth(w, this.getAspectRatio()) * dpr)
.quality(this.quality)
.fit(this.fit)
.format(this.format);
},
getHeightFromWidth(w, h) {
return Math.floor(w * h);
},
getAspectRatio() {
return this.h / this.w;
},
},
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment