import React, { useState, useEffect, useRef, useLayoutEffect } from "react"; import { css, cx } from "@emotion/css"; import useLocation from "wouter/use-location"; import { ReactComponent as Logo } from "../assets/logo.svg"; import { ReactComponent as Right } from "../assets/arrow-right.svg"; import { getTimeout } from "../util"; import Menu from "./Menu"; import useMediaQuery from "../util/useMediaQuery"; const [timer, clear] = getTimeout(); const Container: React.FC<{ children: ( | string | React.DetailedReactHTMLElement | React.ReactElement )[]; hideNav?: boolean; end?: boolean; next?: string; className?: string; }> = ({ children: _children, hideNav = false, end = false, next, className, ...props }) => { const [, navigate] = useLocation(); const mobile = useMediaQuery("(max-width: 50rem)"); const logoContainer = useRef(null); const highlightCircle = useRef(null); const containerChild = useRef(null); const nextBtn = useRef(null); const [showMenu, setShowMenu] = useState(false); const children = React.Children.map( _children, ( child: | string | React.DetailedReactHTMLElement | React.ReactElement, ) => !child || typeof child === "string" ? child : React.cloneElement(child, { style: { opacity: 0, transform: "translateY(3rem)", transition: "all 300ms", }, }), ); useEffect(() => { // scroll back to top when new page is loaded window.scrollTo({ top: 0 }); if (highlightCircle.current) { highlightCircle.current.classList.add("highlight"); timer( () => highlightCircle.current && highlightCircle.current.classList.remove("highlight"), 1500, ); } if (nextBtn.current) { nextBtn.current.style.width = "4rem"; timer( () => nextBtn.current && (nextBtn.current.style.right = "10vw"), 300, ); } if (containerChild.current) { const containerChildren = [...containerChild.current.children] as ( | HTMLElement | SVGElement )[]; containerChildren.forEach((child, idx) => { timer(() => { child.style.removeProperty("opacity"); child.style.removeProperty("transform"); }, 100 * idx); }); timer(() => { document.body.style.maxHeight = "auto"; document.body.style.overflow = "auto"; }, containerChildren.length * 100); } // cleanup return clear; }, []); const handleResize = () => { if (containerChild.current && 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: React.MouseEventHandler = e => { if (containerChild.current) { ( [...containerChild.current.children] as (HTMLElement | SVGElement)[] ).forEach(child => { child.style.marginBottom = "2rem"; child.style.opacity = "0"; }); } document.body.style.maxHeight = "100vh"; document.body.style.overflow = "hidden"; e.currentTarget.style.width = "0"; timer(() => next && navigate(next), 300); }; return (
{!hideNav && ( )} {next && ( )}
* { margin-bottom: 2rem; } `, className, )} ref={containerChild} {...props}> {children}
); }; export default Container;