sanity
sanity copied to clipboard
SanityImage component doesn't apply hotspot / crop
Heya, my understanding is that SanityImage should apply hotspot / crop automatically but it doesn't appear to be working.
I'm using version 1.6.0 of the module and 3.1.1 of nuxt
managed to solve it with "@sanity/image-url" but will leave open for discussion
I'm in the same boat. I'm using @sanity/image-url for images instead of this module's image functionality - mainly because of the hotspot issue.
@philefstat @davidstackio The SanityImage component hasn't been working with the hotspot for a while unfortunately..
I've been using Nuxt3 with @nuxt/image-edge which is working quite well. Here is my snippet:
My picture.js in my Sanity schema:
import { ImageSquare } from 'phosphor-react'
const aspectRatios = [
{
title: 'Original',
value: 'aspect-0'
},
{
title: '1/1 (Square)',
value: 'aspect-1/1'
},
{
title: '2/1',
value: 'aspect-2/1'
},
{
title: '3/2',
value: 'aspect-3/2'
},
{
title: '4/6',
value: 'aspect-4/6'
},
{
title: '16/9',
value: 'aspect-16/9'
}
]
export default {
title: 'Image',
name: 'picture',
type: 'image',
icon: ImageSquare,
options: {
hotspot: true,
metadata: ['lqip']
},
fields: [
{
title: 'Alternative text',
name: 'alt',
type: 'string',
description: 'A short description of the image. Important for SEO and accessiblity.',
validation: (Rule) => Rule.required()
},
{
title: 'Display Size (Aspect Ratio)',
name: 'customRatio',
type: 'string',
description: 'Select how the image is displayed. This affects the aspect ratio of the image within its container.',
options: {
list: aspectRatios
},
initialValue: 'aspect-0'
}
],
preview: {
select: {
alt: 'alt',
filename: 'asset.originalFilename',
dimensions: 'asset.metadata.dimensions',
image: 'asset'
},
prepare({ alt, dimensions, filename, image }) {
return {
title: alt ?? filename,
subtitle: dimensions ? `${dimensions.width}px × ${dimensions.height}px` : '…',
media: image ?? ImageSquare
}
}
}
}
You want to install @nuxt/image-edge for Nuxt3 and add the following code to your nuxt.config.js file:
image: {
sanity: {
projectId: process.env.SANITY_PROJECT_ID,
dataset: process.env.SANITY_DATASET
},
screens: {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
xxl: 1536,
'2xl': 1920,
'3xl': 2400
},
}
And my custom sanity-image.vue component:
<script setup>
const props = defineProps({
image: {
type: Object,
default: undefined
}
})
const styles = computed(() => {
if (!props.image.customRatio) {
return {}
}
return {
'aspect-0': props.image.customRatio === 'aspect-0',
'aspect-1/1': props.image.customRatio === 'aspect-1/1',
'aspect-2/1': props.image.customRatio === 'aspect-2/1',
'aspect-3/2': props.image.customRatio === 'aspect-3/2',
'aspect-4/6': props.image.customRatio === 'aspect-4/6',
'aspect-16/9': props.image.customRatio === 'aspect-16/9'
}
})
const computedSizes = computed(() => {
const sizeVars = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl', '2xl', '3xl']
return sizeVars.map(size => `${size}:100vw`).join(' ')
})
</script>
<template>
<figure class="relative w-full overflow-hidden" :class="styles">
<nuxt-img
:src="props.image.asset._ref"
:alt="props.image.alt"
provider="sanity"
fit="cover"
:sizes="computedSizes"
:modifiers="{
crop: props.image.crop,
hotspot: props.image.hotspot,
}"
loading="lazy"
class="relative w-full h-full"
/>
</figure>
</template>
This example allows for a fully responsive image across almost all screen-sizes with a predefined srcset. It also allows the user to easily select how the aspect ratio of the image is displayed within its own container. Additionally, crops and hotspots are also supported. *Note that I am using tailwind/unocss with this example
@danielroe Maybe we can add this example above to the docs since Nuxt-Image has an official Sanity provider?
@rylanharper Thanks for sharing! I'm using Nuxt 3 as well, but will wait for @nuxt/image to hit v1. Already bookmarked your comment for future reference :)