-
Notifications
You must be signed in to change notification settings - Fork 294
/
Slide.jsx
109 lines (98 loc) · 2.9 KB
/
Slide.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// @flow
import React, { useCallback, useEffect, useRef } from "react";
import styled from "styled-components";
import { useSpring, animated } from "react-spring";
import { openURL } from "~/renderer/linking";
import Box from "~/renderer/components/Box";
import Text from "~/renderer/components/Text";
import { Wrapper, Label, IllustrationWrapper } from "~/renderer/components/Carousel";
import { useHistory } from "react-router-dom";
const Layer = styled(animated.div)`
background-image: url('${p => p.image}');
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
will-change: transform;
position: absolute;
width: ${p => p.width}px;
height: ${p => p.height}px;
transform-origin: top left;
`;
type Img = {
source: string,
transform: [number, number, number, number],
size: { width: number, height: number },
};
type Props = {
url?: string,
path?: string,
title: *,
description: *,
imgs: Img[],
};
const Slide = ({ url, path, title, description, imgs }: Props) => {
const history = useHistory();
const [{ xy }, set] = useSpring(() => ({
xy: [-120, -30],
config: { mass: 10, tension: 550, friction: 140 },
}));
const getTransform = (offsetX, effectX, offsetY, effectY) => ({
transform: xy.interpolate(
(x, y) => `translate3d(${x / effectX + offsetX}px,${y / effectY + offsetY}px, 0)`,
),
});
// React to the user mouse movement inside the banner for parallax effect
const onMouseMove = e => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
set({ xy: [x - rect.width / 2, y - rect.height / 2] });
};
const onMouseLeave = () => set({ xy: [0, 0] });
const onClick = useCallback(() => {
if (path) {
history.push({ pathname: path, state: { source: "banner" } });
return;
}
if (url) {
openURL(url);
}
}, [history, path, url]);
// After initial slide-in animation, set the offset to zero
useEffect(() => {
setTimeout(_ => {
set({ xy: [0, 0] });
}, 400);
}, [set]);
const ref = useRef(null);
return (
<Wrapper onClick={onClick} ref={ref} onMouseMove={onMouseMove} onMouseLeave={onMouseLeave}>
<Box flex={1} p={24}>
<Label ff="Inter|SemiBold" fontSize={2}>
{title}
</Label>
<Text
style={{ marginBottom: 16 }}
ff="Inter|Medium"
color="palette.text.shade50"
fontSize={4}
>
{description}
</Text>
</Box>
<IllustrationWrapper>
{imgs.map(({ source, transform, size }, i) => (
<Layer
key={i}
style={getTransform.apply(null, transform)}
image={source}
width={size.width}
height={size.height}
/>
))}
</IllustrationWrapper>
</Wrapper>
);
};
export default Slide;