feat: use Next.js Image component

This commit is contained in:
Rui Saraiva 2021-12-04 23:43:26 +00:00
parent ad824518d8
commit f01116e55c
No known key found for this signature in database
GPG Key ID: 63937B371A665CD0
22 changed files with 48 additions and 194 deletions

View File

@ -1,10 +1,10 @@
import dynamic from 'next/dynamic'
import Image from 'next/image'
import React, { useState, useRef } from 'react'
import classnames from 'classnames'
import { useDrag } from 'react-use-gesture'
import { Typography } from 'components/typography'
import { ToolTitle } from 'components/tool-title'
import { LazyImage } from 'components/lazy-image'
import { SvgTwitter } from 'components/svgs/svg-twitter'
import { SvgGithub } from 'components/svgs/svg-github'
@ -13,6 +13,10 @@ import { SvgFavycon } from 'components/svgs/svg-favycon'
import { Button } from 'components/button'
import { isTouchCapable } from 'utils/device'
import augustoLopes from '../../public/images/people/augusto-lopes.png'
import ruiSaraiva from '../../public/images/people/rui-saraiva.png'
import miguelTeixeira from '../../public/images/people/miguel-teixeira.png'
const Modal = dynamic(() => import('react-modal'))
const people = [
@ -21,21 +25,21 @@ const people = [
name: 'Augusto Lopes',
role: 'Product Designer',
social: 'twitter',
placeholderHash: 'UrLqFOIUS$-o_Nt6NGRkEkt7M{RjM{NHMxof',
photo: augustoLopes,
},
{
screenName: 'ruisaraiva19',
name: 'Rui Saraiva',
role: 'Full-Stack Developer',
social: 'twitter',
placeholderHash: 'UNMQLqof_LWU?FRkkqt605fk9cjZbaWBt8of',
photo: ruiSaraiva,
},
{
screenName: 'miguellteixeira',
name: 'Miguel Teixeira',
role: 'Full-Stack Developer',
social: 'github',
placeholderHash: 'UcI~*]o0uPXS?wWAMxog8_kCQ,e-tmbIVsjF',
photo: miguelTeixeira,
},
]
@ -141,13 +145,13 @@ const FavyconInfo = ({
{people.map((person) => (
<div key={person.screenName} className={styles.person}>
<div className={styles.personAvatar}>
<LazyImage
src={`/images/people/${person.screenName}@1x.png`}
srcRetina={`/images/people/${person.screenName}@2x.png`}
<Image
src={person.photo}
alt={person.name}
aspectRatio="56/56"
placeholderHash={person.placeholderHash}
rounded
width={56}
height={56}
placeholder="blur"
layout="intrinsic"
/>
</div>
<div>

View File

@ -52,12 +52,18 @@
}
.mobileBackground {
position: relative;
width: 100%;
height: 100vh;
@include breakpoint-md-up {
display: none;
}
}
.desktopBackground {
position: relative;
@include breakpoint-md {
display: none;
}

View File

@ -1,9 +1,13 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { LazyImage } from 'components/lazy-image'
import Image from 'next/image'
import styles from './index.module.scss'
import unsplashImageMobile from '../../public/images/unsplash-vertical.jpg'
import unsplashImageDesktop from '../../public/images/unsplash-horizontal.jpg'
import dndLight from '../../public/images/dnd-light.png'
import dndDark from '../../public/images/dnd-dark.png'
type FavyconWizardProps = {
children: PropTypes.ReactNodeLike
@ -11,32 +15,36 @@ type FavyconWizardProps = {
}
const unsplashImageProps = (isMobile: boolean) => ({
src: `/images/unsplash${isMobile ? '-vertical' : ''}@1x.jpg`,
srcRetina: `/images/unsplash${isMobile ? '-vertical' : ''}@2x.jpg`,
placeholderHash: isMobile ? 'UT0Lxlh2ghgMeSeoe@fkflf5e.e:e.e.f6fk' : 'Un0V-,h2g#gMe,f8f9fif8f6f6f8f6f7fQfQ',
alt: 'Unsplash',
aspectRatio: isMobile ? '614/768' : '540/354',
stretch: isMobile,
src: isMobile ? unsplashImageMobile : unsplashImageDesktop,
width: isMobile ? undefined : 540,
height: isMobile ? undefined : 354,
})
const dndImageProps = (isDark: boolean) => ({
src: `/images/dnd-${isDark ? 'dark' : 'light'}@1x.png`,
srcRetina: `/images/dnd-${isDark ? 'dark' : 'light'}@2x.png`,
alt: 'Drag and drop here!',
aspectRatio: '185/109',
src: isDark ? dndDark : dndLight,
width: 185,
height: 109,
})
const FavyconWizardComponent = ({ children, showDndImage }: FavyconWizardProps) => {
return (
<div className={styles.root}>
<div className={styles.background}>
<LazyImage className={styles.mobileBackground} {...unsplashImageProps(true)} />
<LazyImage className={styles.desktopBackground} {...unsplashImageProps(false)} />
<div className={styles.mobileBackground}>
<Image alt="Unsplash image" placeholder="blur" layout="fill" {...unsplashImageProps(true)} />
</div>
<div className={styles.desktopBackground}>
<Image alt="Unsplash image" placeholder="blur" layout="intrinsic" {...unsplashImageProps(false)} />
</div>
</div>
{children}
<div className={classnames(styles.image, { [styles.hide]: !showDndImage })}>
<LazyImage {...dndImageProps(false)} className={styles.imageLight} />
<LazyImage {...dndImageProps(true)} className={styles.imageDark} />
<div className={styles.imageLight}>
<Image alt="Drag and drop here!" {...dndImageProps(false)} layout="intrinsic" />
</div>
<div className={styles.imageDark}>
<Image alt="Drag and drop here!" {...dndImageProps(true)} layout="intrinsic" />
</div>
</div>
</div>
)

View File

@ -1,52 +0,0 @@
@import '../../styles/variables.scss';
.root {
position: relative;
width: 100%;
&.stretch {
height: 100%;
padding-bottom: 0 !important;
}
&.rounded {
border-radius: 50%;
}
canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
&.rounded canvas {
border-radius: 50%;
}
}
.image {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
font-family: 'object-fit: cover; object-position: center;', sans-serif;
object-fit: cover;
object-position: center;
}
.placeholder {
composes: image;
transition: opacity 0.2s linear 0.2s;
}
.normal {
composes: image;
transition: opacity 0.2s linear;
}

View File

@ -1,76 +0,0 @@
/* eslint-disable @next/next/no-img-element */
import React, { useRef, useEffect } from 'react'
import { LazyImageFull, ImageState } from 'react-lazy-images'
import objectFitImages from 'object-fit-images'
import { BlurhashCanvas } from 'react-blurhash'
import classNames from 'classnames'
import styles from './index.module.scss'
type LazyImageProps = {
src: string
srcRetina?: string
placeholderHash?: string
alt: string
aspectRatio: string
stretch?: boolean
rounded?: boolean
} & React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
const LazyImage = ({
src,
srcRetina = src,
placeholderHash,
alt,
aspectRatio,
stretch = false,
rounded = false,
...props
}: LazyImageProps) => {
const [widthString, heightString] = aspectRatio.split('/')
const width = parseInt(widthString)
const height = parseInt(heightString)
const imgRef = useRef<HTMLImageElement>(null)
useEffect(() => {
if (imgRef.current) {
objectFitImages(imgRef.current)
}
}, [imgRef])
return (
<LazyImageFull src={src} srcSet={`${src} 1x, ${srcRetina} 2x`} alt={alt}>
{({ imageProps, imageState, ref }) => {
const loaded = imageState === ImageState.LoadSuccess
return (
<div
className={classNames(styles.root, { [styles.stretch]: stretch, [styles.rounded]: rounded })}
ref={ref}
style={{ paddingBottom: `${(height / width) * 100}%` }}
{...props}>
{placeholderHash ? (
<BlurhashCanvas
className={styles.placeholder}
hash={placeholderHash}
width={32}
height={32}
style={{ opacity: loaded ? 0 : 1 }}
/>
) : null}
<img
ref={imgRef}
className={styles.normal}
{...imageProps}
alt={imageProps.alt}
style={{ opacity: loaded ? 1 : 0 }}
loading="lazy"
/>
</div>
)
}}
</LazyImageFull>
)
}
export { LazyImage }

View File

@ -1,3 +1,7 @@
module.exports = {
poweredByHeader: false,
images: {
deviceSizes: [375, 750, 1125],
imageSizes: [56, 112, 185, 370, 370, 375, 540, 740, 750, 1080],
},
}

View File

@ -49,15 +49,12 @@
"multer": "1.4.3",
"next": "12.0.6",
"nprogress": "0.2.0",
"object-fit-images": "3.2.4",
"prismjs": "1.25.0",
"prop-types": "15.7.2",
"react": "17.0.2",
"react-blurhash": "0.1.3",
"react-clipboard.js": "2.0.16",
"react-dom": "17.0.2",
"react-dropzone": "11.4.2",
"react-lazy-images": "1.1.0",
"react-modal": "3.14.4",
"react-transition-group": "4.4.2",
"react-use": "17.3.1",
@ -88,7 +85,6 @@
"@types/multer": "1.4.7",
"@types/node": "16.11.11",
"@types/nprogress": "0.2.0",
"@types/object-fit-images": "3.2.2",
"@types/prismjs": "1.16.6",
"@types/react": "17.0.37",
"@types/react-modal": "3.13.1",

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1273,7 +1273,7 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
version "7.10.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==
@ -3617,11 +3617,6 @@
resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f"
integrity sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==
"@types/object-fit-images@3.2.2":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@types/object-fit-images/-/object-fit-images-3.2.2.tgz#b2874e5408a4f31b2834b5425456ccd04d280988"
integrity sha512-49ZQlRQqU8sojbAUW7mlh9zSOnCectxxeq8VXmDpuUy3oVhe49OIkuxm0XLXdoc04uiqguYJ11/nf7nXmkOY/A==
"@types/overlayscrollbars@^1.12.0":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@types/overlayscrollbars/-/overlayscrollbars-1.12.1.tgz#fb637071b545834fb12aea94ee309a2ff4cdc0a8"
@ -12497,11 +12492,6 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-fit-images@3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/object-fit-images/-/object-fit-images-3.2.4.tgz#6c299d38fdf207746e5d2d46c2877f6f25d15b52"
integrity sha512-G+7LzpYfTfqUyrZlfrou/PLLLAPNC52FTy5y1CBywX+1/FkxIloOyQXBmZ3Zxa2AWO+lMF0JTuvqbr7G5e5CWg==
object-inspect@^1.10.3, object-inspect@^1.11.0, object-inspect@^1.9.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
@ -14048,11 +14038,6 @@ rc@^1.2.7, rc@^1.2.8:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-blurhash@0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/react-blurhash/-/react-blurhash-0.1.3.tgz#735f28f8f07fb358d7efe7e7e6dc65a7272bf89e"
integrity sha512-Q9lqbXg92NU6/2DoIl/cBM8YWL+Z4X66OiG4aT9ozOgjBwx104LHFCH5stf6aF+s0Q9Wf310Ul+dG+VXJltmPg==
react-clipboard.js@2.0.16:
version "2.0.16"
resolved "https://registry.yarnpkg.com/react-clipboard.js/-/react-clipboard.js-2.0.16.tgz#45a60684dd6a36ff97e40c53069a27e97a4b6c9c"
@ -14181,14 +14166,6 @@ react-inspector@^5.1.0:
is-dom "^1.0.0"
prop-types "^15.0.0"
react-intersection-observer@^6.1.0:
version "6.4.2"
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-6.4.2.tgz#a061add707c37ea14e1308c77c2e286719347928"
integrity sha512-gL6YrkhniA0tIbyDbUterzBwKh61vHR520rsKULel5T37gG4YP07wnWI3WoqOcKK5bKAu0PZB2FHD7/OjawN+w==
dependencies:
"@babel/runtime" "^7.2.0"
invariant "^2.2.4"
react-is@17.0.2, react-is@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
@ -14199,14 +14176,6 @@ react-is@^16.7.0, react-is@^16.8.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-lazy-images@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-lazy-images/-/react-lazy-images-1.1.0.tgz#c865445c96e568a6249db03a2bb2dccd49cb6f50"
integrity sha512-h5DHFhkMJyh2qsDl3hXWu6d+On10FsgHtRJ+BH7xjgsFOvsqaii9CEwEESqPJrrAiHo1qrN1LgzrV8X3zctHKA==
dependencies:
react-intersection-observer "^6.1.0"
unionize "^2.1.2"
react-lifecycles-compat@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
@ -16950,11 +16919,6 @@ union-value@^1.0.0:
is-extendable "^0.1.1"
set-value "^2.0.1"
unionize@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/unionize/-/unionize-2.2.0.tgz#ce88635aa0793f28ab617abeac36172ba0aeb7bc"
integrity sha512-lHXiL6LPVuRYBGCLOdUd4GMHoAGqM0HtYHAZcA6pUEiwN1nk+LEYlh8bud7saeL0bkFntJzCPEPVVJeFm3Cqsg==
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"