291 lines
8.8 KiB
TypeScript
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>
|
|
<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>
|
|
);
|
|
};
|