Last active
June 7, 2022 21:29
-
-
Save tylerpaige/e6bca4212753cfd0ae2a2b0fb4e193b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import { GatsbyImage } from 'gatsby-plugin-image' | |
/* | |
Example: | |
<GatsbyImageFromStrapi | |
image={image} | |
transformations={[getCropTransformation('4:5')]} | |
layoutsByBreakpoint={{ | |
xs: 0.5, | |
sm: 0.33, | |
lg: 0.25 | |
}} | |
/> | |
*/ | |
export const GatsbyImageFromStrapi = ({ | |
image, | |
transformations = [], | |
layoutsByBreakpoint = undefined, | |
...props | |
}) => { | |
const parsedImage = parseCloudinaryUrlFromStrapiImage(image) | |
// If the transformations include a change to the aspect ratio, | |
// we want to use that instead of the ratio we parsed from Strapi | |
if (transformations.some((t) => t.includes('ar_'))) { | |
const cropTransfomation = transformations.find((t) => t.includes('ar_')) | |
const [width, height] = cropTransfomation.split('ar_').pop().split(':') | |
parsedImage.aspectRatio = parseInt(width) / parseInt(height) | |
} | |
const sources = getSourcesFromStrapiImage( | |
parsedImage, | |
transformations, | |
layoutsByBreakpoint | |
) | |
const thumbnailSource = { | |
src: transformStrapiImage(parsedImage, [ | |
...transformations, | |
getResizeTransformation(100), | |
]), | |
type: parsedImage.mime, | |
size: '100w', | |
} | |
const gatsbyImageData = {} | |
gatsbyImageData.layout = 'fullWidth' | |
gatsbyImageData.backgroundColor = '#f8e8e8' | |
gatsbyImageData.width = parsedImage.aspectRatio | |
gatsbyImageData.height = 1 | |
gatsbyImageData.images = {} | |
gatsbyImageData.images.fallback = {} | |
gatsbyImageData.images.fallback.src = thumbnailSource.src | |
gatsbyImageData.images.fallback.srcSet = `${thumbnailSource.src} 100w` | |
gatsbyImageData.images.fallback.sizes = '100w' | |
gatsbyImageData.images.sources = sources.map((source) => { | |
return { | |
srcSet: source.src, | |
media: source.media, | |
} | |
}) | |
return ( | |
<GatsbyImage | |
image={gatsbyImageData} | |
alt={image.alternativeText} | |
{...props} | |
/> | |
) | |
} | |
export const breakpoints = { | |
sm: 400, | |
md: 800, | |
lg: 1600, | |
xl: 3200 | |
} | |
export const breakpointsArr = Object.entries(breakpoints); | |
export const parseCloudinaryUrlFromStrapiImage = (image) => { | |
const publicID = image.hash | |
let baseURL = image.url.substring(0, image.url.indexOf(publicID)) | |
if (!baseURL.endsWith('upload/')) { | |
baseURL = baseURL.substring( | |
0, | |
baseURL.indexOf('upload/') + 'upload/'.length | |
) | |
} | |
const aspectRatio = image.width / image.height | |
return { | |
aspectRatio, | |
baseURL, | |
publicID, | |
mime: image.mime, | |
alternativeText: image.alternativeText, | |
} | |
} | |
export const transformStrapiImage = (image, transformations) => { | |
const { publicID, baseURL } = | |
image.publicID && image.baseURL | |
? image | |
: parseCloudinaryUrlFromStrapiImage(image) | |
const transformationStr = transformations.join('/') | |
return `${baseURL}${transformationStr}/${publicID}` | |
} | |
export const getResizeTransformation = (width) => { | |
return `c_scale,w_${width}` | |
} | |
export const getCropTransformation = (ratio) => { | |
return `c_crop,ar_${ratio}` | |
} | |
export const resizeStrapiImage = (image, width) => { | |
return transformStrapiImage(image, [getResizeTransformation(width)]) | |
} | |
export const getLayoutMultiplierForBreakpoint = (breakpoint, layouts = {}) => { | |
// A shorthand way to use this is to pass in the multiplier itself | |
if (typeof layouts === "number") { | |
return layouts; | |
} | |
const defaultSize = 1; | |
switch (breakpoint) { | |
case "xl": | |
return layouts.xl || layouts.lg || layouts.md || layouts.sm || defaultSize | |
case "lg": | |
return layouts.lg || layouts.md || layouts.sm || defaultSize | |
case "md": | |
return layouts.md || layouts.sm || defaultSize | |
case "sm": | |
return layouts.sm || defaultSize | |
default: | |
return defaultSize | |
} | |
} | |
export const getSourcesFromStrapiImage = ( | |
image, | |
transformations = [], | |
layoutsByBreakpoint = undefined | |
) => { | |
return breakpointsArr.map(([breakpoint, minimumViewportWidth]) => { | |
const layoutMultiplier = getLayoutMultiplierForBreakpoint(breakpoint, layoutsByBreakpoint); | |
const renderedWidth = minimumViewportWidth * layoutMultiplier; | |
const widthToRequest = renderedWidth * 2; | |
const src = transformStrapiImage(image, [ | |
...transformations, | |
getResizeTransformation(widthToRequest), | |
]) | |
const media = breakpoint === "sm" ? "" : `(min-width: ${minimumViewportWidth}px)`; | |
return { | |
// the url | |
src, | |
// the media query clause | |
media, | |
// the mimetype | |
type: image.mime, | |
// how wide the image asset itself is | |
naturalWidth: widthToRequest, | |
// (approximately) how wide the image will be on the page | |
renderedWidth: renderedWidth | |
} | |
}).reverse(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment