Skip to content

Instantly share code, notes, and snippets.

@heggemsnes
Created May 25, 2022 14:26
Show Gist options
  • Save heggemsnes/77191373ec5393a1fde7d5e929924a0e to your computer and use it in GitHub Desktop.
Save heggemsnes/77191373ec5393a1fde7d5e929924a0e to your computer and use it in GitHub Desktop.
Next Figure / Image – Kult
import { urlFor } from "@lib/sanity"
import { getImageDimensions } from "@sanity/asset-utils"
import {
SanityImageObject,
SanityImageSource,
} from "@sanity/image-url/lib/types/types"
import Image from "next/image"
import {
SanityReference,
SanityImageAsset,
SanityImageCrop,
SanityImageHotspot,
} from "sanity-codegen"
export type UseNextSanityImageDimensions = {
width: number
height: number
aspectRatio: number
}
import { Figure, FlexibleImage } from "sanity-types/schema"
type IImage = {
_type: "image" | "figure" | "flexibleImage"
asset: SanityReference<SanityImageAsset>
crop?: SanityImageCrop
hotspot?: SanityImageHotspot
customRatio?: FlexibleImage["customRatio"]
}
export interface INextFigure {
image: FlexibleImage | Figure
width?: number
height?: number
className?: string
sizes?: string
captionClassName?: string
}
export function NextFigure({
image,
width,
height,
className,
sizes,
captionClassName,
}: INextFigure) {
if (!image || !image?.asset) return null
const { caption, alt } = image
return (
<>
<figure className={`${className}`}>
<NextImage
alt={alt}
image={image}
sizes={sizes}
width={width}
height={height}
/>
{caption && (
<figcaption
className={`border-b border-gray text-sm py-1 ${
captionClassName && captionClassName
}`}
>
{caption}
</figcaption>
)}
</figure>
</>
)
}
interface IINextImage {
image: IImage | any
width?: number
height?: number
alt?: string
sizes?: string
className?: string
layout?: "fixed" | "responsive" | "fill"
[x: string]: any
}
export function NextImage({
image,
width,
height,
alt,
sizes = "(max-width: 500px) 50vw, 500px",
layout = "responsive",
...rest
}: IINextImage) {
if (!image || !image?.asset) return null
const base = image && getImageDimensions(image)
const realAlt = image?.alt ?? alt ?? ""
const cropped = getCroppedDimensions(image, base)
if ("customRatio" in image && image.customRatio !== "0") {
const { width: cWidth, height: cHeight } = getRatioDimension(
image.customRatio
)
const aspect = cHeight / cWidth
const blurHeight = Math.round(64 * aspect)
return (
<Image
alt={realAlt}
placeholder="blur"
blurDataURL={
urlFor(image)
.width(64)
.height(blurHeight)
.quality(30)
.blur(50)
.url() ?? ""
}
sizes={sizes}
layout={layout}
src={urlFor(image).width(cWidth).height(cHeight).url() ?? ""}
width={cWidth}
height={cHeight}
{...rest}
/>
)
}
if (width && height) {
const aspect = height / width
const blurHeight = Math.round(64 * aspect)
return (
<Image
alt={realAlt}
placeholder="blur"
blurDataURL={
urlFor(image)
.width(64)
.height(blurHeight)
.quality(30)
.blur(50)
.url() ?? ""
}
sizes={sizes}
layout={layout}
src={urlFor(image).width(width).height(height).url() ?? ""}
width={width}
height={height}
{...rest}
/>
)
}
// Auto format
return (
<Image
alt={realAlt}
placeholder="blur"
sizes={sizes}
blurDataURL={urlFor(image).width(64).quality(30).blur(50).url() ?? ""}
layout={layout}
src={
urlFor(image).width(cropped.width).height(cropped.height).url() ?? ""
}
width={cropped.width}
height={cropped.height}
{...rest}
/>
)
}
export function getRatioDimension(customRatio: FlexibleImage["customRatio"]) {
switch (customRatio) {
case "1":
return { width: 1000, height: 1000 }
case "medium":
return { width: 1500, height: 1100 }
case "horizontal":
return { width: 2600, height: 1000 }
case "vertical":
return { width: 1100, height: 1500 }
default:
return { width: 1000, height: 1000 }
}
}
export function getCroppedDimensions(
image: SanityImageSource,
baseDimensions: UseNextSanityImageDimensions
): UseNextSanityImageDimensions {
const crop = (image as SanityImageObject).crop
if (!crop) {
return baseDimensions
}
const { width, height } = baseDimensions
const croppedWidth = width * (1 - (crop.left + crop.right))
const croppedHeight = height * (1 - (crop.top + crop.bottom))
return {
width: Math.floor(croppedWidth),
height: Math.floor(croppedHeight),
aspectRatio: croppedWidth / croppedHeight,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment