mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
460 lines
14 KiB
TypeScript
460 lines
14 KiB
TypeScript
/* eslint-disable no-nested-ternary */
|
|
import {
|
|
Box,
|
|
BoxedNextImage,
|
|
Button,
|
|
Flex,
|
|
HStack,
|
|
Icon,
|
|
IconButton,
|
|
Link,
|
|
Stack,
|
|
Text,
|
|
Tooltip,
|
|
usePrefersReducedMotion,
|
|
useToast,
|
|
VStack,
|
|
} from '@metafam/ds';
|
|
import { SetStateAction } from 'jotai';
|
|
import React, {
|
|
Dispatch,
|
|
ReactNode,
|
|
useCallback,
|
|
useEffect,
|
|
useState,
|
|
} from 'react';
|
|
import { FaToggleOff, FaToggleOn } from 'react-icons/fa';
|
|
import { MdClose } from 'react-icons/md';
|
|
|
|
import OctoBg from '#assets/baby_octo.webp';
|
|
import MetaGameLogo from '#assets/new_logo_svg.svg';
|
|
import { MetaLink } from '#components/Link';
|
|
import { Socials } from '#components/SocialLinks';
|
|
import { get, set } from '#lib/store';
|
|
|
|
import { AnimatedWaves, upDownAnimation } from './animations';
|
|
import { LandingConnectButton } from './LandingConnectButton';
|
|
import { sections } from './landingSection';
|
|
|
|
export const LandingHeader: React.FC = () => {
|
|
const [menuToggle, setMenuToggle] = useState(false);
|
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
const savedMotionPreference = get('MotionPreference');
|
|
const [noMotion, setNoMotion] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
if (savedMotionPreference === 'off') {
|
|
setNoMotion(true);
|
|
} else if (savedMotionPreference === 'on') {
|
|
setNoMotion(false);
|
|
} else {
|
|
setNoMotion(prefersReducedMotion);
|
|
}
|
|
}, [savedMotionPreference, prefersReducedMotion]);
|
|
|
|
const reducedNoticeDismissed = get('ReducedMotionNotice') === 'dismissed';
|
|
const root = typeof window !== 'undefined' ? document.body : null;
|
|
const [effectsToggle, setEffectsToggle] = useState(noMotion);
|
|
const toggleIcon = effectsToggle ? FaToggleOff : FaToggleOn;
|
|
const [noticeOpen, setNoticeOpen] = useState(false);
|
|
const toast = useToast();
|
|
|
|
const handleCloseNotice = useCallback(() => {
|
|
setNoticeOpen(false);
|
|
set('ReducedMotionNotice', 'dismissed');
|
|
}, []);
|
|
|
|
const handleToggleEffects = useCallback(() => {
|
|
set('MotionPreference', !noMotion ? 'off' : 'on');
|
|
setNoMotion(!noMotion);
|
|
setEffectsToggle(!effectsToggle);
|
|
toast({
|
|
title: `Motion ${noMotion ? 'enabled' : 'disabled'}`,
|
|
description: `Toggle to turn effects & animations ${
|
|
noMotion ? 'off' : 'on'
|
|
}.`,
|
|
status: 'info',
|
|
duration: 5000,
|
|
isClosable: true,
|
|
});
|
|
}, [effectsToggle, noMotion, toast]);
|
|
|
|
useEffect(() => {
|
|
if (typeof window !== 'undefined' && window.matchMedia !== undefined) {
|
|
if (noMotion) {
|
|
root?.classList.add('no-motion');
|
|
if (!reducedNoticeDismissed) {
|
|
setNoticeOpen(true);
|
|
}
|
|
} else {
|
|
root?.classList.remove('no-motion');
|
|
setNoticeOpen(false);
|
|
}
|
|
setEffectsToggle(noMotion);
|
|
}
|
|
}, [noMotion, prefersReducedMotion, reducedNoticeDismissed, root]);
|
|
|
|
return (
|
|
<>
|
|
<Box
|
|
as="header"
|
|
pos="fixed"
|
|
textAlign="center"
|
|
px={{ base: 1, md: 8, lg: 14 }}
|
|
w="100%"
|
|
top={{ base: 5, '2xl': 10 }}
|
|
left={0}
|
|
zIndex={401}
|
|
>
|
|
<Flex
|
|
h={10}
|
|
minH={10}
|
|
p={{ base: 4, md: 0 }}
|
|
mx="auto"
|
|
align="center"
|
|
justify="space-between"
|
|
w="100%"
|
|
maxW={{ base: 'full' }}
|
|
>
|
|
<HStack
|
|
spacing={8}
|
|
align="center"
|
|
transition="opacity 0.3s 0.6s ease"
|
|
>
|
|
<MetaLink
|
|
key="link-home-logo"
|
|
href="/#start"
|
|
color="white"
|
|
sx={{
|
|
'&.active, &:hover': {
|
|
textDecoration: 'none',
|
|
},
|
|
}}
|
|
>
|
|
<HStack
|
|
fontFamily="body"
|
|
fontSize={{ base: 'md', xl: 'lg', '4xl': '2xl' }}
|
|
fontWeight={400}
|
|
spacing={2}
|
|
alignItems="center"
|
|
justifyContent="flex-start"
|
|
>
|
|
<BoxedNextImage
|
|
src={MetaGameLogo}
|
|
alt="MetaGame Logo"
|
|
w={{ base: '2rem', xl: '2.25rem', '4xl': '2.5rem' }}
|
|
h={{ base: '2.25rem', xl: '2.5rem', '4xl': '2.75rem' }}
|
|
/>
|
|
<Box as="span">MetaGame</Box>
|
|
</HStack>
|
|
</MetaLink>
|
|
</HStack>
|
|
<HStack
|
|
alignItems="center"
|
|
alignContent="center"
|
|
zIndex={401}
|
|
pointerEvents="auto"
|
|
>
|
|
<Tooltip
|
|
label={`Turn effects ${noMotion ? 'On' : 'Off'}`}
|
|
hasArrow
|
|
placement="bottom"
|
|
>
|
|
<Button
|
|
onClick={handleToggleEffects}
|
|
variant="ghost"
|
|
display="inline-block"
|
|
fontWeight="normal"
|
|
color="white"
|
|
borderRadius="inherit inherit 0 0"
|
|
opacity={0.3}
|
|
px={{ base: 1, xl: 2 }}
|
|
sx={{
|
|
'&:hover': {
|
|
backgroundColor: 'transparent',
|
|
color: 'var(--chakra-colors-landing300)',
|
|
opacity: 1,
|
|
svg: {
|
|
filter:
|
|
'drop-shadow(0 0 10px var(--chakra-colors-landing300))',
|
|
},
|
|
},
|
|
}}
|
|
>
|
|
<Icon as={toggleIcon} h={{ base: 8, '2xl': 10 }} w="auto" />
|
|
</Button>
|
|
</Tooltip>
|
|
|
|
<LandingConnectButton isIconStyle />
|
|
<Button
|
|
onClick={() => setMenuToggle(!menuToggle)}
|
|
sx={{
|
|
alignSelf: 'center',
|
|
justifySelf: 'right',
|
|
position: 'relative',
|
|
flexDirection: 'column',
|
|
justifyContent: 'space-around',
|
|
w: { base: '2.25rem', xl: '2.5rem', '4xl': '3.1rem' },
|
|
h: { base: '2.25rem', xl: '2.5rem', '4xl': '3.1rem' },
|
|
borderRadius: { base: '0.25rem', xl: '1rem', '4xl': 'full' },
|
|
background: 'transparent',
|
|
border: 'none',
|
|
cursor: 'pointer',
|
|
padding: 0,
|
|
marginRight: 0,
|
|
zIndex: 401,
|
|
'&:hover, &:focus, &[data-hover]': {
|
|
outline: 'none',
|
|
background: 'transparent',
|
|
boxShadow: 'none',
|
|
},
|
|
'&:hover, &[data-hover]': {
|
|
svg: {
|
|
filter:
|
|
'drop-shadow(0 0 10px var(--chakra-colors-landing300))',
|
|
},
|
|
'path, circle': {
|
|
// fill: 'var(--chakra-colors-landing300)',
|
|
stroke: 'var(--chakra-colors-landing300)',
|
|
},
|
|
},
|
|
div: {
|
|
w: '99%',
|
|
h: '99%',
|
|
borderRadius: { base: '0.25rem', xl: '1rem', '4xl': 'full' },
|
|
transition: 'all 0.2s linear',
|
|
position: 'relative',
|
|
transformOrigin: '1px',
|
|
},
|
|
'path, circle': {
|
|
fill: menuToggle ? 'transparent' : 'transparent',
|
|
transition: noMotion ? 'none' : 'all 0.2s ease',
|
|
stroke: menuToggle ? 'landing600' : 'white',
|
|
},
|
|
'.top-line': {
|
|
transition: noMotion ? 'none' : 'all 0.6s ease',
|
|
transform: menuToggle
|
|
? 'rotate(-405deg) translate3d(1px, 3px, 0)'
|
|
: 'rotate(0)',
|
|
transformOrigin: 'center',
|
|
},
|
|
'.bottom-line': {
|
|
transition: noMotion ? 'none' : 'all 0.6s ease',
|
|
transform: menuToggle
|
|
? 'rotate(405deg) translate3d(0px, -4px, 0)'
|
|
: noMotion
|
|
? 'none'
|
|
: 'rotate(0)',
|
|
transformOrigin: 'center',
|
|
},
|
|
}}
|
|
>
|
|
<MenuIcon2SVG toggle={menuToggle} />
|
|
</Button>
|
|
</HStack>
|
|
</Flex>
|
|
</Box>
|
|
<Flex
|
|
flexFlow="column wrap"
|
|
position="fixed"
|
|
top={0}
|
|
right={{ base: 0 }}
|
|
left={{ base: 0, xl: 'unset' }}
|
|
align="center"
|
|
justify="center"
|
|
w={{ base: '100vw', xl: '100%' }}
|
|
h="100%"
|
|
overflow="hidden"
|
|
zIndex={200}
|
|
sx={{
|
|
opacity: menuToggle ? 1 : 0,
|
|
transform: menuToggle
|
|
? 'translate3d(0, 0, 0)'
|
|
: 'translate3d(0, -120%, 0)',
|
|
transition: noMotion
|
|
? 'none'
|
|
: 'transform 0.2s ease-in-out, opacity 0.2s 0.1s ease-in-out',
|
|
backgroundColor: 'landingDarkGlass',
|
|
backdropFilter: 'blur(7px)',
|
|
'.waveA, .waveB': {
|
|
animationPlayState: 'paused',
|
|
},
|
|
}}
|
|
>
|
|
<Stack
|
|
spacing={4}
|
|
direction={{ base: 'column', md: 'column' }}
|
|
opacity={menuToggle ? 1 : 0}
|
|
transition={noMotion ? 'none' : 'opacity 0.3s 0.5s ease-in-out'}
|
|
fontSize={{ base: 'md', md: 'lg', lg: '2xl' }}
|
|
zIndex={2}
|
|
>
|
|
<VStack spacing={4} alignItems="flex-start">
|
|
{sections.map((section, index) => (
|
|
<NavLink
|
|
key={index}
|
|
target={section.internalLinkId}
|
|
toggle={menuToggle}
|
|
setToggle={setMenuToggle}
|
|
>
|
|
{section.title}
|
|
</NavLink>
|
|
))}
|
|
</VStack>
|
|
<Socials />
|
|
</Stack>
|
|
<AnimatedWaves
|
|
animationName={upDownAnimation}
|
|
playing={noMotion ? false : menuToggle}
|
|
/>
|
|
<Box
|
|
position="absolute"
|
|
bottom={{ base: 3, xl: '0%' }}
|
|
left={-2}
|
|
w="100%"
|
|
h="25%"
|
|
bgImage={OctoBg.src}
|
|
backgroundSize={{ base: '30%', md: '20%', xl: '10%', '4xl': '8%' }}
|
|
backgroundPosition="bottom center"
|
|
backgroundRepeat="no-repeat"
|
|
opacity={0.5}
|
|
pointerEvents="none"
|
|
zIndex={200}
|
|
sx={{
|
|
animation: noMotion ? 'none' : upDownAnimation,
|
|
animationPlayState: menuToggle ? 'playing' : 'paused',
|
|
animationDuration: '5s',
|
|
filter: 'drop-shadow(0 0 20px #000)',
|
|
opacity: menuToggle ? 1 : noMotion ? 1 : 0,
|
|
transition: 'opacity 0.3s 0.2s ease-in-out',
|
|
}}
|
|
/>
|
|
</Flex>
|
|
|
|
<Box
|
|
position="fixed"
|
|
top={0}
|
|
left={0}
|
|
width="full"
|
|
alignItems="center"
|
|
justifyContent="center"
|
|
flexFlow="row nowrap"
|
|
py={1}
|
|
textAlign="center"
|
|
display={!noticeOpen ? 'none' : 'flex'}
|
|
backgroundColor="silver"
|
|
dropShadow={`0 0 10px black`}
|
|
color="dark"
|
|
zIndex={500}
|
|
>
|
|
<Text fontSize={{ base: 'xs', '2xl': 'sm' }}>
|
|
Anon, I noticed that you prefer reduced motion on websites & apps,
|
|
so disabled all unnecessary effects / animations for you. Hover on
|
|
links & buttons remain. Love, Nova{' '}
|
|
<span
|
|
title="Nova. See The Lore of MetaGame"
|
|
role="img"
|
|
className="gradient-text"
|
|
>
|
|
🐙
|
|
</span>{' '}
|
|
</Text>
|
|
<IconButton
|
|
icon={<MdClose />}
|
|
onClick={handleCloseNotice}
|
|
aria-label="close motion notice"
|
|
variant="ghost"
|
|
width={6}
|
|
height={6}
|
|
sx={{
|
|
'&:hover': {
|
|
color: 'var(--chakra-colors-landing500)',
|
|
backgroundColor: 'transparent',
|
|
},
|
|
}}
|
|
/>
|
|
</Box>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const NavLink = ({
|
|
children,
|
|
target,
|
|
toggle,
|
|
setToggle,
|
|
}: {
|
|
children: ReactNode;
|
|
target: string;
|
|
toggle: boolean;
|
|
setToggle: Dispatch<SetStateAction<boolean>>;
|
|
}) => (
|
|
<Link
|
|
px={2}
|
|
py={1}
|
|
href={`/#${target}`}
|
|
onClick={() => setToggle(!toggle)}
|
|
textAlign="center"
|
|
sx={{
|
|
background: 'linear-gradient(90deg, #FFF -29.22%, #FFF 107.53%)',
|
|
backgroundClip: 'text',
|
|
WebkitTextFillColor: 'transparent',
|
|
transition: 'backgroundImage 0.3s ease-in',
|
|
'&.active, &:hover': {
|
|
background: 'linear-gradient(90deg, #FF61E6 -29.22%, #7C56FF 107.53%)',
|
|
backgroundClip: 'text',
|
|
WebkitTextFillColor: 'transparent',
|
|
textDecor: 'none',
|
|
},
|
|
}}
|
|
>
|
|
{children}
|
|
</Link>
|
|
);
|
|
|
|
export const MenuIcon2SVG = ({ toggle }: { toggle: boolean }) => (
|
|
<Box>
|
|
<Box
|
|
as="svg"
|
|
w={{ base: '2.25rem', xl: '2.5rem', '4xl': '2.9rem' }}
|
|
position="absolute"
|
|
ml={0}
|
|
mt={0}
|
|
left={0}
|
|
bottom={0}
|
|
top={0}
|
|
transition="transform 0.5s ease"
|
|
transform={toggle ? 'rotate(-90deg)' : 'rotate(0)'}
|
|
preserveAspectRatio="xMidYMid meet"
|
|
viewBox="0 0 48 48"
|
|
>
|
|
<path
|
|
d="M46.8937 23.64C46.8937 36.4827 36.4827 46.8937 23.64 46.8937C10.7973 46.8937 0.386262 36.4827 0.386262 23.64C0.386262 10.7973 10.7973 0.386262 23.64 0.386262C36.4827 0.386262 46.8937 10.7973 46.8937 23.64Z"
|
|
stroke="white"
|
|
strokeOpacity={0.9}
|
|
strokeWidth={1}
|
|
/>
|
|
<path
|
|
d="M32.6262 20.7609L13.8833 20.7612"
|
|
className="top-line"
|
|
stroke="white"
|
|
strokeWidth={1}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
<path
|
|
d={
|
|
toggle
|
|
? 'M32.6258 27.5447L13.8835 27.5447'
|
|
: 'M26.7258 27.5447L13.8835 27.5447'
|
|
}
|
|
className="bottom-line"
|
|
stroke="white"
|
|
strokeWidth={1}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
);
|