feat: use Next.js Image component
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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 }
|
||||
@ -1,3 +1,7 @@
|
||||
module.exports = {
|
||||
poweredByHeader: false,
|
||||
images: {
|
||||
deviceSizes: [375, 750, 1125],
|
||||
imageSizes: [56, 112, 185, 370, 370, 375, 540, 740, 750, 1080],
|
||||
},
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
38
yarn.lock
@ -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"
|
||||
|
||||