Files
neuf-www/web/src/components/layout/Header.tsx
2024-08-11 10:51:46 +02:00

291 lines
8.8 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { usePathname, useRouter } from "next/navigation";
import Link from "next/link";
import styles from "./header.module.scss";
import { Logo, LogoIcon } from "@/components/general/Logo";
import { Icon } from "../general/Icon";
import { useInView } from "react-intersection-observer";
import { getSearchPath } from "@/lib/common";
export const Header = () => {
const { ref: observer, inView: isInView } = useInView({
triggerOnce: false,
initialInView: true,
});
const { replace } = useRouter();
const [showMenu, setShowMenu] = useState(false);
function toggleMenu() {
setShowMenu(!showMenu);
}
// remove ability to scroll when opening menu + keep previous scroll position when closing menu
useEffect(() => {
if (showMenu) {
const scrollY = window.scrollY;
document.body.style.position = "fixed";
document.body.style.top = `-${scrollY}px`;
} else {
const scrollY = parseInt(document.body.style.top || "0") * -1;
document.body.style.position = "";
document.body.style.top = "";
window.scrollTo(0, scrollY);
}
}, [showMenu]);
// reset scroll position on path change
useEffect(() => {
if (!showMenu) {
window.scrollTo(0, 0);
}
}, [location.pathname, showMenu]);
// hide menu and reset active menu item on path change
const pathname = usePathname();
useEffect(() => {
setShowMenu(false);
setActiveMenuItem(undefined);
}, [pathname]);
const [activeMenuItem, setActiveMenuItem] = useState<string | undefined>(
undefined
);
const handleSearch = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key != "Enter") {
return;
}
const query = e.currentTarget.value;
if (query) {
setShowMenu(false);
replace(getSearchPath(query));
}
};
return (
<>
<header
className={styles.header}
data-show={showMenu}
data-small={!isInView}
>
<Link href="/" aria-label="Hjem">
<Logo />
</Link>
<nav className={styles.siteMenu}>
<ul className={styles.mainMenu}>
<li>
<Link
href="/arrangementer"
data-active={pathname === "/arrangementer"}
>
Arrangementer
</Link>
</li>
<li>
<Link href="/praktisk" data-active={pathname === "/praktisk"}>
Praktisk info
</Link>
</li>
<li>
<Link href="/utleie" data-active={pathname === "/utleie"}>
Utleie
</Link>
</li>
<li>
<Link href="/medlem" data-active={pathname === "/medlem"}>
Bli medlem
</Link>
</li>
</ul>
<button
className={styles.toggleMenu}
aria-label="Vis meny"
onClick={toggleMenu}
>
<MenuIcon showMenu={showMenu} />
</button>
<div className={styles.fullMenu}>
<ul>
<li className={styles.menuItemLarge}>
<Link
href="/arrangementer"
data-active={pathname === "/arrangementer"}
>
Arrangementer
</Link>
</li>
<li className={styles.menuItemLarge}>
<Link href="/praktisk" data-active={pathname === "/praktisk"}>
Praktisk info
</Link>
</li>
<li className={styles.menuItemLarge}>
<Link href="/utleie" data-active={pathname === "/utleie"}>
Utleie
</Link>
</li>
<li className={styles.menuItemLarge}>
<Link href="/medlem" data-active={pathname === "/medlem"}>
Bli medlem
</Link>
</li>
<li className={styles.divider}>
<Link href="/aktuelt" data-active={pathname === "/aktuelt"}>
Siste nytt
</Link>
</li>
<li>
<Link href="/om" data-active={pathname === "/om"}>
Om oss
</Link>
</li>
<li>
<Link href="/kontakt" data-active={pathname === "/kontakt"}>
Kontakt
</Link>
</li>
<li>
<Link href="/frivillig" data-active={pathname === "/frivillig"}>
Bli frivillig
</Link>
</li>
<li>
{/* TODO: skal trolig ikke være så synlig ved lansering */}
<Link href="/foreninger">Foreninger</Link>
</li>
<li className={styles.galtinn}>
<a href="https://galtinn.neuf.no/" target="_blank">
<span>Mitt medlemskap</span>&nbsp;
<Icon type="externalLink" />
</a>
</li>
<li className={styles.search}>
<label htmlFor="search" className="sr-only">Søk</label>
<input
name="search"
type="text"
onKeyDown={handleSearch}
placeholder="Søk"
/>
<div className={styles.searchIcon}>
<Icon type="search" />
</div>
</li>
</ul>
</div>
</nav>
<div className={styles.headerBar} aria-hidden>
<Link href="/" aria-label="Hjem">
{!isInView ? <LogoIcon face="left" /> : <Logo />}
</Link>
<nav className={styles.siteMenu}>
<ul className={styles.mainMenu}>
<li>
<Link
href="/arrangementer"
data-active={pathname === "/arrangementer"}
>
Arrangementer
</Link>
</li>
<li>
<Link href="/praktisk" data-active={pathname === "/praktisk"}>
Praktisk info
</Link>
</li>
<li>
<Link href="/utleie" data-active={pathname === "/utleie"}>
Utleie
</Link>
</li>
<li>
<Link href="/medlem" data-active={pathname === "/medlem"}>
Bli medlem
</Link>
</li>
</ul>
<button
className={styles.toggleMenu}
aria-label="Vis meny"
onClick={toggleMenu}
>
<MenuIcon showMenu={showMenu} />
</button>
</nav>
</div>
<div className={styles.overlay} onClick={toggleMenu}></div>
</header>
<div className={styles.observer} ref={observer}></div>
</>
);
};
export const MenuIcon = ({ showMenu }: { showMenu: boolean }) => {
return (
<div className={styles.menuIcon}>
{showMenu ? (
<svg
viewBox="0 0 309 309"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M154.2 308.4C239.362 308.4 308.4 239.362 308.4 154.2C308.4 69.0377 239.362 0 154.2 0C69.0377 0 0 69.0377 0 154.2C0 239.362 69.0377 308.4 154.2 308.4Z"
fill="var(--color-menu-text)"
/>
<rect
x="101.964"
y="80.8135"
width="177.657"
height="29.9116"
transform="rotate(45 101.964 80.8135)"
fill="var(--color-menu-background)"
/>
<rect
x="227.586"
y="101.964"
width="177.657"
height="29.9116"
transform="rotate(135 227.586 101.964)"
fill="var(--color-menu-background)"
/>
</svg>
) : (
<svg
viewBox="0 0 309 309"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M154.2 308.4C239.362 308.4 308.4 239.362 308.4 154.2C308.4 69.0377 239.362 0 154.2 0C69.0377 0 0 69.0377 0 154.2C0 239.362 69.0377 308.4 154.2 308.4Z"
fill="var(--color-text)"
/>
<rect
x="65.3716"
y="139.244"
width="177.657"
height="29.9116"
fill="var(--color-background)"
/>
<rect
x="65.3716"
y="199.244"
width="177.657"
height="29.9116"
fill="var(--color-background)"
/>
<rect
x="65.3716"
y="79.2444"
width="177.657"
height="29.9116"
fill="var(--color-background)"
/>
</svg>
)}
</div>
);
};