diff --git a/src/components/Container.js b/src/components/Container.js index c0efabd..449a43d 100644 --- a/src/components/Container.js +++ b/src/components/Container.js @@ -1,28 +1,199 @@ -import { css } from "emotion"; - -const Container = ({ children, ...props }) => ( -
+import React, { useEffect, useRef, useLayoutEffect } from "react"; +import { css, cx } from "emotion"; +import { Link, navigate } from "@reach/router"; + +import { ReactComponent as Logo } from "../assets/logo.svg"; +import { ReactComponent as Right } from "../assets/arrow-right.svg"; + +const flash = css` + span& { + width: 5.6rem; + height: 5.6rem; + opacity: 100%; + top: -0.3rem; + left: -0.3rem; + } +`; + +const clearable = new Set(); + +const Container = ({ children, hideNav = false, next, ...props }) => { + const logoContainer = useRef(); + const logo = useRef(); + const highlightCircle = useRef(); + const containerChild = useRef(); + const nextBtn = useRef(); + + children = React.Children.map(children, child => { + return React.cloneElement(child, { + style: { opacity: 0, marginBottom: "5rem", transition: "all 300ms" }, + }); + }); + + useEffect(() => { + /* to prevent the scrollbar janking while animating; + doesn't work consistently; must investigate */ + document.body.style.maxHeight = "100vh"; + document.body.style.overflow = "hidden"; + + if (highlightCircle.current) { + highlightCircle.current.classList.add(flash); + clearable.add( + setTimeout( + () => highlightCircle.current && highlightCircle.current.classList.remove(flash), + 1500, + ), + ); + } + + if (nextBtn.current) { + nextBtn.current.style.width = "4rem"; + setTimeout(() => nextBtn.current && (nextBtn.current.style.right = "10vw"), 300); + } + + if (containerChild.current) { + const containerChildren = [...containerChild.current.children]; + containerChildren.forEach((child, idx) => { + setTimeout(() => { + child.style.removeProperty("opacity"); + child.style.removeProperty("margin-bottom"); + }, 100 * idx); + }); + + setTimeout(() => { + document.body.style.maxHeight = "auto"; + document.body.style.overflow = "auto"; + }, containerChildren.length * 100); + } + + // cleanup + return () => (clearable.forEach(item => clearTimeout(item)), clearable.clear()); + }, []); + + const handleResize = () => { + if (logoContainer.current) + logoContainer.current.style.left = `${containerChild.current.getBoundingClientRect().x}px`; + }; + + useEffect(() => { + window.addEventListener("resize", handleResize); + + // cleanup + return () => window.removeEventListener("resize", handleResize); + }, []); + + // on first render + useLayoutEffect(handleResize, []); + + const handleNext = e => { + if (containerChild.current) { + [...containerChild.current.children].forEach(child => { + child.style.marginBottom = "2rem"; + child.style.opacity = "0"; + }); + } + e.currentTarget.style.width = 0; + setTimeout(() => navigate(next), 300); + }; + + return (
* { - margin-bottom: 2rem; - } - `} - {...props}> - {children} + background: var(--background-color); + padding: 15rem calc(100vw / 8) 8rem calc(100vw / 8); + overflow-x: hidden; + min-height: 100vh; + position: relative; + `}> + {!hideNav && ( + + + + + )} + {next && ( + + )} +
* { + margin-bottom: 2rem; + } + `} + ref={containerChild} + {...props}> + {children} +
-
-); + ); +}; export default Container;