imnya.ng/src/components/Header.astro
imnyang 5403448f63
Some checks failed
/ print-content (push) Failing after 1m41s
wow
2026-09-09 14:39:30 +09:00

117 lines
4.3 KiB
Text

---
const navigationItems = [
{ label: "Home", href: "#home" },
{ label: "About", href: "#about" },
{ label: "Projects", href: "#projects" },
{ label: "Experience", href: "#experience" },
{ label: "Carrer", href: "#carrer" },
{ label: "Contact", href: "#contact" },
] as const;
const desktopLinkClass =
"text-foreground no-underline transition-opacity duration-150 hover:opacity-55 focus-visible:opacity-55";
const mobileLinkClass =
"block rounded-xl px-3 py-2 text-sm font-semibold text-foreground no-underline transition-colors hover:bg-foreground/5";
---
<header
data-node-id="43:26"
class="fixed inset-x-0 top-0 z-50 flex h-[64px] items-center justify-between overflow-clip border-b border-foreground/[0.06] bg-background/90 px-[clamp(26px,2.5vw,48px)] backdrop-blur-xl transition-colors duration-300 max-md:overflow-visible max-md:px-6"
>
<a
class="shrink-0 text-2xl font-bold leading-[normal] text-foreground no-underline max-md:text-xl"
href="#home"
data-node-id="43:28"
>
@imnya.ng
</a>
<div id="navigation" class="relative flex shrink-0 items-center">
<nav
class="flex shrink-0 items-center gap-4 whitespace-nowrap text-base font-semibold leading-[1.5] tracking-[-0.02em] max-md:hidden"
aria-label="주요 메뉴"
data-node-id="43:40"
>
{navigationItems.map((item) => (
<a class={desktopLinkClass} href={item.href}>
{item.label}
</a>
))}
</nav>
<button
id="menu-toggle"
type="button"
class="relative hidden h-10 w-10 items-center justify-center rounded-full text-foreground transition-colors hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-foreground max-md:flex"
aria-label="메뉴 열기"
aria-controls="mobile-nav"
aria-expanded="false"
>
<span class="sr-only">메뉴</span>
<span
aria-hidden="true"
class="absolute h-px w-5 -translate-y-1.5 bg-foreground"
></span>
<span
aria-hidden="true"
class="absolute h-px w-5 bg-foreground"
></span>
<span
aria-hidden="true"
class="absolute h-px w-5 translate-y-1.5 bg-foreground"
></span>
</button>
<nav
id="mobile-nav"
class="absolute right-0 top-[calc(100%+12px)] z-50 hidden min-w-40 flex-col gap-1 rounded-2xl border border-border bg-background p-2 shadow-[0_12px_30px_rgba(0,0,0,0.18)] md:hidden"
aria-label="모바일 메뉴"
>
{navigationItems.map((item) => (
<a class={mobileLinkClass} href={item.href}>
{item.label}
</a>
))}
</nav>
</div>
</header>
<script>
const menuToggle =
document.querySelector<HTMLButtonElement>("#menu-toggle");
const mobileNav = document.querySelector<HTMLElement>("#mobile-nav");
const navigation = document.querySelector<HTMLElement>("#navigation");
if (menuToggle && mobileNav && navigation) {
const setMenuOpen = (isOpen: boolean) => {
mobileNav.classList.toggle("hidden", !isOpen);
mobileNav.classList.toggle("flex", isOpen);
menuToggle.setAttribute("aria-expanded", String(isOpen));
menuToggle.setAttribute(
"aria-label",
isOpen ? "메뉴 닫기" : "메뉴 열기",
);
};
menuToggle.addEventListener("click", () => {
setMenuOpen(menuToggle.getAttribute("aria-expanded") !== "true");
});
mobileNav.addEventListener("click", (event) => {
if (event.target instanceof HTMLAnchorElement) setMenuOpen(false);
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") setMenuOpen(false);
});
document.addEventListener("click", (event) => {
if (
event.target instanceof Node &&
!navigation.contains(event.target)
) {
setMenuOpen(false);
}
});
}
</script>