Newer
Older
My-Portfolio / frontend / src / components / Header.jsx
import { useLocation, useNavigate } from "react-router-dom";
import { navigation } from "../constants";
import { HamburgerMenu } from "./design/Header";
import { useState } from "react";
import { disablePageScroll, enablePageScroll } from "scroll-lock";
import Button from "./Button";
import MenuSvg from "./../assets/svg/MenuSvg";

const Header = () => {
  const { hash, pathname } = useLocation();
  const navigate = useNavigate();
  const [openNavigation, setOpenNavigation] = useState(false);

  const toggleNavigation = () => {
    if (openNavigation) {
      setOpenNavigation(false);
      enablePageScroll();
    } else {
      setOpenNavigation(true);
      disablePageScroll();
    }
  };

  // Custom smooth scroll function
  const smoothScroll = (target, duration) => {
    const header = document.querySelector(".header");

    // Make sure header height is correctly calculated
    const headerHeight = header ? header.offsetHeight : 0;

    const targetPosition =
      target.getBoundingClientRect().top + window.scrollY - headerHeight; // Adjusted for header
    const startPosition = window.scrollY;
    const distance = targetPosition - startPosition;
    let startTime = null;

    const easeInOutQuad = (t, b, c, d) => {
      t /= d / 2;
      if (t < 1) return (c / 2) * t * t + b;
      t--;
      return (-c / 2) * (t * (t - 2) - 1) + b;
    };

    const animateScroll = (currentTime) => {
      if (startTime === null) startTime = currentTime;
      const timeElapsed = currentTime - startTime;
      const run = easeInOutQuad(timeElapsed, startPosition, distance, duration);

      window.scrollTo(0, run);

      if (timeElapsed < duration) {
        requestAnimationFrame(animateScroll);
      } else {
        window.scrollTo(0, targetPosition); // Ensure it reaches the target at the end
      }
    };

    requestAnimationFrame(animateScroll);
  };

  const handleClick = (event, url) => {
    event.preventDefault();
    enablePageScroll();
    setOpenNavigation(false);

    if (url.startsWith("/#")) {
      const sectionId = url.replace("/#", "");

      if (pathname === "/") {
        const section = document.getElementById(sectionId);
        if (section) {
          smoothScroll(section);
        } else {
          console.warn(`Section ${sectionId} not found!`);
        }
      } else {
        navigate("/", { replace: false });

        setTimeout(() => {
          const section = document.getElementById(sectionId);
          if (section) {
            smoothScroll(section);
          } else {
            console.warn(`Section ${sectionId} not found!`);
          }
        }, 500);
      }
    } else {
      navigate(url);
    }
  };

  return (
    <div
      className="
        w-screen
        fixed top-0
        z-50 
        border-b
        border-orange-400
        bg-black
        lg:backdrop-blur-sm header"
    >
      <div
        className="
        flex items-center 
        px-5 
        lg:px-7.5
        xl:px-10
        max-lg:py-4"
      >
        <nav
          className={` ${openNavigation ? "flex" : "hidden"}
        fixed 
        top-[4.8rem]
        left-0
        right-0
        bottom-0
        bg-black/80
        backdrop-blur-3xl
        lg:static
        lg:flex
        lg:mx-auto
        lg:bg-transparent`}
        >
          <div
            className="
            relative
            z-2
            flex
            flex-col
            items-center
            justify-center
            m-auto
            lg:flex-row"
          >
            {navigation.map((item) => (
              <a
                key={item.id}
                href={item.url}
                onClick={(event) => handleClick(event, item.url)}
                className={`block relative font-sans text-2xl font-bold lg:font-normal lg:text-xl uppercase text-n-1 
                    transition-colors hover:text-orange-400 ${
                      item.onlyMobile ? "lg:hidden" : ""
                    }
                    px-4 py-4 md:py-8 lg:mr-0.25 lg:2xl lf:font-semibold ${
                      item.url === hash
                        ? "z-2 lg:text-orange-400"
                        : "lg:text-n-1"
                    }
                    lg:leading-5 lg:hover:text-orange-400 xl:px-4
                    before:content-[''] before:absolute before:bottom-4 before:left-0 
                    before:w-full before:h-0.5 before:bg-orange-400 
                    before:origin-center before:scale-x-0 
                    before:transition-transform 
                    before:duration-300 
                    hover:before:w-full hover:before:scale-x-75
                  `}
              >
                {item.title}
              </a>
            ))}
          </div>

          <HamburgerMenu />
        </nav>

        <Button
          className="ml-auto lg:hidden"
          px="px-3"
          onClick={toggleNavigation}
        >
          <MenuSvg openNavigation={openNavigation} />
        </Button>
      </div>
    </div>
  );
};

export default Header;