fix animations
This commit is contained in:
194
src/animation.ts
194
src/animation.ts
@@ -1,134 +1,110 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export type Animations = {
|
||||||
|
[k: string]: Animation[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AnimationStates = {
|
||||||
|
[k: string]: React.CSSProperties[]
|
||||||
|
}
|
||||||
|
|
||||||
type Animation = {
|
type Animation = {
|
||||||
stateA: React.CSSProperties
|
stateA: React.CSSProperties
|
||||||
stateB: React.CSSProperties
|
stateB: React.CSSProperties
|
||||||
delay: number
|
delay: number
|
||||||
run?(callback: (state: any) => any): any // todo fix
|
run?(callback: (state: any) => any): any // todo fix
|
||||||
prepare?(callback: (state: any) => any): any // todo fix
|
prepare?(callback: (state: any) => any): any // todo fix
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnimationController = {}
|
export type AnimationRunner = {
|
||||||
|
getState(): AnimationStates
|
||||||
type AnimationRunner = {
|
run(): any
|
||||||
getState(): any
|
awaitAnimationComplete(callback: () => void): any
|
||||||
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 => ({
|
export const createAnimation = (stateA: React.CSSProperties, stateB: React.CSSProperties, delay: number): Animation => ({
|
||||||
stateA,
|
stateA,
|
||||||
stateB,
|
stateB,
|
||||||
delay,
|
delay,
|
||||||
});
|
});
|
||||||
|
|
||||||
const getAnimationState = (animation: Animation | Animation[], stateName: 'stateA' | 'stateB' = 'stateA'): React.CSSProperties => {
|
const getAnimationStates = (animations: Animation[], stateName: 'stateA' | 'stateB' = 'stateA'): React.CSSProperties[] => {
|
||||||
if (animation instanceof Array) {
|
return animations.map(animation => animation[stateName]);
|
||||||
return animation.map(a => getAnimationState(a, stateName))[0]; // todo fix
|
|
||||||
}
|
|
||||||
|
|
||||||
return animation[stateName];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMaxTransitionTime = (transition: string) => {
|
const getMaxTransitionTime = (transition: string) => {
|
||||||
const re = /(\d+)ms/g;
|
const re = /(\d+)ms/g;
|
||||||
const times: number[] = [];
|
const times: number[] = [];
|
||||||
let matches;
|
let matches;
|
||||||
while ((matches = re.exec(transition)) != null) {
|
while ((matches = re.exec(transition)) != null) {
|
||||||
times.push(parseInt(matches[1], 10));
|
times.push(parseInt(matches[1], 10));
|
||||||
}
|
}
|
||||||
return Math.max(...times);
|
return Math.max(...times);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAnimationDuration = (animation: Animation | Animation[]): number => {
|
const getAnimationDuration = (animation: Animation | Animation[]): number => {
|
||||||
if (animation instanceof Array) {
|
if (animation instanceof Array) {
|
||||||
return animation.reduce((maxDuration, a) => {
|
return animation.reduce((maxDuration, a) => {
|
||||||
const duration = getAnimationDuration(a);
|
const duration = getAnimationDuration(a);
|
||||||
if (duration > maxDuration) {
|
if (duration > maxDuration) {
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
return maxDuration;
|
return maxDuration;
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = animation.stateB;
|
const state = animation.stateB;
|
||||||
const maxTransition = state.transition ? getMaxTransitionTime(state.transition) : 0;
|
const maxTransition = state.transition ? getMaxTransitionTime(state.transition) : 0;
|
||||||
return maxTransition + animation.delay;
|
return maxTransition + animation.delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMaxAnimationsDuration = (animations: {[k: string]: Animation} | Animation[]) => (
|
const getMaxAnimationsDuration = (animations: Animations) => (
|
||||||
getAnimationDuration(Object.values(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 = () => {
|
||||||
let state = Object.entries(animations).reduce((state, [name, animation]) => ({
|
}): AnimationRunner => {
|
||||||
...state,
|
const animations = Object.entries(animationsIn).reduce((state, [name, animation]) => ({
|
||||||
[name]: getAnimationState(animation),
|
...state,
|
||||||
}), {});
|
[name]: animation instanceof Array ? animation : [animation] as Animation[],
|
||||||
|
}), {} as Animations);
|
||||||
|
|
||||||
const animationsDuration = getMaxAnimationsDuration(animations);
|
let state = Object.entries(animations).reduce((state, [name, animation]) => ({
|
||||||
|
...state,
|
||||||
|
[name]: getAnimationStates(animation),
|
||||||
|
}), {} as AnimationStates);
|
||||||
|
|
||||||
const animate = (name: string, animation: Animation) => {
|
const animationsDuration = getMaxAnimationsDuration(animations);
|
||||||
if (animation instanceof Array) {
|
|
||||||
animation.forEach((a, index) => {
|
const animate = (name: string, animation: Animation[]) => {
|
||||||
window.requestAnimationFrame(() => {
|
animation.forEach((a, index) => {
|
||||||
window.setTimeout(() => {
|
window.requestAnimationFrame(() => {
|
||||||
state = {
|
window.setTimeout(() => {
|
||||||
...state,
|
state = {
|
||||||
[name]: [
|
...state,
|
||||||
// ...(state[name]?.slice(0, index)), // todo fix
|
[name]: [
|
||||||
a.stateB,
|
...(state[name]?.slice(0, index)),
|
||||||
// ...(state[name]?.slice(index + 1, state[name].length)), // todo fix
|
a.stateB,
|
||||||
],
|
...(state[name]?.slice(index + 1, state[name].length)),
|
||||||
};
|
],
|
||||||
subscriber();
|
};
|
||||||
}, a.delay);
|
subscriber();
|
||||||
|
}, a.delay);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
window.setTimeout(() => {
|
|
||||||
state = {
|
|
||||||
...state,
|
|
||||||
[name]: animation.stateB,
|
|
||||||
};
|
|
||||||
subscriber();
|
|
||||||
}, animation.delay);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getState() {
|
getState() {
|
||||||
return state;
|
return state;
|
||||||
},
|
},
|
||||||
run() {
|
run() {
|
||||||
Object.entries(animations).forEach(([name, animation]) => {
|
Object.entries(animations).forEach(([name, animation]) => {
|
||||||
animate(name, animation)
|
animate(name, animation)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
awaitAnimationComplete(callback) {
|
awaitAnimationComplete(callback) {
|
||||||
window.setTimeout(callback, animationsDuration);
|
window.setTimeout(callback, animationsDuration);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,243 +1,239 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import Badge from '../Badge/Badge';
|
import Badge from '../Badge/Badge';
|
||||||
import ItemList from '../ItemList/ItemList';
|
import ItemList from '../ItemList/ItemList';
|
||||||
import Link from '../Link/Link';
|
import Link from '../Link/Link';
|
||||||
import FooterEnd from '../FooterEnd/FooterEnd';
|
import FooterEnd from '../FooterEnd/FooterEnd';
|
||||||
import SetTitle from '../SetTitle';
|
import SetTitle from '../SetTitle';
|
||||||
import ItemRevisions from '../ItemRevisions/ItemRevisions';
|
import ItemRevisions from '../ItemRevisions/ItemRevisions';
|
||||||
import { createAnimation, createAnimationRunner } from '../../animation';
|
import {
|
||||||
|
AnimationStates,
|
||||||
|
createAnimation,
|
||||||
|
createAnimationRunner
|
||||||
|
} from '../../animation';
|
||||||
import './item-page.scss';
|
import './item-page.scss';
|
||||||
import { translate } from '../../config';
|
import {translate} from '../../config';
|
||||||
import { groupByQuadrants, Item } from '../../model';
|
import {groupByQuadrants, Item} from '../../model';
|
||||||
|
|
||||||
const getItem = (pageName: string, items: Item[]) => {
|
const getItem = (pageName: string, items: Item[]) => {
|
||||||
const [quadrantName, itemName] = pageName.split('/');
|
const [quadrantName, itemName] = pageName.split('/');
|
||||||
const item = items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
return items.filter((item) => item.quadrant === quadrantName && item.name === itemName)[0];
|
||||||
return item;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getItemsInRing = (pageName: string, items: Item[]) => {
|
const getItemsInRing = (pageName: string, items: Item[]) => {
|
||||||
const item = getItem(pageName, items);
|
const item = getItem(pageName, items);
|
||||||
const itemsInRing = groupByQuadrants(items)[item.quadrant][item.ring];
|
return groupByQuadrants(items)[item.quadrant][item.ring];
|
||||||
return itemsInRing;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type PageItemProps = {
|
type PageItemProps = {
|
||||||
pageName: string;
|
pageName: string;
|
||||||
items: Item[];
|
items: Item[];
|
||||||
leaving: boolean;
|
leaving: boolean;
|
||||||
onLeave: () => void;
|
onLeave: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PageItem({ pageName, items, leaving, onLeave }: PageItemProps) {
|
export default function PageItem({pageName, items, leaving, onLeave}: PageItemProps) {
|
||||||
const itemsInRing = getItemsInRing(pageName, items);
|
const itemsInRing = getItemsInRing(pageName, items);
|
||||||
|
|
||||||
const animationsIn = {
|
const animationsIn = {
|
||||||
background: createAnimation(
|
background: createAnimation(
|
||||||
{
|
{
|
||||||
transform: 'translateX(calc((100vw - 1200px) / 2 + 800px))',
|
transform: 'translateX(calc((100vw - 1200px) / 2 + 800px))',
|
||||||
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
transition: 'transform 450ms cubic-bezier(0.24, 1.12, 0.71, 0.98)',
|
||||||
transform: 'translateX(0)',
|
transform: 'translateX(0)',
|
||||||
},
|
},
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
navHeader: createAnimation(
|
navHeader: createAnimation(
|
||||||
{
|
{
|
||||||
transform: 'translateX(-40px)',
|
transform: 'translateX(-40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(0px)',
|
transform: 'translateX(0px)',
|
||||||
opacity: '1',
|
opacity: '1',
|
||||||
},
|
},
|
||||||
300
|
300
|
||||||
),
|
),
|
||||||
text: createAnimation(
|
text: createAnimation(
|
||||||
{
|
{
|
||||||
transform: 'translateY(-20px)',
|
transform: 'translateY(-20px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateY(0px)',
|
transform: 'translateY(0px)',
|
||||||
opacity: '1',
|
opacity: '1',
|
||||||
},
|
},
|
||||||
600
|
600
|
||||||
),
|
),
|
||||||
items: itemsInRing.map((item, i) =>
|
items: itemsInRing.map((item, i) =>
|
||||||
createAnimation(
|
createAnimation(
|
||||||
{
|
{
|
||||||
transform: 'translateX(-40px)',
|
transform: 'translateX(-40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(0px)',
|
transform: 'translateX(0px)',
|
||||||
opacity: '1',
|
opacity: '1',
|
||||||
},
|
},
|
||||||
400 + 100 * i
|
400 + 100 * i
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
footer: createAnimation(
|
footer: createAnimation(
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(-40px)',
|
transform: 'translateX(-40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(0px)',
|
transform: 'translateX(0px)',
|
||||||
opacity: '1',
|
opacity: '1',
|
||||||
},
|
},
|
||||||
600 + itemsInRing.length * 100
|
600 + itemsInRing.length * 100
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const animationsOut = {
|
const animationsOut = {
|
||||||
background: createAnimation(animationsIn.background.stateB, animationsIn.background.stateA, 300 + itemsInRing.length * 50),
|
background: createAnimation(animationsIn.background.stateB, animationsIn.background.stateA, 300 + itemsInRing.length * 50),
|
||||||
navHeader: createAnimation(
|
navHeader: createAnimation(
|
||||||
animationsIn.navHeader.stateB,
|
animationsIn.navHeader.stateB,
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(40px)',
|
transform: 'translateX(40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
text: createAnimation(
|
text: createAnimation(
|
||||||
animationsIn.text.stateB,
|
animationsIn.text.stateB,
|
||||||
{
|
{
|
||||||
transform: 'translateY(20px)',
|
transform: 'translateY(20px)',
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
items: itemsInRing.map((item, i) =>
|
items: itemsInRing.map((item, i) =>
|
||||||
createAnimation(
|
createAnimation(
|
||||||
animationsIn.items[i].stateB,
|
animationsIn.items[i].stateB,
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(40px)',
|
transform: 'translateX(40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
100 + 50 * i
|
100 + 50 * i
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
footer: createAnimation(
|
footer: createAnimation(
|
||||||
animationsIn.text.stateB,
|
animationsIn.text.stateB,
|
||||||
{
|
{
|
||||||
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
transition: 'opacity 150ms ease-out, transform 300ms ease-out',
|
||||||
transform: 'translateX(40px)',
|
transform: 'translateX(40px)',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
},
|
},
|
||||||
200 + itemsInRing.length * 50
|
200 + itemsInRing.length * 50
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [animations, setAnimations] = useState<any>();
|
const [animations, setAnimations] = useState<AnimationStates>(() => {
|
||||||
|
return leaving ? createAnimationRunner(animationsIn).getState() : {}
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
const [stateLeaving, setStateLeaving] = useState(leaving);
|
||||||
if (leaving) {
|
|
||||||
// entering from an other page
|
useEffect(() => {
|
||||||
// setAnimations(createAnimationRunner(animationsIn).getState())
|
if (!stateLeaving && leaving) {
|
||||||
} else {
|
let animationRunner = createAnimationRunner(
|
||||||
// Hard refresh
|
animationsOut,
|
||||||
setAnimations(null);
|
() => 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])
|
||||||
|
|
||||||
|
const getAnimationStates = (name: string) => {
|
||||||
|
if (!animations) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return animations[name];
|
||||||
}
|
}
|
||||||
}, [leaving]);
|
|
||||||
|
|
||||||
const [stateLeaving, setStateLeaving] = useState(leaving);
|
const getAnimationState = (name: string) => {
|
||||||
|
const animations = getAnimationStates(name)
|
||||||
|
if (animations === undefined || animations.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return animations[0]
|
||||||
|
};
|
||||||
|
|
||||||
let [animationRunner, setAnimationRunner] = useState<any>();
|
const item = getItem(pageName, items);
|
||||||
|
|
||||||
// useEffect(() => {
|
return (
|
||||||
// if (!stateLeaving && leaving) {
|
<div>
|
||||||
// animationRunner = createAnimationRunner(
|
<SetTitle title={item.title}/>
|
||||||
// animationsOut,
|
<div className='item-page'>
|
||||||
// handleAnimationsUpdate,
|
<div className='item-page__nav'>
|
||||||
// );
|
<div className='item-page__nav__inner'>
|
||||||
// setAnimationRunner(animationRunner)
|
<div className='item-page__header' style={getAnimationState('navHeader')}>
|
||||||
// animationRunner.run();
|
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
||||||
// animationRunner.awaitAnimationComplete(onLeave);
|
</div>
|
||||||
// }
|
|
||||||
// if (stateLeaving && !leaving) {
|
|
||||||
// animationRunner = createAnimationRunner(
|
|
||||||
// animationsIn,
|
|
||||||
// handleAnimationsUpdate,
|
|
||||||
// );
|
|
||||||
// setAnimationRunner(animationRunner)
|
|
||||||
// animationRunner.run();
|
|
||||||
// }
|
|
||||||
// setStateLeaving(leaving)
|
|
||||||
// }, [leaving])
|
|
||||||
|
|
||||||
const handleAnimationsUpdate = () => {
|
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')}
|
||||||
setAnimations(animationRunner.getState());
|
itemStyle={getAnimationStates('items')}>
|
||||||
};
|
<div className='split'>
|
||||||
|
<div className='split__left'>
|
||||||
const getAnimationState = (name: string) => {
|
<Badge big type={item.ring}>
|
||||||
if (!animations) {
|
{item.ring}
|
||||||
return undefined;
|
</Badge>
|
||||||
}
|
</div>
|
||||||
return animations[name];
|
<div className='split__right'>
|
||||||
};
|
<Link className='icon-link' pageName={item.quadrant}>
|
||||||
|
<span className='icon icon--pie icon-link__icon'/>
|
||||||
const item = getItem(pageName, items);
|
Quadrant Overview
|
||||||
|
</Link>
|
||||||
return (
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<SetTitle title={item.title} />
|
</ItemList>
|
||||||
<div className='item-page'>
|
<div className='item-page__footer' style={getAnimationState('footer')}>
|
||||||
<div className='item-page__nav'>
|
<FooterEnd modifier='in-sidebar'/>
|
||||||
<div className='item-page__nav__inner'>
|
</div>
|
||||||
<div className='item-page__header' style={getAnimationState('navHeader')}>
|
</div>
|
||||||
<h3 className='headline'>{translate(item.quadrant)}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ItemList items={itemsInRing} activeItem={item} headerStyle={getAnimationState('navHeader')} itemStyle={getAnimationState('items')}>
|
|
||||||
<div className='split'>
|
|
||||||
<div className='split__left'>
|
|
||||||
<Badge big type={item.ring}>
|
|
||||||
{item.ring}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='split__right'>
|
<div className='item-page__content' style={getAnimationState('background')}>
|
||||||
<Link className='icon-link' pageName={item.quadrant}>
|
<div className='item-page__content__inner' style={getAnimationState('text')}>
|
||||||
<span className='icon icon--pie icon-link__icon' />
|
<div className='item-page__header'>
|
||||||
Quadrant Overview
|
<div className='split'>
|
||||||
</Link>
|
<div className='split__left'>
|
||||||
|
<h1 className='hero-headline hero-headline--inverse'>{item.title}</h1>
|
||||||
|
</div>
|
||||||
|
<div className='split__right'>
|
||||||
|
<Badge big type={item.ring}>
|
||||||
|
{item.ring}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='markdown' dangerouslySetInnerHTML={{__html: item.body}}/>
|
||||||
|
{item.revisions.length > 1 && <ItemRevisions revisions={item.revisions.slice(1)}/>}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</ItemList>
|
|
||||||
<div className='item-page__footer' style={getAnimationState('footer')}>
|
|
||||||
<FooterEnd modifier='in-sidebar' />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='item-page__content' style={getAnimationState('background')}>
|
);
|
||||||
<div className='item-page__content__inner' style={getAnimationState('text')}>
|
|
||||||
<div className='item-page__header'>
|
|
||||||
<div className='split'>
|
|
||||||
<div className='split__left'>
|
|
||||||
<h1 className='hero-headline hero-headline--inverse'>{item.title}</h1>
|
|
||||||
</div>
|
|
||||||
<div className='split__right'>
|
|
||||||
<Badge big type={item.ring}>
|
|
||||||
{item.ring}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='markdown' dangerouslySetInnerHTML={{ __html: item.body }} />
|
|
||||||
{item.revisions.length > 1 && <ItemRevisions revisions={item.revisions.slice(1)} />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Badge from '../Badge/Badge';
|
|||||||
import Link from '../Link/Link';
|
import Link from '../Link/Link';
|
||||||
import ItemList from '../ItemList/ItemList';
|
import ItemList from '../ItemList/ItemList';
|
||||||
import Flag from '../Flag/Flag';
|
import Flag from '../Flag/Flag';
|
||||||
import { Item, Group } from '../../model';
|
import { Group } from '../../model';
|
||||||
import './quadrant-section.scss';
|
import './quadrant-section.scss';
|
||||||
const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: boolean) => {
|
const renderList = (ringName: Ring, quadrantName: string, groups: Group, big: boolean) => {
|
||||||
const itemsInRing = groups[quadrantName][ringName];
|
const itemsInRing = groups[quadrantName][ringName];
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ export default function Router({pageName, items, releases, search}: RouterProps)
|
|||||||
}, [pageName, items, statePageName]);
|
}, [pageName, items, statePageName]);
|
||||||
|
|
||||||
const handlePageLeave = () => {
|
const handlePageLeave = () => {
|
||||||
setLeaving(true);
|
|
||||||
setStatePageName(nextPageName);
|
setStatePageName(nextPageName);
|
||||||
setNextPageName('');
|
setNextPageName('');
|
||||||
|
|
||||||
@@ -76,7 +75,8 @@ export default function Router({pageName, items, releases, search}: RouterProps)
|
|||||||
case page.index:
|
case page.index:
|
||||||
return <PageIndex leaving={leaving} items={items} onLeave={handlePageLeave} releases={releases}/>;
|
return <PageIndex leaving={leaving} items={items} onLeave={handlePageLeave} releases={releases}/>;
|
||||||
case page.overview:
|
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:
|
case page.help:
|
||||||
return <PageHelp leaving={leaving} onLeave={handlePageLeave}/>;
|
return <PageHelp leaving={leaving} onLeave={handlePageLeave}/>;
|
||||||
case page.quadrant:
|
case page.quadrant:
|
||||||
|
|||||||
@@ -26,17 +26,6 @@ export function assetUrl(file: string) {
|
|||||||
// return `/techradar/assets/${file}`
|
// 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}`);
|
export const getItemPageNames = (items: Item[]) => items.map(item => `${item.quadrant}/${item.name}`);
|
||||||
|
|
||||||
const messages:{[k: string]: string} = {
|
const messages:{[k: string]: string} = {
|
||||||
@@ -55,5 +44,3 @@ export function isMobileViewport() {
|
|||||||
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
return width < 1200;
|
return width < 1200;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const formatRelease = (release: moment.MomentInput) => moment(release, 'YYYY-MM-DD').format('MMM YYYY');
|
|
||||||
|
|||||||
Reference in New Issue
Block a user