added motion to login scene
BIN
public/.DS_Store
vendored
Normal file
Before Width: | Height: | Size: 265 KiB After Width: | Height: | Size: 258 KiB |
1255
public/images/clouds__bg.svg
Normal file
After Width: | Height: | Size: 45 KiB |
1902
public/images/clouds__cloud.svg
Normal file
After Width: | Height: | Size: 131 KiB |
1337
public/images/clouds__cube.svg
Normal file
After Width: | Height: | Size: 48 KiB |
2074
public/images/clouds__dudes.svg
Normal file
After Width: | Height: | Size: 92 KiB |
3652
public/images/clouds__trash.svg
Normal file
After Width: | Height: | Size: 202 KiB |
|
@ -1,14 +1,87 @@
|
|||
import React, { FC, useState } from "react";
|
||||
import React, {
|
||||
FC,
|
||||
memo,
|
||||
MouseEventHandler,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
import styles from "./styles.module.scss";
|
||||
|
||||
interface LoginSceneProps {}
|
||||
|
||||
const LoginScene: FC<LoginSceneProps> = () => {
|
||||
interface Layer {
|
||||
src: string;
|
||||
velocity: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
const layers: Layer[] = [
|
||||
{
|
||||
src: "/images/clouds__bg.svg",
|
||||
velocity: -0.3,
|
||||
width: 3840,
|
||||
height: 1080,
|
||||
},
|
||||
{
|
||||
src: "/images/clouds__cube.svg",
|
||||
velocity: -0.1,
|
||||
width: 3840,
|
||||
height: 1080,
|
||||
},
|
||||
{
|
||||
src: "/images/clouds__cloud.svg",
|
||||
velocity: 0.2,
|
||||
width: 3840,
|
||||
height: 1080,
|
||||
},
|
||||
{
|
||||
src: "/images/clouds__dudes.svg",
|
||||
velocity: 0.5,
|
||||
width: 3840,
|
||||
height: 1080,
|
||||
},
|
||||
{
|
||||
src: "/images/clouds__trash.svg",
|
||||
velocity: 0.8,
|
||||
width: 3840,
|
||||
height: 1080,
|
||||
},
|
||||
];
|
||||
|
||||
const LoginScene: FC<LoginSceneProps> = memo(() => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
const onMouseMove = useCallback(
|
||||
(event: MouseEvent): any => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { x, width } = ref.current.getBoundingClientRect();
|
||||
const middle = (width - x) / 2;
|
||||
const shift = event.pageX / middle / 2 - 0.5;
|
||||
|
||||
layers.map((it, index) => {
|
||||
document.getElementById(
|
||||
`LoginScene__${index}`,
|
||||
)?.style.transform = `translate(${shift * it.velocity * 200}px, 0)`;
|
||||
});
|
||||
},
|
||||
[ref],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
return () => document.removeEventListener("mousemove", onMouseMove);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.scene}>
|
||||
<div className={styles.scene} ref={ref}>
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
|
@ -39,19 +112,23 @@ const LoginScene: FC<LoginSceneProps> = () => {
|
|||
fill="url(#fallbackGradient)"
|
||||
/>
|
||||
|
||||
<image
|
||||
href="/images/clouds.svg"
|
||||
width={1920}
|
||||
height={1080}
|
||||
x={0}
|
||||
y={0}
|
||||
opacity={loaded ? 1 : 0}
|
||||
onLoad={() => setLoaded(true)}
|
||||
className={styles.image}
|
||||
/>
|
||||
{layers.map((it, index) => (
|
||||
<image
|
||||
id={`LoginScene__${index}`}
|
||||
key={it.src}
|
||||
href={it.src}
|
||||
width={it.width}
|
||||
height={it.height}
|
||||
x={1920 / 2 - it.width / 2}
|
||||
y={0}
|
||||
opacity={loaded ? 1 : 0}
|
||||
onLoad={() => setLoaded(true)}
|
||||
className={styles.image}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export { LoginScene };
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
.image {
|
||||
transition: opacity 1s;
|
||||
will-change: opacity, transform;
|
||||
|
||||
@include tablet {
|
||||
display: none;
|
||||
|
|