diff --git a/src/components/common/footer/footer.module.scss b/src/components/common/footer/footer.module.scss
index 9887fb0..46f7e88 100644
--- a/src/components/common/footer/footer.module.scss
+++ b/src/components/common/footer/footer.module.scss
@@ -30,15 +30,15 @@
top: 50%;
left: 50%;
width: 100%;
- height: 100%;
+ height: 101%;
content: '';
transform: translate(-50%, -50%);
pointer-events: none;
background: linear-gradient(
0deg,
- black 15%,
+ var(--color-black) 15%,
rgb(9 9 121 / 0) 50%,
- black 100%
+ var(--color-black) 100%
);
@media screen and (max-width: 800px) {
content: normal;
@@ -51,7 +51,7 @@
background: radial-gradient(
ellipse farthest-corner at center center,
rgb(4 4 4 / 0.05) 45%,
- #000 0
+ var(--color-black) 0
);
filter: blur(tovw(80px, 'default', 40px));
}
diff --git a/src/components/common/header/header.module.scss b/src/components/common/header/header.module.scss
index 2e5141f..94105c3 100644
--- a/src/components/common/header/header.module.scss
+++ b/src/components/common/header/header.module.scss
@@ -2,7 +2,7 @@
.header {
position: fixed;
- z-index: 10;
+ z-index: 20;
display: flex;
align-items: center;
justify-content: space-between;
@@ -25,10 +25,123 @@
margin: 0 0 0 tovw(122px, 'default', 90px);
padding: 0;
list-style-type: none;
- gap: tovw(32px, 'default', 20px);
+ gap: tovw(32px, 'default', 16px);
+ }
+
+ li:not(.item--mobile) {
+ position: relative;
+
+ &::after {
+ position: absolute;
+ top: 50%;
+ left: tovw(-16px, 'default', -16px);
+ width: tovw(7px, 'default', 7px);
+ height: tovw(7px, 'default', 7px);
+ content: '';
+ transition: opacity var(--normal-transition);
+ transform: translateY(-50%);
+ opacity: 0;
+ background: var(--color-white);
+ }
+ }
+
+ li.active {
+ &::after {
+ opacity: 1;
+ }
}
.burger {
- width: tovw(22px, 'default', 22px);
+ width: tovw(28px, 'default', 28px);
+ }
+
+ &__mobile {
+ position: fixed;
+ z-index: 10;
+ top: tovw(75px, 'mobile');
+ right: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: calc(100 * var(--vh) - tovw(75px, 'mobile'));
+ padding: tovw(16px, 'mobile');
+ background-color: var(--color-black);
+ background-image: linear-gradient(
+ 180deg,
+ rgb(0 0 244 / 0) 1.63%,
+ rgb(0 0 244 / 0.9) 81.47%
+ );
+
+ ul {
+ flex-direction: column;
+ margin: 0;
+ padding: 0;
+ }
+
+ a {
+ font-size: tovw(50px, 'mobile');
+ letter-spacing: tovw(-1px, 'mobile');
+ opacity: 0.6;
+
+ @media screen and (max-height: 750px) {
+ font-size: calc(var(--vh) * 5.2);
+ }
+ }
+
+ li.active {
+ a {
+ opacity: 1;
+ }
+ }
+
+ svg {
+ display: block;
+ }
+
+ button {
+ width: 100%;
+ margin: tovw(59px, 'mobile') 0 tovw(44px, 'mobile') 0;
+
+ @media screen and (max-height: 750px) {
+ margin: calc(var(--vh) * 7.2) 0 calc(var(--vh) * 5.2) 0;
+ }
+ }
+
+ p {
+ text-align: center;
+ }
+
+ .social {
+ position: relative;
+ display: grid;
+ justify-content: center;
+ width: 100%;
+ margin: tovw(32px, 'mobile') 0;
+ padding-top: tovw(32px, 'mobile');
+ grid-template-columns: repeat(6, tovw(24px, 'mobile'));
+ gap: tovw(24px, 'mobile');
+
+ &::after {
+ position: absolute;
+ top: tovw(-32px, 'mobile');
+ left: tovw(-16px, 'mobile');
+ width: calc(100% + tovw(32px, 'mobile'));
+ height: tovw(1px, 'mobile', 1px);
+ margin: tovw(24px, 'mobile') 0;
+ content: '';
+ background: white;
+ }
+
+ li,
+ a {
+ display: block;
+ width: tovw(24px, 'default', 24px);
+ height: tovw(24px, 'default', 24px);
+ }
+
+ a {
+ opacity: 1;
+ }
+ }
}
}
diff --git a/src/components/common/header/index.tsx b/src/components/common/header/index.tsx
index 317d1c5..8977e45 100644
--- a/src/components/common/header/index.tsx
+++ b/src/components/common/header/index.tsx
@@ -1,15 +1,103 @@
import clsx from 'clsx'
import NextLink from 'next/link'
+import { useRouter } from 'next/router'
+import * as React from 'react'
import Burger from '~/components/icons/burguer'
import { Logo } from '~/components/icons/logo'
import { Button } from '~/components/primitives/button'
import Link from '~/components/primitives/link'
+import { useIsomorphicLayoutEffect } from '~/hooks/use-isomorphic-layout-effect'
+import { DURATION, gsap } from '~/lib/gsap'
+import { ConnectLinks } from '../footer/footer'
import { defaultHeaderLinks } from './header'
import s from './header.module.scss'
+const HeaderMobile = React.forwardRef<
+ HTMLDivElement,
+ JSX.IntrinsicElements['div']
+>(({ className, ...props }, ref) => {
+ const router = useRouter()
+
+ const isActive = (href: string) => router.pathname === href
+ return (
+
+
+ {defaultHeaderLinks.length > 0 &&
+ defaultHeaderLinks.map((link, index) => (
+ -
+
+ {link.title}
+
+
+ ))}
+
+
+
+ {ConnectLinks.length > 0 &&
+ ConnectLinks.map((link, index) => (
+ -
+
+ {link.title}
+ {link.logo && link.logo}
+
+
+ ))}
+
+
Laconic, The Source of Proof
+
+ )
+})
+
export const Header = () => {
+ const [isOpen, setIsOpen] = React.useState(false)
+ const headerMobileRef = React.useRef(null)
+ const timelineRef = React.useRef()
+ const router = useRouter()
+
+ const isActive = (href: string) => router.pathname === href
+
+ useIsomorphicLayoutEffect(() => {
+ if (!headerMobileRef.current) return
+
+ const navigationItems =
+ headerMobileRef.current.querySelectorAll('.items li')
+ const socialItems = headerMobileRef.current.querySelectorAll('.social li')
+ const button = headerMobileRef.current.querySelector('button')
+ const text = headerMobileRef.current.querySelector('p')
+
+ timelineRef.current = gsap.timeline({
+ paused: true,
+ smoothChildTiming: true
+ })
+ timelineRef.current.fromTo(
+ headerMobileRef.current,
+ {
+ xPercent: 100
+ },
+ { xPercent: 0, duration: DURATION }
+ )
+ timelineRef.current.fadeIn([navigationItems, button, socialItems, text]),
+ '>-40%'
+ }, [])
+
+ useIsomorphicLayoutEffect(() => {
+ if (isOpen) {
+ gsap.set('body, html', { overflowY: 'hidden' })
+ timelineRef.current?.timeScale(1).play()
+ } else {
+ gsap.set('body, html', { overflowY: 'auto' })
+ timelineRef.current?.timeScale(1.5).reverse()
+ }
+ }, [isOpen])
+
return (
)
}
diff --git a/src/components/icons/burguer.tsx b/src/components/icons/burguer.tsx
index f955798..ba06cf5 100644
--- a/src/components/icons/burguer.tsx
+++ b/src/components/icons/burguer.tsx
@@ -1,16 +1,95 @@
-const Burger = ({ className, fill }: { className?: string; fill?: string }) => {
+import * as React from 'react'
+
+import { useIsomorphicLayoutEffect } from '~/hooks/use-isomorphic-layout-effect'
+import { gsap } from '~/lib/gsap'
+
+const Burger = ({
+ className,
+ fill,
+ isOpen
+}: {
+ className?: string
+ fill?: string
+ isOpen: boolean
+}) => {
+ const timelineRef = React.useRef()
+ const topRef = React.useRef(null)
+ const middleRef = React.useRef(null)
+ const bottomRef = React.useRef(null)
+
+ useIsomorphicLayoutEffect(() => {
+ timelineRef.current = gsap.timeline({
+ paused: true,
+ reversed: true,
+ smoothChildTiming: true
+ })
+
+ timelineRef.current.to(topRef.current, {
+ y: -4,
+ transformOrigin: '50% 50%'
+ })
+ timelineRef.current.to(
+ bottomRef.current,
+ {
+ y: 4,
+ transformOrigin: '50% 50%'
+ },
+ '<'
+ )
+ timelineRef.current.to(
+ middleRef.current,
+ {
+ scale: 0.1,
+ transformOrigin: '50% 50%'
+ },
+ '<'
+ )
+ timelineRef.current.add('rotate')
+ timelineRef.current.to(topRef.current, { y: 6 }, 'rotate')
+ timelineRef.current.to(bottomRef.current, { y: -6 }, 'rotate')
+ timelineRef.current.to(
+ topRef.current,
+ { rotationZ: 45, transformOrigin: '50% 50%' },
+ 'rotate'
+ )
+ timelineRef.current.to(
+ bottomRef.current,
+ { rotationZ: -45, transformOrigin: '50% 50%' },
+ 'rotate'
+ )
+
+ timelineRef.current.timeScale(2.23)
+
+ return () => {
+ timelineRef.current?.kill()
+ }
+ }, [])
+
+ useIsomorphicLayoutEffect(() => {
+ if (isOpen) {
+ timelineRef.current?.play()
+ } else {
+ timelineRef.current?.reverse()
+ }
+ }, [isOpen])
+
return (
)
}
diff --git a/src/components/icons/socials.tsx b/src/components/icons/socials.tsx
index 447bbc3..f193386 100644
--- a/src/components/icons/socials.tsx
+++ b/src/components/icons/socials.tsx
@@ -1,3 +1,5 @@
+import { useReactId } from '~/hooks/use-react-id'
+
const Telegram = ({
className,
fill
@@ -5,6 +7,7 @@ const Telegram = ({
className?: string
fill?: string
}) => {
+ const id = useReactId()
return (
-
+
@@ -42,6 +45,7 @@ const Twitter = ({
className?: string
fill?: string
}) => {
+ const id = useReactId()
return (
@@ -71,6 +75,7 @@ const Twitter = ({
}
const Reddit = ({ className, fill }: { className?: string; fill?: string }) => {
+ const id = useReactId()
return (
@@ -132,6 +137,8 @@ const Facebook = ({
className?: string
fill?: string
}) => {
+ const id = useReactId()
+
return (
@@ -167,6 +174,7 @@ const Instagram = ({
className?: string
fill?: string
}) => {
+ const id = useReactId()
return (
diff --git a/src/components/primitives/button/button.module.scss b/src/components/primitives/button/button.module.scss
index 78bf377..2320477 100644
--- a/src/components/primitives/button/button.module.scss
+++ b/src/components/primitives/button/button.module.scss
@@ -39,4 +39,15 @@
&--small {
padding: tovw(11.5px, 'default', 11.5px) tovw(24px, 'default', 10px);
}
+
+ &--unstyled {
+ border: none;
+ padding: tovw(12px, 'default', 12px);
+ background: none;
+
+ &:hover {
+ background: none;
+ color: currentcolor;
+ }
+ }
}
diff --git a/src/components/primitives/button/index.tsx b/src/components/primitives/button/index.tsx
index 198d9f9..dc4a8c5 100644
--- a/src/components/primitives/button/index.tsx
+++ b/src/components/primitives/button/index.tsx
@@ -9,7 +9,7 @@ import s from './button.module.scss'
export type ButtonProps = JSX.IntrinsicElements['button'] & {
size?: 'small' | 'medium' | 'large'
- variant?: 'default' | 'primary'
+ variant?: 'default' | 'primary' | 'unstyled'
}
export const Button = React.forwardRef(
diff --git a/src/components/sections/homepage/hero/hero.module.scss b/src/components/sections/homepage/hero/hero.module.scss
index 72e90a4..6665359 100644
--- a/src/components/sections/homepage/hero/hero.module.scss
+++ b/src/components/sections/homepage/hero/hero.module.scss
@@ -27,15 +27,15 @@
top: 50%;
left: 50%;
width: 100%;
- height: 100%;
+ height: 101%;
content: '';
transform: translate(-50%, -50%);
pointer-events: none;
background: linear-gradient(
0deg,
- black 15%,
+ var(--color-black) 15%,
rgb(9 9 121 / 0) 50%,
- black 100%
+ var(--color-black) 100%
);
@supports (aspect-ratio: 16 / 9) {
aspect-ratio: 16 / 9;
@@ -51,7 +51,7 @@
background: radial-gradient(
ellipse farthest-corner at center center,
rgb(4 4 4 / 0.25) 45%,
- #000 0
+ var(--color-black) 0
);
filter: blur(tovw(80px, 'default', 40px));
}
diff --git a/src/css/global.scss b/src/css/global.scss
index 7a3e145..b6b2d63 100644
--- a/src/css/global.scss
+++ b/src/css/global.scss
@@ -18,6 +18,7 @@
--color-black: #040404;
--color-white: #fbfbfb;
--color-grey-light: #8e8e8e;
+ --color-grey-lightness: #dedede;
// Duration
--duration-normal: 0.525s;