new hero animation using bodymovin and lottie

This commit is contained in:
August Skare
2018-11-07 09:48:10 +01:00
parent 2dfca078fd
commit 3a23e795ac
25 changed files with 261 additions and 46 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 KiB

View File

@@ -23,6 +23,8 @@
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-helmet": "^5.2.0",
"react-loadable": "^5.5.0",
"react-lottie": "^1.2.3",
"react-tabs": "^2.3.0",
"styled-components": "^4.0.2",
"styled-normalize": "^8.0.1"
@@ -35,6 +37,8 @@
"@types/react": "^16.4.2",
"@types/react-dom": "^16.0.7",
"@types/react-helmet": "^5.0.6",
"@types/react-loadable": "^5.4.1",
"@types/react-lottie": "^1.2.0",
"@types/react-router-dom": "^4.0.4",
"@types/react-tabs": "^2.3.0",
"@types/react-tap-event-plugin": "0.0.30",

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Animation from '../index';
import * as animationData from './data.json';
function AnimationCompiler() {
return <Animation animationData={animationData} width={2150} height={700} />;
}
export default AnimationCompiler;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Animation from '../index';
import * as animationData from './data.json';
function AnimationCov() {
return <Animation animationData={animationData} width={1981} height={660} />;
}
export default AnimationCov;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Animation from '../index';
import * as animationData from './data.json';
function AnimationProfiler() {
return <Animation animationData={animationData} width={1985} height={657} />;
}
export default AnimationProfiler;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Animation from '../index';
import * as animationData from './data.json';
function AnimationTrace() {
return <Animation animationData={animationData} width={2241} height={610} />;
}
export default AnimationTrace;

View File

@@ -0,0 +1,105 @@
import * as React from 'react';
import Lottie from 'react-lottie';
import styled from 'styled-components';
import { media } from 'ts/variables';
interface AnimationProps {
animationData: object;
width: number;
height: number;
}
interface AnimationState {
width?: number;
height?: number;
}
class Animation extends React.PureComponent<AnimationProps, AnimationState> {
timeout = null as any;
constructor(props: AnimationProps) {
super(props);
this.state = {
height: undefined,
width: undefined,
};
this.handleResize = this.handleResize.bind(this);
this.updateAnimationSize = this.updateAnimationSize.bind(this);
}
componentDidMount() {
this.updateAnimationSize();
window.addEventListener('resize', this.handleResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}
handleResize() {
clearTimeout(this.timeout);
this.timeout = setTimeout(this.updateAnimationSize, 200);
}
updateAnimationSize() {
const windowWidth = window.innerWidth;
let width = undefined;
let height = undefined;
if (windowWidth < 1200) {
const maxWidth = windowWidth + 250;
const ratio = maxWidth / this.props.width;
height = Math.round(this.props.height * ratio);
width = Math.round(this.props.width * ratio);
}
this.setState({ width, height });
}
render() {
let { animationData } = this.props;
const height = this.state.height || this.props.height;
const width = this.state.width || this.props.width;
return (
<Container height={height}>
<InnerContainer>
<Lottie
width={width}
height={height}
options={{
loop: true,
autoplay: true,
animationData: animationData,
}}
/>
</InnerContainer>
</Container>
);
}
}
const Container = styled.div`
width: 100%;
height: ${(props: { height: number }) => props.height}px;
position: absolute;
top: 40%;
left: 0;
z-index: -1;
overflow: hidden;
${media.medium`
top: auto;
bottom: -3rem;
`};
`;
const InnerContainer = styled.div`
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
`;
export default Animation;

View File

@@ -3,7 +3,6 @@ import * as React from 'react';
import ThemeContext from 'ts/context';
import GlobalStyles from 'ts/globalStyles';
import Header from 'ts/components/Header';
import Hero from 'ts/components/Hero';
import Footer from 'ts/components/Footer';
interface BaseProps {
@@ -16,7 +15,6 @@ function Base(props: BaseProps) {
<ThemeContext.Provider value={props.context}>
<GlobalStyles />
<Header />
<Hero />
{props.children}
<Footer />
</ThemeContext.Provider>

View File

@@ -6,8 +6,12 @@ import { withContext, Props } from './withContext';
import Button from './Button';
import { Beta } from './Typography';
function Hero(props: Props) {
const { subtitle, tagline, title } = props;
interface HeroProps extends Props {
children: React.ReactNode;
}
function Hero(props: HeroProps) {
const { subtitle, tagline } = props;
return (
<React.Fragment>
@@ -19,13 +23,7 @@ function Hero(props: Props) {
Read the Docs
</Button>
</HeroContainer>
<ImageContainer>
<Image
src={`/images/${title}@1x.gif`}
srcSet={`/images/${title}@1x.gif, /images/${title}@2x.gif 2x`}
/>
</ImageContainer>
{navigator.userAgent !== 'ReactSnap' ? props.children : null}
</StyledHero>
</React.Fragment>
);
@@ -67,39 +65,4 @@ const Tagline = styled(Beta)`
`};
`;
const ImageContainer = styled.div`
width: 100%;
height: 800px;
position: absolute;
top: 100%;
left: 0;
overflow: hidden;
transform: translateY(-50%);
z-index: -1;
${media.xlarge`
height: 533.333333334px;
transform: translateY(-60%);
`};
${media.small`
height: 400px;
transform: translateY(-70%);
`};
`;
const Image = styled.img`
width: min-content;
height: 100%;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
object-fit: contain;
${media.small`
height: 100%;
width: auto;
left: 0;
transform: translateX(-15%);
`};
`;
export default withContext(Hero);

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { render, hydrate } from 'react-dom';
import * as Loadable from 'react-loadable';
import { Lead } from 'ts/components/Typography';
import context from 'ts/context/compiler';
@@ -10,10 +11,20 @@ import Code from 'ts/components/Code';
import InlineCode from 'ts/components/InlineCode';
import CompilerComponent from 'ts/components/Compiler';
import Breakout from 'ts/components/Breakout';
import Hero from 'ts/components/Hero';
const Animation = Loadable({
loader: () => System.import(/* webpackChunkName: 'compiler-animation' */ 'ts/components/Animations/Compiler'),
loading: () => <div />,
delay: 1000,
});
function Compiler() {
return (
<Base context={context}>
<Hero>
<Animation />
</Hero>
<CompilerComponent />
<Content>
<ContentBlock main title="Get started" />

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { render, hydrate } from 'react-dom';
import * as Loadable from 'react-loadable';
import context from 'ts/context/cov';
import Base from 'ts/components/Base';
@@ -11,10 +12,20 @@ import InlineCode from 'ts/components/InlineCode';
import { List, ListItem } from 'ts/components/List';
import Breakout from 'ts/components/Breakout';
import { Intro, IntroLead, IntroAside } from 'ts/components/Intro';
import Hero from 'ts/components/Hero';
const Animation = Loadable({
loader: () => System.import(/* webpackChunkName: 'cov-animation' */ 'ts/components/Animations/Cov'),
loading: () => <div />,
delay: 1000,
});
function Cov() {
return (
<Base context={context}>
<Hero>
<Animation />
</Hero>
<Intro>
<IntroLead title="Measure your tests">
<p>

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { render, hydrate } from 'react-dom';
import * as Loadable from 'react-loadable';
import context from 'ts/context/profiler';
import Base from 'ts/components/Base';
@@ -11,10 +12,20 @@ import Code from 'ts/components/Code';
import InlineCode from 'ts/components/InlineCode';
import { List, ListItem } from 'ts/components/List';
import { Intro, IntroLead, IntroAside } from 'ts/components/Intro';
import Hero from 'ts/components/Hero';
const Animation = Loadable({
loader: () => System.import(/* webpackChunkName: 'profiler-animation' */ 'ts/components/Animations/Profiler'),
loading: () => <div />,
delay: 1000,
});
function Profiler() {
return (
<Base context={context}>
<Hero>
<Animation />
</Hero>
<Intro>
<IntroLead title="Outline gas usage">
<p>

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { render, hydrate } from 'react-dom';
import * as Loadable from 'react-loadable';
import context from 'ts/context/trace';
import Base from 'ts/components/Base';
@@ -11,10 +12,20 @@ import InlineCode from 'ts/components/InlineCode';
import { List, ListItem } from 'ts/components/List';
import TraceComponent from 'ts/components/Trace';
import Breakout from 'ts/components/Breakout';
import Hero from 'ts/components/Hero';
const Animation = Loadable({
loader: () => System.import(/* webpackChunkName: 'trace-animation' */ 'ts/components/Animations/Trace'),
loading: () => <div />,
delay: 1000,
});
function Trace() {
return (
<Base context={context}>
<Hero>
<Animation />
</Hero>
<TraceComponent />
<Content>
<ContentBlock main title="Get started" />

View File

@@ -1379,6 +1379,21 @@
dependencies:
"@types/react" "*"
"@types/react-loadable@^5.4.1":
version "5.4.1"
resolved "https://registry.yarnpkg.com/@types/react-loadable/-/react-loadable-5.4.1.tgz#bc76978c6d9039e5808797b5ee35f6ae18b7329f"
integrity sha512-nBvsWjPfBHepN5LoK/wgaunZSK9LmkKsPYum+/QrEKzUAb1yoe1/dwqTH6ZrinHDjru9LgjvXOqek9hvbq4Skw==
dependencies:
"@types/react" "*"
"@types/webpack" "*"
"@types/react-lottie@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/react-lottie/-/react-lottie-1.2.0.tgz#87eccca2580a18c95a3fbb9f421c85debafb95e4"
integrity sha512-3ZE0QxbHEpGeuKTTvnCchfgVt4xW7VMxzMd2PgVNOXwkO8qLrNggkXudsk3RJ92IQLFnYRfbACPD1/X7zIjDdQ==
dependencies:
"@types/react" "*"
"@types/react-redux@^4.4.37":
version "4.4.47"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-4.4.47.tgz#12af1677116e08d413fe2620d0a85560c8a0536e"
@@ -1518,11 +1533,23 @@
"@types/node" "*"
"@types/react" "*"
"@types/tapable@*":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==
"@types/tmp@^0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d"
integrity sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=
"@types/uglify-js@*":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
dependencies:
source-map "^0.6.1"
"@types/uuid@^3.4.2", "@types/uuid@^3.4.3":
version "3.4.3"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.3.tgz#121ace265f5569ce40f4f6d0ff78a338c732a754"
@@ -1542,6 +1569,16 @@
dependencies:
"@types/ethereum-protocol" "*"
"@types/webpack@*":
version "4.4.17"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.17.tgz#3da3e0823a051311ba510bdc32354888921fc8b4"
integrity sha512-f8fHYEhlrSQJ5BHaonyatL11MYwqQ7I6QDVCT41LqIyxR7j9B2uY4cQKxDoWFC9l2NbFGsIhiJBKZ6Y6LMBFLA==
dependencies:
"@types/node" "*"
"@types/tapable" "*"
"@types/uglify-js" "*"
source-map "^0.6.0"
"@types/websocket@^0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-0.0.39.tgz#aa971e24f9c1455fe2a57ee3e69c7d395016b12a"
@@ -11180,6 +11217,11 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
dependencies:
js-tokens "^3.0.0"
lottie-web@^5.1.3:
version "5.4.1"
resolved "https://registry.yarnpkg.com/lottie-web/-/lottie-web-5.4.1.tgz#98465741d4907293656cab31e395d79d0546ef26"
integrity sha512-pn5nCxobPVY9dcl+gh5s4q5k5MX6GeayUh4l7AhelDSTWkvyvGGK9dOMu6+FS0pseXjUyuZwzxtx2Tf796B0IQ==
loud-rejection@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
@@ -14431,6 +14473,21 @@ react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-loadable@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4"
integrity sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==
dependencies:
prop-types "^15.5.0"
react-lottie@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/react-lottie/-/react-lottie-1.2.3.tgz#8544b96939e088658072eea5e12d912cdaa3acc1"
integrity sha512-qLCERxUr8M+4mm1LU0Ruxw5Y5Fn/OmYkGfnA+JDM/dZb3oKwVAJCjwnjkj9TMHtzR2U6sMEUD3ZZ1RaHagM7kA==
dependencies:
babel-runtime "^6.26.0"
lottie-web "^5.1.3"
react-markdown@^3.2.2:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e"