Ability to save image width and height when uploading an image
- Dominant language
- JavaScript
- Stars
- 19.4k
- Forks
- 3.1k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 9
Description
**Is your feature request related to a problem? Please describe.**
Nowadays modern browsers use image 'width' and 'height' attributes to avoid layout shift
https://twitter.com/jensimmons/status/1172922185570279425
Also Next.js image component requires 'width' and 'height' attributes to be provided
https://nextjs.org/docs/api-reference/next/image#required-props
The problem is that it's pretty annoying to input these values manually. It would be very convenient if these values could be written automatically when image is uploaded.
**Describe the solution you'd like**
In config in could look like
```yml
collections:
- label: Albums
name: albums
folder: content/albums
format: yaml
create: true
fields:
- { label: Title, name: title, widget: string }
- label: Images
name: images
widget: list
fields:
- { label: Image, name: image, widget: image }
- { label: Width, name: width, widget: string, value: '{{entry.images.image.width}}' }
- { label: Height, name: height, widget: string, value: '{{entry.images.image.height}}' }
```
**Describe alternatives you've considered**
Currently I'm doing it using CMS preSave event, but it's pretty verbose
```ts
async function saveImageDimensions({ entry }: any) {
if (entry.get('data').get('collection') !== 'albums') {
return entry.get('data')
}
const images = entry.get('data').get('images').toJSON()
const mediaFiles = entry.get('mediaFiles').toJSON() as ReadonlyArray<{
path: string
url: string
}>
const mediaFilesObj: { [key: string]: string } = {}
for (let i = 0, l = mediaFiles.length; i < l; i += 1) {
const { url, path } = mediaFiles[i]
mediaFilesObj[path.replace(/^public(.*)/, '$1')] = url
}
const dimensions = await Promise.all<{
path: string
width: number
height: number
}>(
images.map(({ image }: { image: string }) => {
return new Promise((resolve) => {
const img = new Image()
img.onload = function handleLoad() {
resolve({
path: image,
width: img.naturalWidth,
height: img.naturalHeight,
})
}
img.src = mediaFilesObj[image]
})
}),
)
const dimensionsObj: {
[key: string]: { width: number; height: number }
} = {}
for (let i = 0, l = dimensions.length; i < l; i += 1) {
const { path, width, height } = dimensions[i]
dimensionsObj[path] = { width, height }
}
return entry.get('data').set(
'images',
entry
.get('data')
.get('images')
.map((item: any) => {
return item
.set('width', dimensionsObj[item.get('image')].width)
.set('height', dimensionsObj[item.get('image')].height)
}),
)
}
cms.registerEventListener({
name: 'preSave',
handler: saveImageDimensions,
})
```
Contributor guide
Assessment
This issue has not been assessed yet.