Header.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import Link from 'next/link'
  2. import { useRouter } from 'next/router'
  3. import { useContext, useEffect, useState } from 'react'
  4. import { ClusterContext, DEFAULT_CLUSTER } from '../../contexts/ClusterContext'
  5. import Pyth from '../../images/logomark.inline.svg'
  6. import MobileMenu from './MobileMenu'
  7. export interface BurgerState {
  8. initial: boolean | null
  9. opened: boolean | null
  10. }
  11. function Header() {
  12. const { cluster } = useContext(ClusterContext)
  13. const router = useRouter()
  14. const [isSticky, setIsSticky] = useState(false)
  15. const navigation = [
  16. {
  17. name: 'Main',
  18. href: `/${cluster === DEFAULT_CLUSTER ? '' : `?cluster=${cluster}`}`,
  19. target: '_self',
  20. },
  21. {
  22. name: 'Pyth Network',
  23. href: 'https://pyth.network/',
  24. target: '_blank',
  25. },
  26. ]
  27. const [headerState, setHeaderState] = useState<BurgerState>({
  28. initial: false,
  29. opened: null,
  30. })
  31. // Toggle menu
  32. const handleToggleMenu = () => {
  33. if (headerState.initial === false) {
  34. setHeaderState({
  35. initial: null,
  36. opened: true,
  37. })
  38. } else {
  39. setHeaderState({
  40. ...headerState,
  41. opened: !headerState.opened,
  42. })
  43. }
  44. }
  45. useEffect(() => {
  46. window.addEventListener('scroll', ifSticky)
  47. return () => {
  48. window.removeEventListener('scroll', ifSticky)
  49. }
  50. })
  51. const ifSticky = () => {
  52. const scrollTop = window.scrollY
  53. if (!headerState.opened) {
  54. scrollTop >= 250 ? setIsSticky(true) : setIsSticky(false)
  55. }
  56. }
  57. return (
  58. <>
  59. <header
  60. className={`left-0 top-0 z-40 w-full px-1 transition-all lg:px-10
  61. ${isSticky || headerState.opened ? 'fixed ' : 'absolute'}
  62. ${isSticky && !headerState.opened ? 'bg-darkGray shadow-black' : ''}
  63. `}
  64. >
  65. <div
  66. className={`relative flex items-center justify-between ${
  67. isSticky ? 'lg:py-4' : 'before:gradient-border md:py-6'
  68. }
  69. ${
  70. !headerState.opened
  71. ? 'px-4 py-3 lg:px-10 lg:py-6'
  72. : 'sm:px-4 sm:py-3 sm:lg:px-10 sm:lg:py-6'
  73. }
  74. `}
  75. >
  76. <Link href="/">
  77. <a
  78. className={`basis-7 ${
  79. headerState.opened &&
  80. 'fixed left-5 top-3 sm:relative sm:left-0 sm:top-0'
  81. }`}
  82. >
  83. <Pyth />
  84. </a>
  85. </Link>
  86. <nav>
  87. <ul
  88. className={`hidden list-none lg:flex ${
  89. headerState.opened && 'hidden'
  90. }`}
  91. >
  92. {navigation.map((item) => (
  93. <li key={item.name}>
  94. <Link href={item.href}>
  95. <a
  96. className={`px-6 text-sm leading-none tracking-wide transition-colors hover:text-white lg:px-6 xl:px-8 ${
  97. router.pathname === item.href
  98. ? 'text-white'
  99. : 'text-light'
  100. }`}
  101. aria-current={
  102. router.pathname === item.href ? 'page' : undefined
  103. }
  104. target={item.target}
  105. >
  106. {item.name}
  107. </a>
  108. </Link>
  109. </li>
  110. ))}
  111. </ul>
  112. </nav>
  113. <div
  114. className={`basis-7 ${
  115. headerState.opened &&
  116. 'fixed right-5 top-[20px] sm:relative sm:left-0 sm:top-0'
  117. }`}
  118. onClick={handleToggleMenu}
  119. >
  120. <button className="group ml-auto block lg:hidden">
  121. <span
  122. className={`ml-auto block h-0.5 w-3.5 rounded-sm bg-light transition-all lg:group-hover:w-5 ${
  123. headerState.opened
  124. ? 'mb-0 w-5 translate-y-1 rotate-45'
  125. : 'mb-1'
  126. }`}
  127. ></span>
  128. <span
  129. className={`mb-1 block h-0.5 w-5 rounded-sm bg-light transition-all ${
  130. headerState.opened && 'opacity-0'
  131. }`}
  132. ></span>
  133. <span
  134. className={`ml-auto block h-0.5 w-3.5 rounded-sm bg-light transition-all lg:group-hover:w-5 ${
  135. headerState.opened
  136. ? 'mb-0 w-5 -translate-y-1 -rotate-45'
  137. : 'mb-1'
  138. }`}
  139. ></span>
  140. </button>
  141. </div>
  142. </div>
  143. </header>
  144. <MobileMenu headerState={headerState} setHeaderState={setHeaderState} />
  145. </>
  146. )
  147. }
  148. export default Header