Repository navigation
Expand file tree
/
Copy pathHeader.astro
More file actions
139 lines (130 loc) · 4.05 KB
/
Copy pathHeader.astro
File metadata and controls
139 lines (130 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
---
import { settingsQuery } from "@/lib/sanity/queries";
import NavLink from "./NavLink.astro";
import ThemeToggle from "./ThemeToggle.astro";
import SearchModal from "./SearchModal.astro";
const settings = await Astro.locals.sanity.loadQuery(settingsQuery);
const navLinks = settings?.navLinks ?? [];
// The Next header split these across a desktop <nav> and a mobile Sheet;
// `sideOnly` links appear only in the drawer.
const desktopLinks = navLinks.filter((link) => link?.sideOnly !== true);
---
<header
class="fixed left-0 right-0 top-0 z-40 flex items-center justify-between px-6 py-4 shadow-md bg-background"
>
<div class="flex items-center gap-4">
<a class="text-lg font-bold md:text-2xl" href="/">CodingCat.dev</a>
<nav class="items-center hidden md:flex gap-6" aria-label="Main">
{
desktopLinks.map((link) => (
<NavLink href={link?.path ?? "/"}>{link?.title}</NavLink>
))
}
</nav>
</div>
<div class="flex items-center gap-2">
<button
type="button"
id="search-header-trigger"
class="inline-flex items-center justify-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors border border-border/60 cursor-pointer"
aria-label="Search CodingCat.dev (⌘K)"
>
<svg
class="size-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
<span class="hidden md:inline-flex items-center text-[10px] font-mono bg-muted px-1.5 py-0.5 rounded border border-border">⌘K</span>
</button>
<ThemeToggle />
<button
type="button"
id="nav-drawer-toggle"
class="md:hidden inline-flex items-center justify-center rounded-md size-9 hover:bg-accent hover:text-accent-foreground transition-colors"
aria-controls="nav-drawer"
aria-expanded="false"
>
<svg
class="size-6"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M3 6h18M3 12h18M3 18h18"></path>
</svg>
<span class="sr-only">Toggle navigation menu</span>
</button>
</div>
</header>
<div
id="nav-drawer"
hidden
class="fixed inset-0 z-50 md:hidden bg-background/95 backdrop-blur"
>
<div class="flex items-center justify-end px-6 py-4">
<button
type="button"
id="nav-drawer-close"
class="inline-flex items-center justify-center rounded-md size-9 hover:bg-accent"
aria-label="Close navigation menu"
>
<svg
class="size-6"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M18 6 6 18M6 6l12 12"></path>
</svg>
</button>
</div>
<nav class="grid gap-2 px-6 py-6 text-lg" aria-label="Mobile">
{navLinks.map((link) => <NavLink href={link?.path ?? "/"}>{link?.title}</NavLink>)}
</nav>
</div>
<SearchModal />
<script>
const drawer = document.getElementById("nav-drawer");
const openButton = document.getElementById("nav-drawer-toggle");
const closeButton = document.getElementById("nav-drawer-close");
const searchTrigger = document.getElementById("search-header-trigger");
searchTrigger?.addEventListener("click", () => {
(window as unknown as { openSearchModal?: () => void }).openSearchModal?.();
});
const setOpen = (open: boolean) => {
if (!drawer) {
return;
}
drawer.hidden = !open;
openButton?.setAttribute("aria-expanded", String(open));
document.body.style.overflow = open ? "hidden" : "";
};
openButton?.addEventListener("click", () => setOpen(true));
closeButton?.addEventListener("click", () => setOpen(false));
drawer?.addEventListener("click", (event) => {
if (event.target instanceof HTMLAnchorElement) {
setOpen(false);
}
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && drawer && !drawer.hidden) {
setOpen(false);
}
});
</script>