Skip to content

Commit bc5c362

Browse files
committed
Fix mobile menu behavior
1 parent e9c3e1c commit bc5c362

File tree

4 files changed

+136
-18
lines changed

4 files changed

+136
-18
lines changed

docs/src/components/TopBar.astro

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,16 @@ showThemeSwitcher = (showThemeSwitcher === 'false') ? false : true;
1919
import './TopBar.css';
2020
---
2121
<script>
22+
import { ScrollNav } from '../javascript/scrollnav.js';
2223
import { $ } from '@semantic-ui/query';
23-
let scrollingDown;
24-
let lastScrollPosition;
25-
$(window).on('scroll', function() {
26-
const isMobile = $(window).width() < 768;
27-
const scrollTop = $('html').scrollTop();
28-
scrollingDown = Boolean(scrollTop >= lastScrollPosition);
29-
lastScrollPosition = scrollTop;
30-
requestAnimationFrame(() => {
31-
if(isMobile && scrollingDown && scrollTop !== 0) {
32-
$('topbar').addClass('hidden');
33-
}
34-
else {
35-
$('topbar').removeClass('hidden');
36-
}
37-
});
38-
}, { passive: true });
24+
console.log(ScrollNav);
25+
const nav = new ScrollNav($('topbar').el(),
26+
{
27+
deltaThreshold: 5,
28+
velocityThreshold: 15,
29+
hideClass: 'hidden'
30+
}
31+
);
3932
</script>
4033
<topbar class={floating ? 'floating' : 'fluid'} transition:persist>
4134
<div class="content">

docs/src/javascript/scrollnav.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
class ScrollNav {
2+
constructor(element, options = {}) {
3+
if (!(element instanceof Element)) {
4+
throw new Error('ScrollNav requires a DOM element');
5+
}
6+
7+
// Store element reference
8+
this.element = element;
9+
10+
// Configuration with defaults
11+
this.options = {
12+
deltaThreshold: 5,
13+
velocityThreshold: 15,
14+
hideClass: 'hidden',
15+
...options
16+
};
17+
18+
// State
19+
this.lastScrollY = window.scrollY;
20+
this.currentScrollY = window.scrollY;
21+
this.isVisible = true;
22+
this.isScrolling = false;
23+
this.scrollTimeout = null;
24+
this.ticking = false;
25+
26+
// Bind methods
27+
this.onScroll = this.onScroll.bind(this);
28+
this.update = this.update.bind(this);
29+
30+
// Initialize
31+
this.init();
32+
}
33+
34+
init() {
35+
// Initial state
36+
this.show();
37+
38+
// Attach scroll listener using passive event for performance
39+
window.addEventListener('scroll', this.onScroll, { passive: true });
40+
}
41+
42+
onScroll() {
43+
this.currentScrollY = window.scrollY;
44+
45+
// Only request animation frame if we're not already processing one
46+
if (!this.ticking) {
47+
requestAnimationFrame(this.update);
48+
this.ticking = true;
49+
}
50+
51+
// Reset scroll end timer
52+
clearTimeout(this.scrollTimeout);
53+
this.scrollTimeout = setTimeout(() => {
54+
this.isScrolling = false;
55+
}, 150);
56+
}
57+
58+
update() {
59+
// Calculate delta and velocity
60+
const delta = this.currentScrollY - this.lastScrollY;
61+
const velocity = Math.abs(delta);
62+
63+
// Only trigger if we've crossed our thresholds
64+
if (velocity > this.options.velocityThreshold &&
65+
Math.abs(delta) > this.options.deltaThreshold) {
66+
if (delta > 0) { // Scrolling down
67+
this.hide();
68+
} else { // Scrolling up
69+
this.show();
70+
}
71+
}
72+
73+
// Update state for next frame
74+
this.lastScrollY = this.currentScrollY;
75+
this.ticking = false;
76+
}
77+
78+
show() {
79+
if (!this.isVisible) {
80+
this.element.classList.remove(this.options.hideClass);
81+
this.isVisible = true;
82+
}
83+
}
84+
85+
hide() {
86+
if (this.isVisible) {
87+
this.element.classList.add(this.options.hideClass);
88+
this.isVisible = false;
89+
}
90+
}
91+
92+
destroy() {
93+
window.removeEventListener('scroll', this.onScroll);
94+
clearTimeout(this.scrollTimeout);
95+
}
96+
}
97+
98+
export { ScrollNav };

docs/src/layouts/Homepage.css

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
}
2727
li ui-icon[check] {
2828
color: var(--secondary-text-color);
29+
background-color: #eab59f1c;
30+
border-radius: var(--circular-radius);
31+
padding: 3px;
32+
height: 17px;
33+
font-size: 12px;
2934
}
3035

3136

@@ -129,6 +134,15 @@
129134
}
130135

131136

137+
&.offscreen {
138+
canvas {
139+
display: none;
140+
}
141+
142+
&:before {
143+
display: none;
144+
}
145+
}
132146

133147
}
134148

@@ -257,7 +271,7 @@
257271
background-position: 0% 0%;
258272
}
259273
100% {
260-
background-position: 0% -475px;
274+
background-position: 0% 475px;
261275
}
262276
}
263277

docs/src/pages/index.astro

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const code2=`
4242
<content>
4343
<ui-container>
4444
<div class="center">
45-
<h1>Web Components Ready for Scale</h1>
45+
<h1>Scalable Web Components</h1>
4646
<p>Build UI components with <b>web standards</b>, <b>signals-based reactivity</b>, and <b>zero abstraction cost</b>. Create truly <b>portable in house design systems</b> that work everywhere.</p>
4747
<ui-button primary icon-after icon="right-chevron" href="/learn/selection">Try In 5 Minutes</ui-button>
4848
<ui-button secondary href="/components">View Docs</ui-button>
@@ -54,6 +54,19 @@ const code2=`
5454
import { Gradient } from '../javascript/gradient.js'
5555
const gradient = new Gradient()
5656
gradient.initGradient('#gradient')
57+
const observer = new IntersectionObserver(
58+
(entries) => {
59+
entries.forEach(entry => {
60+
entry.target.classList.toggle('offscreen', !entry.isIntersecting);
61+
});
62+
},
63+
{
64+
threshold: 0,
65+
rootMargin: '0px'
66+
}
67+
);
68+
const el = document.querySelector('aboveFold');
69+
observer.observe(el);
5770
</script>
5871
<ribbons>
5972
<ribbon>

0 commit comments

Comments
 (0)