From fd3a80ed0b1199fdb0cfb042aca188ca2518866b Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 23 Sep 2024 13:33:25 -0700 Subject: [PATCH] Support image blur placeholders during development (#3234) ## Description This is a quality-of-life change that adds an image placeholder (though not derived from the original image) during development. Before: https://github.com/user-attachments/assets/9b9ea1cf-499b-4411-8209-7bb2dba75a4d After: https://github.com/user-attachments/assets/45cde166-ee16-40da-9d35-076ba18169b1 ## Checklist - [x] I have read and understood the [WATcloud Guidelines](https://cloud.watonomous.ca/docs/community-docs/watcloud/guidelines) - [x] I have performed a self-review of my code --- components/picture.tsx | 9 +++++---- lib/utils.ts | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/components/picture.tsx b/components/picture.tsx index 8691b4d..8106031 100644 --- a/components/picture.tsx +++ b/components/picture.tsx @@ -1,5 +1,6 @@ import type { WATcloudStaticImage } from "@/build/fixtures/images"; import { getImageBlurSvg } from "@/lib/image-blur-svg"; +import { shimmer, toBase64 } from "@/lib/utils"; /** * Renders an image component with multiple sources and an alt text. @@ -23,12 +24,12 @@ export default function Picture({ imgClassName?: string; style?: React.CSSProperties; }) { - // The blur logic is derived from https://github.com/vercel/next.js/blob/98be3ba23ea65ac5b581999d79a1093f147b46f0/packages/next/src/shared/lib/get-img-props.ts#L626 + // The blur logic is derived from https://github.com/vercel/next.js/blob/98be3ba23ea65ac5b581999d79a1093f147b46f0/packages/next/src/shared/lib/get-img-props.ts // blurDataURL is a base64-encoded string generated by the nextjs image loader - // This is only generated during production builds, so in development, we might see - // no placeholders. - const blurDataURL = image.jpg.blurDataURL || ""; + // This is only generated during production builds, and is set to a (broken) URL starting with "/_next" + // during development. In that case, we use a placeholder SVG instead. + const blurDataURL = (image.jpg.blurDataURL || "/_next").startsWith("/_next") ? `data:image/svg+xml;base64,${toBase64(shimmer(image.jpg.width, image.jpg.height))}` : image.jpg.blurDataURL as string; const backgroundImage = `url("data:image/svg+xml;charset=utf-8,${getImageBlurSvg( { diff --git a/lib/utils.ts b/lib/utils.ts index de6ac77..091e248 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -383,4 +383,25 @@ export function maxBy(array: T[], iteratee: (element: T) => number): T | unde export function minBy(array: T[], iteratee: (element: T) => number): T | undefined { return maxBy(array, (element) => -iteratee(element)); -} \ No newline at end of file +} + +// Derived from https://github.com/vercel/next.js/blob/4380d0b79d07637abd50a584b51317eae1297885/examples/image-legacy-component/pages/shimmer.tsx#L4-L16 +export const shimmer = (w: number, h: number) => ` + + + + + + + + + + + +`; + +// Derived from https://github.com/vercel/next.js/blob/4380d0b79d07637abd50a584b51317eae1297885/examples/image-legacy-component/pages/shimmer.tsx#L18-L21 +export const toBase64 = (str: string) => + typeof window === "undefined" + ? Buffer.from(str).toString("base64") + : window.btoa(str); \ No newline at end of file