-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathHeader.astro
More file actions
165 lines (141 loc) · 4.69 KB
/
Header.astro
File metadata and controls
165 lines (141 loc) · 4.69 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
---
import NavItems from "@components/NavItems.astro";
import HeaderActions from "@components/header/header-actions.astro";
import HeaderLogo from "@components/header/header-logo.astro";
import Search from "@components/Search.astro";
import links from "@data/links.json";
---
<section
id="navbar"
>
<div
class="container max-w-[1150px] mx-auto px-6 py-2 mt-4 lg:p-2 lg:mt-6 flex items-center justify-between relative z-40 bg-white/80 rounded-full backdrop-blur-md shadow-lg"
>
<input
type="checkbox"
name="mobile-controls"
id="nav_toggle"
class="hidden peer"
aria-hidden="true"
/>
<HeaderLogo />
<nav class="hidden xl:block">
<NavItems items={links.header} />
</nav>
<HeaderActions />
<div
class="fixed bg-body-background top-0 left-0 w-screen h-screen overflow-scroll hidden peer-checked:block xl:peer-checked:hidden z-50 px-6 py-2"
>
<div class="flex items-center justify-between">
<HeaderLogo />
<HeaderActions mobile />
</div>
<nav class="mt-8">
<NavItems items={[...links.header]} />
</nav>
</div>
</div>
</section>
<Search />
<style>
#navbar {
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
transition: transform 0.3s ease-in-out;
transform: translateY(0);
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const navbar = document.getElementById("navbar") as HTMLElement;
if (!navbar) return;
let prevScrollPos = window.pageYOffset || document.documentElement.scrollTop;
let ticking = false;
let isVisible = true;
// Ensure navbar is visible initially
navbar.style.transform = "translateY(0)";
navbar.style.transition = "transform 0.3s ease-in-out";
function updateNavbar() {
// Handle iOS bounce - scroll position can be negative during bounce
const rawScrollPos = window.pageYOffset || document.documentElement.scrollTop;
const currentScrollPos = Math.max(0, rawScrollPos);
// Show navbar immediately if we're bouncing above the page (negative scroll)
// or if we're very close to the top
if (rawScrollPos <= 0 || currentScrollPos <= 50) {
if (!isVisible) {
navbar.style.transform = "translateY(0)";
isVisible = true;
}
prevScrollPos = currentScrollPos;
ticking = false;
return;
}
const documentHeight = document.documentElement.scrollHeight;
const windowHeight = window.innerHeight;
// Don't hide navbar when at the very bottom
if (currentScrollPos + windowHeight >= documentHeight - 50) {
if (!isVisible) {
navbar.style.transform = "translateY(0)";
isVisible = true;
}
prevScrollPos = currentScrollPos;
ticking = false;
return;
}
// Only update if scroll difference is significant
const scrollDiff = Math.abs(currentScrollPos - prevScrollPos);
if (scrollDiff < 3) {
ticking = false;
return;
}
// Show navbar when scrolling up, hide when scrolling down
if (prevScrollPos > currentScrollPos && !isVisible) {
navbar.style.transform = "translateY(0)";
isVisible = true;
} else if (prevScrollPos < currentScrollPos && isVisible && currentScrollPos > 100) {
navbar.style.transform = "translateY(-100%)";
isVisible = false;
}
prevScrollPos = currentScrollPos;
ticking = false;
}
function requestTick() {
if (!ticking) {
requestAnimationFrame(updateNavbar);
ticking = true;
}
}
// Use passive listener for better performance on mobile
window.addEventListener("scroll", requestTick, { passive: true });
// Additional safety check specifically for iOS bounce recovery
let bounceCheckTimeout: any = null;
window.addEventListener("scroll", function() {
// Clear any existing timeout
if (bounceCheckTimeout) {
clearTimeout(bounceCheckTimeout);
}
// Set a timeout to check position after scroll momentum stops
bounceCheckTimeout = setTimeout(() => {
const finalScrollPos = Math.max(0, window.pageYOffset || document.documentElement.scrollTop);
if (finalScrollPos <= 50 && !isVisible) {
navbar.style.transform = "translateY(0)";
isVisible = true;
prevScrollPos = finalScrollPos;
}
}, 150);
}, { passive: true });
// Handle page visibility changes (when switching tabs/apps)
document.addEventListener("visibilitychange", function() {
if (!document.hidden) {
const currentScrollPos = Math.max(0, window.pageYOffset || document.documentElement.scrollTop);
if (currentScrollPos <= 50) {
navbar.style.transform = "translateY(0)";
isVisible = true;
prevScrollPos = currentScrollPos;
}
}
});
});
</script>