fix animations
This commit is contained in:
@@ -1,3 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
export type Animations = {
|
||||
[k: string]: Animation[]
|
||||
}
|
||||
|
||||
export type AnimationStates = {
|
||||
[k: string]: React.CSSProperties[]
|
||||
}
|
||||
|
||||
type Animation = {
|
||||
stateA: React.CSSProperties
|
||||
stateB: React.CSSProperties
|
||||
@@ -6,48 +16,20 @@ type Animation = {
|
||||
prepare?(callback: (state: any) => any): any // todo fix
|
||||
}
|
||||
|
||||
type AnimationController = {}
|
||||
|
||||
type AnimationRunner = {
|
||||
getState(): any
|
||||
export type AnimationRunner = {
|
||||
getState(): AnimationStates
|
||||
run(): any
|
||||
awaitAnimationComplete(callback: () => void): any
|
||||
}
|
||||
|
||||
export const createAnimationController = (animations: {[k: string]: Animation}, component: any): AnimationController => {
|
||||
return {
|
||||
animations,
|
||||
start: () => {
|
||||
Object.entries(animations).map(([name, animation]) => animation.run && animation.run((state) => {
|
||||
component.setState({
|
||||
...component.state,
|
||||
[name]: state,
|
||||
});
|
||||
}));
|
||||
},
|
||||
prepare: () => {
|
||||
Object.entries(animations).map(([name, animation]) => animation.prepare && animation.prepare((state) => {
|
||||
component.setState({
|
||||
...component.state,
|
||||
[name]: state,
|
||||
});
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const createAnimation = (stateA: React.CSSProperties, stateB: React.CSSProperties, delay: number): Animation => ({
|
||||
stateA,
|
||||
stateB,
|
||||
delay,
|
||||
});
|
||||
|
||||
const getAnimationState = (animation: Animation | Animation[], stateName: 'stateA' | 'stateB' = 'stateA'): React.CSSProperties => {
|
||||
if (animation instanceof Array) {
|
||||
return animation.map(a => getAnimationState(a, stateName))[0]; // todo fix
|
||||
}
|
||||
|
||||
return animation[stateName];
|
||||
const getAnimationStates = (animations: Animation[], stateName: 'stateA' | 'stateB' = 'stateA'): React.CSSProperties[] => {
|
||||
return animations.map(animation => animation[stateName]);
|
||||
};
|
||||
|
||||
const getMaxTransitionTime = (transition: string) => {
|
||||
@@ -76,46 +58,40 @@ const getAnimationDuration = (animation: Animation | Animation[]): number => {
|
||||
return maxTransition + animation.delay;
|
||||
};
|
||||
|
||||
const getMaxAnimationsDuration = (animations: {[k: string]: Animation} | Animation[]) => (
|
||||
getAnimationDuration(Object.values(animations))
|
||||
const getMaxAnimationsDuration = (animations: Animations) => (
|
||||
Math.max(...Object.values(animations).map(animations => getAnimationDuration(Object.values(animations))))
|
||||
);
|
||||
|
||||
export const createAnimationRunner = (animations: {[k: string]: Animation} | Animation[], subscriber: () => void = () => {}):AnimationRunner => {
|
||||
export const createAnimationRunner = (animationsIn: { [k: string]: (Animation | Animation[]) }, subscriber: () => void = () => {
|
||||
}): AnimationRunner => {
|
||||
const animations = Object.entries(animationsIn).reduce((state, [name, animation]) => ({
|
||||
...state,
|
||||
[name]: animation instanceof Array ? animation : [animation] as Animation[],
|
||||
}), {} as Animations);
|
||||
|
||||
let state = Object.entries(animations).reduce((state, [name, animation]) => ({
|
||||
...state,
|
||||
[name]: getAnimationState(animation),
|
||||
}), {});
|
||||
[name]: getAnimationStates(animation),
|
||||
}), {} as AnimationStates);
|
||||
|
||||
const animationsDuration = getMaxAnimationsDuration(animations);
|
||||
|
||||
const animate = (name: string, animation: Animation) => {
|
||||
if (animation instanceof Array) {
|
||||
const animate = (name: string, animation: Animation[]) => {
|
||||
animation.forEach((a, index) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
window.setTimeout(() => {
|
||||
state = {
|
||||
...state,
|
||||
[name]: [
|
||||
// ...(state[name]?.slice(0, index)), // todo fix
|
||||
...(state[name]?.slice(0, index)),
|
||||
a.stateB,
|
||||
// ...(state[name]?.slice(index + 1, state[name].length)), // todo fix
|
||||
...(state[name]?.slice(index + 1, state[name].length)),
|
||||
],
|
||||
};
|
||||
subscriber();
|
||||
}, a.delay);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
window.requestAnimationFrame(() => {
|
||||
window.setTimeout(() => {
|
||||
state = {
|
||||
...state,
|
||||
[name]: animation.stateB,
|
||||
};
|
||||
subscriber();
|
||||
}, animation.delay);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,21 +5,23 @@ import Link from '../Link/Link';
|
||||
import FooterEnd from '../FooterEnd/FooterEnd';
|
||||
import SetTitle from '../SetTitle';
|
||||
import ItemRevisions from '../ItemRevisions/ItemRevisions';
|
||||
import { createAnimation, createAnimationRunner } from '../../animation';
|
||||
import {
|
||||
AnimationStates,
|
||||
createAnimation,
|
||||
createAnimationRunner
|
||||
} from '../../animation';
|
||||
import './item-page.scss';
|
||||
import {translate} from '../../config';
|
||||
import {groupByQuadrants, Item} from '../../model';
|
||||
|
||||
const getItem = (pageName: string, items: Item[]) => {
|
||||
const [quadrantName, itemName] = pageName.split('/');
|
||||
const item = items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
||||
return item;
|
||||
return items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
||||
};
|
||||
|
||||
const getItemsInRing = (pageName: string, items: Item[]) => {
|
||||
const item = getItem(pageName, items);
|
||||
const itemsInRing = groupByQuadrants(items)[item.quadrant][item.ring];
|
||||
return itemsInRing;
|
||||
return groupByQuadrants(items)[item.quadrant][item.ring];
|
||||
};
|
||||
|
||||
type PageItemProps = {
|
||||
@@ -139,52 +141,45 @@ export default function PageItem({ pageName, items, leaving, onLeave }: PageItem
|
||||
),
|
||||
};
|
||||
|
||||
const [animations, setAnimations] = useState<any>();
|
||||
|
||||
useEffect(() => {
|
||||
if (leaving) {
|
||||
// entering from an other page
|
||||
// setAnimations(createAnimationRunner(animationsIn).getState())
|
||||
} else {
|
||||
// Hard refresh
|
||||
setAnimations(null);
|
||||
}
|
||||
}, [leaving]);
|
||||
const [animations, setAnimations] = useState<AnimationStates>(() => {
|
||||
return leaving ? createAnimationRunner(animationsIn).getState() : {}
|
||||
});
|
||||
|
||||
const [stateLeaving, setStateLeaving] = useState(leaving);
|
||||
|
||||
let [animationRunner, setAnimationRunner] = useState<any>();
|
||||
useEffect(() => {
|
||||
if (!stateLeaving && leaving) {
|
||||
let animationRunner = createAnimationRunner(
|
||||
animationsOut,
|
||||
() => setAnimations(animationRunner.getState),
|
||||
)
|
||||
animationRunner.run();
|
||||
animationRunner.awaitAnimationComplete(onLeave);
|
||||
setStateLeaving(true)
|
||||
}
|
||||
if (stateLeaving && !leaving) {
|
||||
let animationRunner = createAnimationRunner(
|
||||
animationsIn,
|
||||
() => setAnimations(animationRunner.getState),
|
||||
)
|
||||
animationRunner.run();
|
||||
setStateLeaving(false)
|
||||
}
|
||||
}, [stateLeaving, leaving])
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!stateLeaving && leaving) {
|
||||
// animationRunner = createAnimationRunner(
|
||||
// animationsOut,
|
||||
// handleAnimationsUpdate,
|
||||
// );
|
||||
// setAnimationRunner(animationRunner)
|
||||
// animationRunner.run();
|
||||
// animationRunner.awaitAnimationComplete(onLeave);
|
||||
// }
|
||||
// if (stateLeaving && !leaving) {
|
||||
// animationRunner = createAnimationRunner(
|
||||
// animationsIn,
|
||||
// handleAnimationsUpdate,
|
||||
// );
|
||||
// setAnimationRunner(animationRunner)
|
||||
// animationRunner.run();
|
||||
// }
|
||||
// setStateLeaving(leaving)
|
||||
// }, [leaving])
|
||||
|
||||
const handleAnimationsUpdate = () => {
|
||||
setAnimations(animationRunner.getState());
|
||||
};
|
||||
|
||||
const getAnimationState = (name: string) => {
|
||||
const getAnimationStates = (name: string) => {
|
||||
if (!animations) {
|
||||
return undefined;
|
||||
}
|
||||
return animations[name];
|
||||
}
|
||||
|
||||
const getAnimationState = (name: string) => {
|
||||
const animations = getAnimationStates(name)
|
||||
if (animations === undefined || animations.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
return animations[0]
|
||||
};
|
||||
|
||||
const item = getItem(pageName, items);
|
||||
@@ -199,7 +194,8 @@ export default function PageItem({ pageName, items, leaving, onLeave }: PageItem
|
||||
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
||||
</div>
|
||||
|
||||
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')} itemStyle={getAnimationState('items')}>
|
||||
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')}
|
||||
itemStyle={getAnimationStates('items')}>
|
||||
<div className='split'>
|
||||
<div className='split__left'>
|
||||
<Badge big type={item.ring}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import Badge from '../Badge/Badge';
|
||||
import Link from '../Link/Link';
|
||||
import ItemList from '../ItemList/ItemList';
|
||||
import Flag from '../Flag/Flag';
|
||||
import { Item, Group } from '../../model';
|
||||
import { Group } from '../../model';
|
||||
import './quadrant-section.scss';
|
||||
const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: boolean) => {
|
||||
const itemsInRing = groups[quadrantName][ringName];
|
||||
|
||||
@@ -61,7 +61,6 @@ export default function Router({pageName, items, releases, search}: RouterProps)
|
||||
}, [pageName, items, statePageName]);
|
||||
|
||||
const handlePageLeave = () => {
|
||||
setLeaving(true);
|
||||
setStatePageName(nextPageName);
|
||||
setNextPageName('');
|
||||
|
||||
@@ -76,7 +75,8 @@ export default function Router({pageName, items, releases, search}: RouterProps)
|
||||
case page.index:
|
||||
return <PageIndex leaving={leaving} items={items} onLeave={handlePageLeave} releases={releases}/>;
|
||||
case page.overview:
|
||||
return <PageOverview items={items} rings={rings} search={search} leaving={leaving} onLeave={handlePageLeave}/>;
|
||||
return <PageOverview items={items} rings={rings} search={search} leaving={leaving}
|
||||
onLeave={handlePageLeave}/>;
|
||||
case page.help:
|
||||
return <PageHelp leaving={leaving} onLeave={handlePageLeave}/>;
|
||||
case page.quadrant:
|
||||
|
||||
@@ -26,17 +26,6 @@ export function assetUrl(file: string) {
|
||||
// return `/techradar/assets/${file}`
|
||||
}
|
||||
|
||||
const getPageNames = (radar: Radar) => {
|
||||
return [
|
||||
'index',
|
||||
'overview',
|
||||
'help-and-about-tech-radar',
|
||||
'aoe-toolbox',
|
||||
...quadrants,
|
||||
...getItemPageNames(radar.items),
|
||||
]
|
||||
}
|
||||
|
||||
export const getItemPageNames = (items: Item[]) => items.map(item => `${item.quadrant}/${item.name}`);
|
||||
|
||||
const messages:{[k: string]: string} = {
|
||||
@@ -55,5 +44,3 @@ export function isMobileViewport() {
|
||||
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
return width < 1200;
|
||||
}
|
||||
|
||||
// const formatRelease = (release: moment.MomentInput) => moment(release, 'YYYY-MM-DD').format('MMM YYYY');
|
||||
|
||||
Reference in New Issue
Block a user