src/components/layout/Header.astro 4.0 K raw
1
---
2
import { MENU_LINKS } from "@/data/constants";
3
4
const url = new URL(Astro.request.url);
5
---
6
7
<script>
8
	import { toggleClass } from "@/utils";
9
10
  class MobileNavBtn extends HTMLElement {
11
		constructor() {
12
			super();
13
			const headerEl = document.getElementById("main-header")!;
14
			const mobileButtonEl = document.getElementById("toggle-navigation-menu") as HTMLButtonElement;
15
			let menuOpen = false;
16
17
			function toggleMobileMenu() {
18
				toggleClass(headerEl, "menu-open");
19
				menuOpen = !menuOpen;
20
				mobileButtonEl.setAttribute("aria-expanded", menuOpen.toString());
21
			}
22
23
			mobileButtonEl.addEventListener("click", toggleMobileMenu);
24
25
			document.addEventListener("astro:after-swap", () => {
26
				if (menuOpen) toggleMobileMenu();
27
			});
28
		}
29
	}
30
31
	customElements.define("mobile-button", MobileNavBtn);
32
33
</script>
34
35
<header id="main-header" class="group relative mb-28 flex items-center justify-between sm:pl-[4.5rem]">
36
	<div class="flex sm:flex-col">
37
		<a
38
			href="/"
39
			class="inline-flex items-center sm:relative sm:inline-block"
40
			aria-current={url.pathname === "/" ? "page" : false}
41
      >
42
43
      <svg
44
        key="0"
45
        class="mr-3 h-10 w-6 sm:pb-4 sm:absolute sm:left-[-4.5rem] sm:mr-0 sm:h-20 sm:w-12"
46
        fill="none"
47
        stroke="currentColor"
48
        strokeLinecap="round"
49
        strokeLinejoin="round"
50
        strokeWidth="2"
51
        viewBox="0 0 24 24"
52
        xmlns="http://www.w3.org/2000/svg"
53
      >
54
        <path d="m8 3 4 8 5-5 5 15H2L8 3z" />
55
      </svg>
56
57
58
			<span class="text-xl font-bold sm:text-2xl">Steve Simkins</span>
59
		</a>
60
		<nav
61
			id="navigation-menu"
62
			class="absolute -inset-x-4 top-14 hidden flex-col items-end gap-y-4 rounded-md bg-[color:var(--theme-menu-bg)] py-4 text-accent shadow backdrop-blur group-[.menu-open]:z-50 group-[.menu-open]:flex sm:static sm:z-auto sm:mt-1 sm:-ml-4 sm:flex sm:flex-row sm:items-center sm:divide-x sm:divide-dashed sm:divide-accent sm:rounded-none sm:bg-transparent sm:py-0 sm:shadow-none sm:backdrop-blur-none"
63
			aria-label="Main menu"
64
		>
65
			{
66
				MENU_LINKS.map((link) => (
67
					<a
68
						href={link.path}
69
						class="py-4 px-4 sm:py-0 sm:hover:underline"
70
						aria-current={url.pathname === link.path ? "page" : false}
71
						rel="prefetch"
72
					>
73
						{link.title}
74
					</a>
75
				))
76
			}
77
		</nav>
78
	</div>
79
  <mobile-button>
80
    <button
81
        id="toggle-navigation-menu"
82
        class="group relative ml-8 h-7 w-7 sm:invisible sm:hidden"
83
        type="button"
84
        aria-label="Open main menu"
85
        aria-expanded="false"
86
        aria-haspopup="menu"
87
        >
88
        <svg
89
            id="line-svg"
90
            class="absolute top-1/2 left-1/2 h-full w-full -translate-x-1/2 -translate-y-1/2 transition-all group-aria-expanded:scale-0 group-aria-expanded:opacity-0"
91
            aria-hidden="true"
92
            focusable="false"
93
            xmlns="http://www.w3.org/2000/svg"
94
                   fill="none"
95
                         viewBox="0 0 24 24"
96
                                  stroke-width="1.5"
97
                                                stroke="currentColor"
98
                                                        >
99
                                                        <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9h16.5m-16.5 6.75h16.5"></path>
100
        </svg>
101
      <svg
102
          id="cross-svg"
103
          class="absolute top-1/2 left-1/2 h-full w-full -translate-x-1/2 -translate-y-1/2 scale-0 text-accent opacity-0 transition-all group-aria-expanded:scale-100 group-aria-expanded:opacity-100"
104
          class="text-accent"
105
          aria-hidden="true"
106
          focusable="false"
107
          xmlns="http://www.w3.org/2000/svg"
108
                 fill="none"
109
                       viewBox="0 0 24 24"
110
                                stroke-width="1.5"
111
                                              stroke="currentColor"
112
                                                      >
113
                                                      <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path>
114
      </svg>
115
    </button>
116
  </mobile-button>
117
118
</header>