Add Fadable component

This commit is contained in:
Tom Raithel
2017-02-25 23:34:25 +01:00
parent 5e57c9caae
commit 5f20c00bec
9 changed files with 163 additions and 46 deletions

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import actions from '../actions'; import actions from '../actions';
@@ -13,7 +14,7 @@ function App(props) {
<div className="page__header"> <div className="page__header">
<Header {...props} /> <Header {...props} />
</div> </div>
<div className="page__content"> <div className={classNames('page__content', { 'is-faded': props.isFaded })}>
<Router {...props} /> <Router {...props} />
</div> </div>
<div className="page__footer"> <div className="page__footer">

45
js/components/Fadeable.js Normal file
View File

@@ -0,0 +1,45 @@
import React from 'react';
import classNames from 'classnames';
class Fadeable extends React.Component {
constructor(props) {
super(props);
this.state = {
faded: props.leaving,
};
}
componentWillReceiveProps({ leaving }) {
if (!this.props.leaving && leaving) {
this.setState({
...this.state,
faded: true,
});
}
if (this.props.leaving && !leaving) {
this.setState({
...this.state,
faded: false,
});
}
}
handleTransitionEnd = () => {
if (this.state.faded) {
this.props.onLeave();
}
};
render() {
return (
<div
className={classNames('fadable', { 'is-faded': this.state.faded })}
onTransitionEnd={this.handleTransitionEnd}
>
{this.props.children}
</div>
);
}
}
export default Fadeable;

View File

@@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import HeroHeadline from './HeroHeadline'; import HeroHeadline from './HeroHeadline';
import Fadeable from './Fadeable';
export default function PageHelp() { export default function PageHelp({ leaving, onLeave }) {
return ( return (
<div> <Fadeable leaving={leaving} onLeave={onLeave}>
<HeroHeadline>How to use AOE Technology Radar</HeroHeadline> <HeroHeadline>How to use AOE Technology Radar</HeroHeadline>
</div> </Fadeable>
); );
} }

View File

@@ -1,14 +1,15 @@
import React from 'react'; import React from 'react';
import HeroHeadline from './HeroHeadline'; import HeroHeadline from './HeroHeadline';
import QuadrantGrid from './QuadrantGrid'; import QuadrantGrid from './QuadrantGrid';
import Fadeable from './Fadeable';
export default function PageIndex({ items, navigate }) { export default function PageIndex({ leaving, onLeave, items, navigate }) {
return ( return (
<div> <Fadeable leaving={leaving} onLeave={onLeave}>
<div className="headline-group"> <div className="headline-group">
<HeroHeadline alt="Mar 2017">AOE Technology Radar</HeroHeadline> <HeroHeadline alt="Mar 2017">AOE Technology Radar</HeroHeadline>
</div> </div>
<QuadrantGrid items={items} /> <QuadrantGrid items={items} />
</div> </Fadeable>
); );
} }

View File

@@ -3,14 +3,17 @@ import HeroHeadline from './HeroHeadline';
import Badge from './Badge'; import Badge from './Badge';
import ItemList from './ItemList'; import ItemList from './ItemList';
import Link from './Link'; import Link from './Link';
import Fadeable from './Fadeable';
import { groupByQuadrants } from '../../common/model'; import { groupByQuadrants } from '../../common/model';
export default function PageItems({ pageName, items }) { export default function PageItems({ leaving, onLeave, pageName, items }) {
const [quadrantName, itemName] = pageName.split('/'); const [quadrantName, itemName] = pageName.split('/');
const item = items.filter(item => item.quadrant === quadrantName && item.name === itemName)[0]; const item = items.filter(item => item.quadrant === quadrantName && item.name === itemName)[0];
const itemsInRing = groupByQuadrants(items)[item.quadrant][item.ring]; const itemsInRing = groupByQuadrants(items)[item.quadrant][item.ring];
return ( return (
<Fadeable leaving={leaving} onLeave={onLeave}>
<div className="item-page"> <div className="item-page">
<div className="item-page__nav"> <div className="item-page__nav">
<div className="item-page__nav__inner"> <div className="item-page__nav__inner">
@@ -47,5 +50,6 @@ export default function PageItems({ pageName, items }) {
</div> </div>
</div> </div>
</div> </div>
</Fadeable>
); );
} }

View File

@@ -4,6 +4,7 @@ import HeadlineGroup from './HeadlineGroup';
import HeroHeadline from './HeroHeadline'; import HeroHeadline from './HeroHeadline';
import Badge from './Badge'; import Badge from './Badge';
import Link from './Link'; import Link from './Link';
import Fadeable from './Fadeable';
import { groupByFirstLetter } from '../../common/model'; import { groupByFirstLetter } from '../../common/model';
import { translate } from '../../common/config'; import { translate } from '../../common/config';
@@ -45,7 +46,7 @@ class PageOverview extends React.Component {
const groups = this.getFilteredAndGroupedItems(); const groups = this.getFilteredAndGroupedItems();
return ( return (
<div> <Fadeable leaving={this.props.leaving} onLeave={this.props.onLeave}>
<HeadlineGroup> <HeadlineGroup>
<HeroHeadline>Technologies Overview</HeroHeadline> <HeroHeadline>Technologies Overview</HeroHeadline>
</HeadlineGroup> </HeadlineGroup>
@@ -106,7 +107,7 @@ class PageOverview extends React.Component {
} }
</div> </div>
</div> </Fadeable>
); );
} }
} }

View File

@@ -2,17 +2,19 @@ import React from 'react';
import HeroHeadline from './HeroHeadline'; import HeroHeadline from './HeroHeadline';
import HeadlineGroup from './HeadlineGroup'; import HeadlineGroup from './HeadlineGroup';
import QuadrantSection from './QuadrantSection'; import QuadrantSection from './QuadrantSection';
import Fadeable from './Fadeable';
import { translate } from '../../common/config'; import { translate } from '../../common/config';
import { groupByQuadrants } from '../../common/model'; import { groupByQuadrants } from '../../common/model';
export default function PageQuadrant({ pageName, items }) { export default function PageQuadrant({ leaving, onLeave, pageName, items }) {
const groups = groupByQuadrants(items); const groups = groupByQuadrants(items);
return ( return (
<div> <Fadeable leaving={leaving} onLeave={onLeave}>
<HeadlineGroup> <HeadlineGroup>
<HeroHeadline>{translate(pageName)}</HeroHeadline> <HeroHeadline>{translate(pageName)}</HeroHeadline>
</HeadlineGroup> </HeadlineGroup>
<QuadrantSection groups={groups} quadrantName={pageName} big /> <QuadrantSection groups={groups} quadrantName={pageName} big />
</div> </Fadeable>
); );
} }

View File

@@ -27,7 +27,46 @@ const getPageByName = (items, pageName) => {
return 'div'; return 'div';
} }
export default function Router({ pageName, ...props}) { class Router extends React.Component {
const Comp = getPageByName(props.items, pageName); constructor(props) {
return <Comp {...props} pageName={pageName} />; super(props);
this.state = {
pageName: props.pageName,
leaving: false,
};
}
componentWillReceiveProps({ pageName }) {
this.setState({
...this.state,
nextPageName: pageName,
leaving: true,
});
}
handlePageLeave = () => {
this.setState({
...this.state,
pageName: this.state.nextPageName,
leaving: true,
nextPageName: null,
});
window.setTimeout(() => {
window.requestAnimationFrame(() => {
this.setState({
...this.state,
leaving: false,
});
});
}, 0);
};
render() {
const { pageName, leaving } = this.state;
const Comp = getPageByName(this.props.items, pageName);
return <Comp {...this.props} pageName={pageName} leaving={leaving} onLeave={this.handlePageLeave} />;
}
} }
export default Router;

View File

@@ -0,0 +1,23 @@
.fadable {
position: relative;
&::after {
transition: opacity 0.2s cubic-bezier(0.54, 0, 0.28, 1);
content: '';
display: block;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0;
background: var(--color-gray-dark);
pointer-events: none;
}
&.is-faded {
&::after {
opacity: 1;
}
}
}