sanity icon indicating copy to clipboard operation
sanity copied to clipboard

SanityImage component doesn't apply hotspot / crop

Open philefstat opened this issue 2 years ago • 4 comments
trafficstars

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

philefstat avatar Mar 17 '23 11:03 philefstat

managed to solve it with "@sanity/image-url" but will leave open for discussion

philefstat avatar Mar 17 '23 11:03 philefstat

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.

davidstackio avatar Apr 18 '23 14:04 davidstackio

@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 avatar Apr 21 '23 23:04 rylanharper

@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 :)

davidstackio avatar Apr 21 '23 23:04 davidstackio