Skip to content

Commit 767adbf

Browse files
authored
Merge pull request pomber#1 from pomber/animate-code
2 parents 269542d + 2b7a307 commit 767adbf

File tree

8 files changed

+400
-59
lines changed

8 files changed

+400
-59
lines changed

src/airframe/airframe.js

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import easing from "./easing";
2+
/* eslint-disable */
3+
function mergeResults(results) {
4+
const firstResult = results[0];
5+
if (results.length < 2) {
6+
return firstResult;
7+
}
8+
if (Array.isArray(firstResult)) {
9+
// console.log("merge", results);
10+
return firstResult.map((_, i) => {
11+
return mergeResults(results.map(result => result[i]));
12+
});
13+
} else {
14+
return Object.assign({}, ...results);
15+
}
16+
}
17+
18+
const airframe = {
19+
parallel: ({ children: fns }) => {
20+
return (t, ...args) => {
21+
const styles = fns.map(fn => fn(t, ...args));
22+
const result = mergeResults(styles);
23+
return result;
24+
};
25+
},
26+
chain: ({ children: fns, durations }) => {
27+
return (t, ...args) => {
28+
let style = fns[0](0, ...args);
29+
let lowerDuration = 0;
30+
for (let i = 0; i < fns.length; i++) {
31+
const fn = fns[i];
32+
const thisDuration = durations[i];
33+
const upperDuration = lowerDuration + thisDuration;
34+
if (lowerDuration <= t && t <= upperDuration) {
35+
const innerT = (t - lowerDuration) / thisDuration;
36+
style = mergeResults([style, fn(innerT, ...args)]);
37+
} else if (upperDuration < t) {
38+
// merge the end of previous animation
39+
style = mergeResults([style, fn(1, ...args)]);
40+
} else if (t < lowerDuration) {
41+
// merge the start of future animation
42+
style = mergeResults([fn(0, ...args), style]);
43+
}
44+
lowerDuration = upperDuration;
45+
}
46+
return style;
47+
};
48+
},
49+
delay: () => () => ({}),
50+
tween: ({ from, to, ease = easing.linear }) => (t, targets) => {
51+
const style = {};
52+
Object.keys(from).forEach(key => {
53+
const value = from[key] + (to[key] - from[key]) * ease(t);
54+
if (key === "x") {
55+
style["transform"] = `translateX(${value}px)`;
56+
} else {
57+
style[key] = value;
58+
}
59+
});
60+
return style;
61+
}
62+
};
63+
64+
/* @jsx createAnimation */
65+
export const Stagger = props => (t, targets) => {
66+
const filter = target => !props.filter || props.filter(target);
67+
const interval =
68+
targets.filter(filter).length < 2
69+
? 0
70+
: props.interval / (targets.filter(filter).length - 1);
71+
let i = 0;
72+
return targets.map(target => {
73+
// console.log(target, props.filter(target));
74+
if (!filter(target)) {
75+
return {};
76+
}
77+
const animation = (
78+
<parallel>
79+
<chain durations={[i * interval, 1 - props.interval]}>
80+
<delay />
81+
{props.children[0]}
82+
</chain>
83+
</parallel>
84+
);
85+
i++;
86+
const result = animation(t, target);
87+
// console.log("Stagger Result", t, result);
88+
return result;
89+
});
90+
};
91+
92+
export function createAnimation(type, props, ...children) {
93+
const allProps = Object.assign({ children }, props);
94+
if (typeof type === "string") {
95+
if (window.LOG === "verbose") {
96+
return (t, ...args) => {
97+
console.groupCollapsed(type, t);
98+
const result = airframe[type](allProps)(t, ...args);
99+
console.log(result);
100+
console.groupEnd();
101+
return result;
102+
};
103+
} else {
104+
return airframe[type](allProps);
105+
}
106+
} else {
107+
if (window.LOG === "verbose") {
108+
return (t, ...args) => {
109+
console.groupCollapsed(type.name, t);
110+
const result = type(allProps)(t, ...args);
111+
console.log(result);
112+
console.groupEnd();
113+
return result;
114+
};
115+
} else {
116+
return type(allProps);
117+
}
118+
}
119+
}

src/airframe/easing.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
export default {
2+
// no easing, no acceleration
3+
linear: function(t) {
4+
return t;
5+
},
6+
// accelerating from zero velocity
7+
easeInQuad: function(t) {
8+
return t * t;
9+
},
10+
// decelerating to zero velocity
11+
easeOutQuad: function(t) {
12+
return t * (2 - t);
13+
},
14+
// acceleration until halfway, then deceleration
15+
easeInOutQuad: function(t) {
16+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
17+
},
18+
// accelerating from zero velocity
19+
easeInCubic: function(t) {
20+
return t * t * t;
21+
},
22+
// decelerating to zero velocity
23+
easeOutCubic: function(t) {
24+
return --t * t * t + 1;
25+
},
26+
// acceleration until halfway, then deceleration
27+
easeInOutCubic: function(t) {
28+
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
29+
},
30+
// accelerating from zero velocity
31+
easeInQuart: function(t) {
32+
return t * t * t * t;
33+
},
34+
// decelerating to zero velocity
35+
easeOutQuart: function(t) {
36+
return 1 - --t * t * t * t;
37+
},
38+
// acceleration until halfway, then deceleration
39+
easeInOutQuart: function(t) {
40+
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
41+
},
42+
// accelerating from zero velocity
43+
easeInQuint: function(t) {
44+
return t * t * t * t * t;
45+
},
46+
// decelerating to zero velocity
47+
easeOutQuint: function(t) {
48+
return 1 + --t * t * t * t * t;
49+
},
50+
// acceleration until halfway, then deceleration
51+
easeInOutQuint: function(t) {
52+
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
53+
}
54+
};

src/animation.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { createAnimation, Stagger } from "./airframe/airframe";
2+
import easing from "./airframe/easing";
3+
4+
/* eslint-disable */
5+
6+
const dx = 250;
7+
8+
/* @jsx createAnimation */
9+
10+
// window.LOG = "verbose";
11+
12+
const SlideToLeft = () => (
13+
<tween
14+
from={{ x: 0, opacity: 1 }}
15+
to={{ x: -dx, opacity: 0 }}
16+
ease={easing.easeInQuad}
17+
/>
18+
);
19+
20+
function ShrinkHeight() {
21+
return (
22+
<tween
23+
from={{ height: 15 }}
24+
to={{ height: 0 }}
25+
ease={easing.easeInOutQuad}
26+
/>
27+
);
28+
}
29+
30+
const SlideFromRight = () => (
31+
<tween
32+
from={{ x: dx, opacity: 0 }}
33+
to={{ x: 0, opacity: 1 }}
34+
ease={easing.easeOutQuad}
35+
/>
36+
);
37+
function GrowHeight() {
38+
return (
39+
<tween
40+
from={{ height: 0 }}
41+
to={{ height: 15 }}
42+
ease={easing.easeInOutQuad}
43+
/>
44+
);
45+
}
46+
47+
function SwitchLines({ filterExit, filterEnter }) {
48+
return (
49+
<parallel>
50+
<Stagger interval={0.2} filter={filterExit}>
51+
<chain durations={[0.35, 0.3, 0.35]}>
52+
<SlideToLeft />
53+
<ShrinkHeight />
54+
</chain>
55+
</Stagger>
56+
<Stagger interval={0.2} filter={filterEnter}>
57+
<chain durations={[0.35, 0.3, 0.35]}>
58+
<delay />
59+
<GrowHeight />
60+
<SlideFromRight />
61+
</chain>
62+
</Stagger>
63+
</parallel>
64+
);
65+
}
66+
67+
export default (
68+
<chain durations={[0.5, 0.5]}>
69+
<SwitchLines
70+
filterExit={line => line.left && !line.middle}
71+
filterEnter={line => !line.left && line.middle}
72+
/>
73+
<SwitchLines
74+
filterExit={line => line.middle && !line.right}
75+
filterEnter={line => !line.middle && line.right}
76+
/>
77+
</chain>
78+
);

src/differ.js

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -83,61 +83,3 @@ export function getSlides(codes) {
8383
.filter(line => line.middle || line.left || line.right);
8484
});
8585
}
86-
87-
//
88-
89-
function getLines(change) {
90-
return change.value
91-
.trimRight(newlineRe)
92-
.split(newlineRe)
93-
.map(content => ({
94-
content
95-
}));
96-
}
97-
98-
export function tripleDiff(left, middle, right) {
99-
const leftDiff = diff.diffLines(left, middle);
100-
const rightDiff = diff.diffLines(middle, right);
101-
102-
let x = leftDiff
103-
.map(change =>
104-
change.value
105-
.trimRight(newlineRe)
106-
.split(newlineRe)
107-
.map(content => ({
108-
content,
109-
left: !change.added,
110-
middle: !change.removed
111-
}))
112-
)
113-
.flat();
114-
// console.log(JSON.stringify(leftDiff, null, 2));
115-
// console.log(JSON.stringify(x, null, 2));
116-
117-
let i = 0;
118-
// console.log(rightDiff);
119-
rightDiff.forEach(change => {
120-
let mx = x.filter(l => l.middle || l.right);
121-
if (change.added) {
122-
const lines = change.value
123-
.trimRight(newlineRe)
124-
.split(newlineRe)
125-
.map(content => ({
126-
content,
127-
left: false,
128-
middle: false,
129-
right: true
130-
}));
131-
insert(x, i, lines);
132-
} else if (!change.removed) {
133-
// console.log(change);
134-
for (let j = 0; j < change.count; j++) {
135-
mx[i + j].right = true;
136-
}
137-
}
138-
i += change.count;
139-
});
140-
// console.log(JSON.stringify(rightDiff, null, 2));
141-
// console.log(JSON.stringify(x, null, 2));
142-
return x;
143-
}

src/history.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useEffect, useState } from "react";
22
import { getSlides } from "./differ";
33
import { useSpring } from "react-use";
4+
import Slide from "./slide";
45

56
export default function History({ commits, language }) {
67
const codes = commits.map(commit => commit.content);
@@ -22,7 +23,11 @@ export default function History({ commits, language }) {
2223
}
2324
};
2425
});
25-
return <pre>{codes[index]}</pre>;
26+
return (
27+
<React.Fragment>
28+
<Slide time={current - index} lines={slideLines[index]} />
29+
</React.Fragment>
30+
);
2631
}
2732
function useSliderSpring(initial) {
2833
const [target, setTarget] = useState(initial);

src/index.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ body {
66
sans-serif;
77
-webkit-font-smoothing: antialiased;
88
-moz-osx-font-smoothing: grayscale;
9+
background-color: rgb(1, 22, 39);
10+
color: rgb(214, 222, 235);
911
}
1012

1113
code {

0 commit comments

Comments
 (0)