Skip to content

Commit

Permalink
Merge branch 'canary' into patch-4
Browse files Browse the repository at this point in the history
  • Loading branch information
Timer authored Oct 30, 2019
2 parents 319ee0f + 61a9cfb commit c12d78b
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 0 deletions.
42 changes: 42 additions & 0 deletions examples/with-framer-motion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# framer-motion example

## How to use

### Using `create-next-app`

Execute [`create-next-app`](https://github.com/segmentio/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example:

```bash
npx create-next-app --example with-framer-motion with-framer-motion
# or
yarn create next-app --example with-framer-motion with-framer-motion
```

### Download manually

Download the example:

```bash
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-framer-motion
cd with-framer-motion
```

Install it and run:

```bash
npm install
npm run build
npm start
```

Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))

```bash
now
```

## The idea behind the example

Framer [`Motion`](https://github.com/framer/motion) is a production-ready animation library. By using a custom [`<App>`](https://nextjs.org/docs#custom-app) along with Motion's [`AnimatePresence`](https://www.framer.com/api/motion/animate-presence/) component, transitions between Next pages becomes simple and declarative.

When using Next's `<Link>` component, you will likely want to [disable the default scroll behavior](https://nextjs.org/docs#disabling-the-scroll-changes-to-top-on-page) for a more seamless navigation experience. Scrolling to the top of a page can be re-enabled by adding a `onExitComplete` callback on the `AnimatePresence` component.
146 changes: 146 additions & 0 deletions examples/with-framer-motion/components/Gallery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import * as React from 'react'
import Link from 'next/link'

import { motion } from 'framer-motion'
import { images } from '../constants'

const transition = { duration: 0.5, ease: [0.43, 0.13, 0.23, 0.96] }

const thumbnailVariants = {
initial: { scale: 0.9, opacity: 0 },
enter: { scale: 1, opacity: 1, transition },
exit: {
scale: 0.5,
opacity: 0,
transition: { duration: 1.5, ...transition }
}
}

const frameVariants = {
hover: { scale: 0.95 }
}

const imageVariants = {
hover: { scale: 1.1 }
}

const Thumbnail = ({ id, i }) => (
<>
<motion.div className='thumbnail' variants={thumbnailVariants}>
<motion.div
className='frame'
whileHover='hover'
variants={frameVariants}
transition={transition}
>
<Link href='/image/[id]' as={`/image/${i}`} scroll={false}>
<motion.img
src={`https://static1.squarespace.com/static/5b475b2c50a54f54f9b4e1dc/t/${id}.jpg?format=1500w`}
alt='The Barbican'
variants={imageVariants}
transition={transition}
/>
</Link>
</motion.div>
</motion.div>
<style>
{`
.thumbnail {
flex: 1 0 33%;
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.frame {
overflow: hidden;
}
.thumbnail img {
width: 100%;
height: 100%;
}
`}
</style>
</>
)

const Gallery = () => (
<>
<h1>Barbican</h1>
<div className='gallery'>
<motion.div
className='thumbnails'
initial='initial'
animate='enter'
exit='exit'
variants={{ exit: { transition: { staggerChildren: 0.1 } } }}
>
{images.map((id, i) => (
<Thumbnail key={id} id={id} i={i} />
))}
</motion.div>
</div>
<style>
{`
h1 {
font-size: 100px;
text-align: center;
position: fixed;
bottom: -100px;
z-index: 1;
color: #f9fbf8;
left: 50%;
transform: translateX(-50%);
pointer-events: none;
}
.gallery {
padding: 40px;
margin: 0 auto;
width: 100%;
max-width: 1200px;
position: relative;
}
.thumbnails {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
}
@media screen and (min-width: 600px) {
h1 {
font-size: 140px;
bottom: -130px;
}
}
@media screen and (min-width: 800px) {
h1 {
font-size: 180px;
bottom: -170px;
}
}
@media screen and (min-width: 1000px) {
h1 {
font-size: 220px;
bottom: -200px;
}
}
@media screen and (min-width: 1200px) {
h1 {
font-size: 280px;
bottom: -260px;
}
}
`}
</style>
</>
)

export default Gallery
70 changes: 70 additions & 0 deletions examples/with-framer-motion/components/SingleImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from 'react'
import Link from 'next/link'

import { motion } from 'framer-motion'
import { images } from '../constants'

const transition = {
duration: 1,
ease: [0.43, 0.13, 0.23, 0.96]
}

const imageVariants = {
exit: { y: '50%', opacity: 0, transition },
enter: {
y: '0%',
opacity: 1,
transition
}
}

const backVariants = {
exit: { x: 100, opacity: 0, transition },
enter: { x: 0, opacity: 1, transition: { delay: 1, ...transition } }
}

const SingleImage = ({ id }) => (
<>
<motion.div className='single' initial='exit' animate='enter' exit='exit'>
<motion.img
variants={imageVariants}
src={`https://static1.squarespace.com/static/5b475b2c50a54f54f9b4e1dc/t/${
images[id]
}.jpg?format=1500w`}
alt='The Barbican'
/>
<motion.div className='back' variants={backVariants}>
<Link href='/'>
<a>← Back</a>
</Link>
</motion.div>
</motion.div>
<style>
{`
.single {
overflow: hidden;
height: 100vh;
}
.single img {
max-width: 100%;
max-height: 100vh;
}
.back {
position: fixed;
top: 50px;
right: 50px;
font-size: 54px;
z-index: 1;
}
.back a {
text-decoration: none;
}
`}
</style>
</>
)

export default SingleImage
8 changes: 8 additions & 0 deletions examples/with-framer-motion/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const images = [
'5b5a3938562fa764113169a6/1532639559620/DSCF3338',
'5b5a3628f950b7390fbfc5f8/1532639027872/DSCF3246',
'5b5a3741575d1fccb5ac6b3f/1532639066455/DSCF3268',
'5b5a376b0e2e728eeeaca8e4/1532683586969/DSCF3274',
'5b5c228403ce64f3c80d4d8e/1532764845121/DSCF3348',
'5b5a3b800e2e728eeead9575/1532640158813/DSCF3375'
]
16 changes: 16 additions & 0 deletions examples/with-framer-motion/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "with-framer-motion",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"framer-motion": "latest",
"next": "latest",
"react": "16.11.0",
"react-dom": "16.11.0"
},
"license": "ISC"
}
49 changes: 49 additions & 0 deletions examples/with-framer-motion/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import App, { Container } from 'next/app'
import { AnimatePresence } from 'framer-motion'

export default class MyApp extends App {
/**
* Handle scrolling gracefully, since next/router scrolls to top
* before exit animation is complete.
*
* Note that next/link components should also be using `scroll={false}`
**/
handleExitComplete () {
if (typeof window !== 'undefined') {
window.scrollTo({ top: 0 })
}
}

render () {
const { Component, pageProps, router } = this.props
return (
<>
<Container>
<AnimatePresence
exitBeforeEnter
onExitComplete={this.handleExitComplete}
>
<Component {...pageProps} key={router.route} />
</AnimatePresence>
</Container>
<style>
{`
body {
padding: 0;
margin: 0;
background: #f9fbf8;
}
* {
box-sizing: border-box;
font-family: Helvetica, sans-serif;
font-weight: 900;
color: #222;
}
`}
</style>
</>
)
}
}
15 changes: 15 additions & 0 deletions examples/with-framer-motion/pages/image/[id].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as React from 'react'
import SingleImage from '../../components/SingleImage'

const Page = ({ id }) => {
return <SingleImage id={id} />
}

Page.getInitialProps = ({ query }) => {
const id = Number.parseInt(query.id, 10)
return {
id
}
}

export default Page
6 changes: 6 additions & 0 deletions examples/with-framer-motion/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
import Gallery from '../components/Gallery'

const Index = () => <Gallery />

export default Index

0 comments on commit c12d78b

Please sign in to comment.