Created
February 26, 2021 14:57
-
-
Save monecchi/f6d73655f47e07be1cc00b469cfa93b6 to your computer and use it in GitHub Desktop.
Revisions
-
TheThirdRace revised this gist
Dec 5, 2020 . 1 changed file with 14 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -4,8 +4,19 @@ * Keep the values in sync between: * - `deviceSizes` in `next.config.js` * - `deviceSizes` in `image.ts` * * ! Recommended * NextJs optimize images according to your viewport. This is wonderful for mobile, but for desktop with a 4k screen, NextJs would * download the 3840px version of your image. * * To workaround this unfortunate situation, I highly recommend you pass `size` to images with the highest width value being the * max width an image can have on your site. * * For example, content on my site is centered and cannot be more than 960px wide, thus I make sure that 960 is in `deviceSizes` and * I use `Sizes.main` to limit the image to only 960px. This considerably reduce the size in KB of my images and they're much * better optimized on screens larger than 960px. * * This file is a way to generate the strings to pass to Image's `size` property and put the results in an Enum for easier consumption */ const deviceSizes = [320, 480, 640, 750, 828, 960, 1080, 1200, 1440, 1920, 2048, 2560, 3840] const deviceSizesMax = Math.max(...deviceSizes) @@ -24,7 +35,7 @@ const generateSizes = (upperLimit: number = deviceSizesMax): string => { }) .join() } // console.log(generateSizes(960)) // I use a variable, but since it's easier to understand with a real number... // console.log(generateSizes()) export enum Sizes { -
TheThirdRace revised this gist
Dec 5, 2020 . 2 changed files with 49 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,11 +1,13 @@ import { chakra, ThemingProps, useStyleConfig } from '@chakra-ui/react' import NextImage, { ImageProps as NextImageProps } from 'next/image' import { ReactElement } from 'react' import { Sizes } from '../../theme/variables/image' // TODO review props when NextJs is updated so we don't have to defined it here /** * ? Because NextJs typing is preventing auto-suggest for layout, width and height, * ? we declare the styles differently in this component and will manage the switch * ? to NextJs typings when calling NextJs `next/image` component */ type LayoutValue = 'fixed' | 'intrinsic' | 'responsive' | undefined @@ -20,8 +22,7 @@ type LayoutAndSize = } /** * Types for the Image component itself */ type ImageProps = Pick< NextImageProps, @@ -31,10 +32,11 @@ type ImageProps = Pick< Pick<ThemingProps, 'variant'> & { dimensions?: [number, number] layout?: 'fill' | LayoutValue sizes?: Sizes // could be a string too, this one is just a way to make it easier } /** * Wraps NextJs `next/image` component in Chakra's factory function * This is what will allow to use the theme and the styling properties on the component */ const ImageWithChakra = chakra( @@ -47,13 +49,14 @@ const ImageWithChakra = chakra( objectPosition, priority, quality, sizes, src, unoptimized, ...nextjsInternals }: ImageProps): ReactElement => { /** * ? As explained earlier, NextJs typing is preventing auto-suggest for layout, width and height * ? Here we actually convert our component typing to NextJs typing */ const [width, height] = dimensions @@ -68,9 +71,6 @@ const ImageWithChakra = chakra( layout: 'fill' } return ( <NextImage className={className} @@ -79,9 +79,12 @@ const ImageWithChakra = chakra( objectPosition={objectPosition} priority={priority} quality={quality} sizes={sizes} src={src} unoptimized={unoptimized} // eslint-disable-next-line react/jsx-props-no-spreading {...layoutAndSize} // eslint-disable-next-line react/jsx-props-no-spreading {...nextjsInternals} /> ) @@ -90,9 +93,10 @@ const ImageWithChakra = chakra( export const Image = ({ variant, ...props }: ImageProps): ReactElement => { /** * ? This components serves as an interface to pass Chakra's styles * ? You can use the theme and/or styling properties (eg. backgroundColor='red.200') */ const styles = useStyleConfig('Image', { variant }) // eslint-disable-next-line react/jsx-props-no-spreading return <ImageWithChakra sx={styles} {...props} /> } This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,33 @@ /** * ! Important in optimizing images * * Keep the values in sync between: * - `deviceSizes` in `next.config.js` * - `deviceSizes` in `image.ts` * - `contentMaxWidthInPixel` in `page.ts` * - value needs to be included in `deviceSizes` */ const deviceSizes = [320, 480, 640, 750, 828, 960, 1080, 1200, 1440, 1920, 2048, 2560, 3840] const deviceSizesMax = Math.max(...deviceSizes) /** * ? `generateSizes` will create the strings necessary for `Sizes` enum * * ? Simply uncomment the `console.log` and adjust values */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const generateSizes = (upperLimit: number = deviceSizesMax): string => { const sizes = [...deviceSizes.filter((v) => v < upperLimit), upperLimit] return sizes .map((v, i) => { return i < sizes.length - 1 ? ` (max-width: ${v}px) ${v}px` : ` ${v}px` }) .join() } // console.log(generateSizes(contentMaxWidthInPixel)) // console.log(generateSizes()) export enum Sizes { main = '(max-width: 320px) 320px, (max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 750px) 750px, (max-width: 828px) 828px, 960px', full = '(max-width: 320px) 320px, (max-width: 480px) 480px, (max-width: 640px) 640px, (max-width: 750px) 750px, (max-width: 828px) 828px, (max-width: 960px) 960px, (max-width: 1080px) 1080px, (max-width: 1200px) 1200px, (max-width: 1440px) 1440px, (max-width: 1920px) 1920px, (max-width: 2048px) 2048px, (max-width: 2560px) 2560px, 3840px' } -
TheThirdRace revised this gist
Nov 28, 2020 . No changes.There are no files selected for viewing
-
TheThirdRace revised this gist
Nov 28, 2020 . No changes.There are no files selected for viewing
-
TheThirdRace revised this gist
Nov 28, 2020 . No changes.There are no files selected for viewing
-
TheThirdRace revised this gist
Nov 28, 2020 . No changes.There are no files selected for viewing
-
TheThirdRace created this gist
Nov 28, 2020 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,98 @@ import { chakra, ThemingProps, useStyleConfig } from '@chakra-ui/react' import NextImage, { ImageProps as NextImageProps } from 'next/image' import { ReactElement } from 'react' /** * ? Because NextJs typing is preventing auto-suggest for layout, width and height * ? we declare the styles differently in this component and will manage the switch * ? to NextJs typings when calling NextJs Image component */ type LayoutValue = 'fixed' | 'intrinsic' | 'responsive' | undefined type LayoutAndSize = | { layout: 'fill' } | { layout: LayoutValue height: number width: number } /** * Types for the Image component * Picking only the props I want to allow, you can adjust to your liking */ type ImageProps = Pick< NextImageProps, 'className' | 'loading' | 'objectFit' | 'objectPosition' | 'priority' | 'quality' | 'src' | 'unoptimized' > & Pick<Required<NextImageProps>, 'alt'> & Pick<ThemingProps, 'variant'> & { dimensions?: [number, number] layout?: 'fill' | LayoutValue } /** * Wrap NextJs Image component in Chakra's factory function * This is what will allow to use the theme and the styling properties on the component */ const ImageWithChakra = chakra( ({ className, dimensions = [0, 0], layout = 'fill', loading, objectFit, objectPosition, priority, quality, src, unoptimized, ...nextjsInternals }: ImageProps): ReactElement => { /** * As explained earlier, NextJs typing is preventing auto-suggest for layout, width and height * Here we actual convert our component typing to NextJs typing */ const [width, height] = dimensions const layoutAndSize: LayoutAndSize = height > 0 || width > 0 ? { height, layout: layout === 'fill' ? 'intrinsic' : layout, width } : { layout: 'fill' } /** * The actual NextImage component */ return ( <NextImage className={className} loading={loading} objectFit={objectFit} objectPosition={objectPosition} priority={priority} quality={quality} src={src} unoptimized={unoptimized} {...layoutAndSize} {...nextjsInternals} /> ) } ) export const Image = ({ variant, ...props }: ImageProps): ReactElement => { /** * This components serves as an interface to pass Chakra's styles * You can use the theme and/or styling properties (eg. backgroundColor='red.200') */ const styles = useStyleConfig('Image', { variant }) return <ImageWithChakra sx={styles} {...props} /> }