Implement auto-hiding sticky navbar on scroll and pointer-event safe smooth scroll
This commit is contained in:
+76
-31
@@ -380,6 +380,30 @@ export default function App({ previewMode = false }) {
|
||||
const [isCareersOpen, setIsCareersOpen] = useState(false);
|
||||
const [activeSection, setActiveSection] = useState('home');
|
||||
const [currentPage, setCurrentPage] = useState('home');
|
||||
const [navbarVisible, setNavbarVisible] = useState(true);
|
||||
const lastScrollY = useRef(0);
|
||||
|
||||
const smoothScrollTo = (top) => {
|
||||
document.body.style.pointerEvents = 'none';
|
||||
window.scrollTo({ top, behavior: 'smooth' });
|
||||
|
||||
let scrollTimeout;
|
||||
const handleScrollEnd = () => {
|
||||
document.body.style.pointerEvents = '';
|
||||
window.removeEventListener('scrollend', handleScrollEnd);
|
||||
window.removeEventListener('scroll', handleScrollDebounce);
|
||||
clearTimeout(scrollTimeout);
|
||||
};
|
||||
|
||||
const handleScrollDebounce = () => {
|
||||
clearTimeout(scrollTimeout);
|
||||
scrollTimeout = setTimeout(handleScrollEnd, 100);
|
||||
};
|
||||
|
||||
window.addEventListener('scrollend', handleScrollEnd);
|
||||
window.addEventListener('scroll', handleScrollDebounce);
|
||||
scrollTimeout = setTimeout(handleScrollEnd, 800);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const syncPageFromHash = () => {
|
||||
@@ -387,11 +411,11 @@ export default function App({ previewMode = false }) {
|
||||
if (hash === '#contact' || hash === '#contactus') {
|
||||
setCurrentPage('contact');
|
||||
setActiveSection('contactus');
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
smoothScrollTo(0);
|
||||
} else if (hash === '#about' || hash === '#aboutus') {
|
||||
setCurrentPage('about');
|
||||
setActiveSection('aboutus');
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
smoothScrollTo(0);
|
||||
} else if (hash === '#home' || hash === '') {
|
||||
setCurrentPage('home');
|
||||
}
|
||||
@@ -461,32 +485,49 @@ export default function App({ previewMode = false }) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (previewMode || currentPage === 'contact') return;
|
||||
if (previewMode) return;
|
||||
|
||||
let lastScroll = window.scrollY;
|
||||
|
||||
const handleScroll = () => {
|
||||
// If at top of the page, home is active
|
||||
if (window.scrollY < 100) {
|
||||
setActiveSection('home');
|
||||
return;
|
||||
const currentScroll = window.scrollY;
|
||||
const diff = currentScroll - lastScroll;
|
||||
|
||||
if (currentScroll <= 50) {
|
||||
setNavbarVisible(true);
|
||||
} else if (diff > 5 && currentScroll > 100) {
|
||||
setNavbarVisible(false);
|
||||
} else if (diff < -5) {
|
||||
setNavbarVisible(true);
|
||||
}
|
||||
|
||||
const sections = ['home', 'aboutus', 'services', 'whyus', 'products', 'insights', 'contactus'];
|
||||
const scrollPosition = window.scrollY + 120; // 120px offset for header height and visual center
|
||||
lastScroll = currentScroll;
|
||||
|
||||
// Special case: if scrolled down near the very bottom of the page, contactus is active
|
||||
if (window.scrollY > 300 && window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 100) {
|
||||
setActiveSection('contactus');
|
||||
return;
|
||||
}
|
||||
if (currentPage === 'home') {
|
||||
// If at top of the page, home is active
|
||||
if (currentScroll < 100) {
|
||||
setActiveSection('home');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const sectionId of sections) {
|
||||
const el = document.getElementById(sectionId);
|
||||
if (el) {
|
||||
const top = el.offsetTop;
|
||||
const height = el.offsetHeight;
|
||||
if (scrollPosition >= top && scrollPosition < top + height) {
|
||||
setActiveSection(sectionId);
|
||||
break;
|
||||
const sections = ['home', 'aboutus', 'services', 'whyus', 'products', 'insights', 'contactus'];
|
||||
const scrollPosition = currentScroll + 120; // 120px offset for header height and visual center
|
||||
|
||||
// Special case: if scrolled down near the very bottom of the page, contactus is active
|
||||
if (currentScroll > 300 && window.innerHeight + currentScroll >= document.documentElement.scrollHeight - 100) {
|
||||
setActiveSection('contactus');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const sectionId of sections) {
|
||||
const el = document.getElementById(sectionId);
|
||||
if (el) {
|
||||
const top = el.offsetTop;
|
||||
const height = el.offsetHeight;
|
||||
if (scrollPosition >= top && scrollPosition < top + height) {
|
||||
setActiveSection(sectionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,7 +536,7 @@ export default function App({ previewMode = false }) {
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
handleScroll(); // run once on mount
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, [previewMode]);
|
||||
}, [previewMode, currentPage]);
|
||||
|
||||
const getActiveNavItem = () => {
|
||||
if (currentPage === 'contact') return 'Contact Us';
|
||||
@@ -548,15 +589,16 @@ export default function App({ previewMode = false }) {
|
||||
const el = document.getElementById(sectionId);
|
||||
if (el) {
|
||||
const top = el.getBoundingClientRect().top + window.scrollY - NAV_OFFSET;
|
||||
window.scrollTo({ top, behavior: 'smooth' });
|
||||
smoothScrollTo(top);
|
||||
setActiveSection(sectionId);
|
||||
} else if (sectionId === 'contactus') {
|
||||
window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' });
|
||||
smoothScrollTo(document.documentElement.scrollHeight);
|
||||
setActiveSection('contactus');
|
||||
}
|
||||
};
|
||||
|
||||
const handleNavClick = (item) => {
|
||||
setNavbarVisible(true);
|
||||
setMobileMenuOpen(false);
|
||||
if (item === 'Careers') {
|
||||
setIsCareersOpen(true);
|
||||
@@ -567,7 +609,7 @@ export default function App({ previewMode = false }) {
|
||||
setCurrentPage('contact');
|
||||
setActiveSection('contactus');
|
||||
window.location.hash = 'contact';
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
smoothScrollTo(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -575,7 +617,7 @@ export default function App({ previewMode = false }) {
|
||||
setCurrentPage('about');
|
||||
setActiveSection('aboutus');
|
||||
window.location.hash = 'aboutus';
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
smoothScrollTo(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -587,14 +629,14 @@ export default function App({ previewMode = false }) {
|
||||
|
||||
const doScroll = (sectionId) => {
|
||||
if (!sectionId || sectionId === 'home') {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
smoothScrollTo(0);
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
const el = document.getElementById(sectionId);
|
||||
if (el) {
|
||||
const top = el.getBoundingClientRect().top + window.scrollY - NAV_OFFSET;
|
||||
window.scrollTo({ top, behavior: 'smooth' });
|
||||
smoothScrollTo(top);
|
||||
setActiveSection(sectionId);
|
||||
}
|
||||
});
|
||||
@@ -695,9 +737,12 @@ export default function App({ previewMode = false }) {
|
||||
|
||||
{/* Navigation Bar */}
|
||||
<nav className="glass site-nav" style={{
|
||||
position: 'sticky', top: 0, zIndex: 50,
|
||||
position: 'sticky',
|
||||
top: navbarVisible ? 0 : (isMobile ? '-72px' : '-88px'),
|
||||
zIndex: 50,
|
||||
padding: isMobile ? '0.85rem 1.25rem' : '1.2rem 4rem',
|
||||
borderBottom: activeSection === 'products' ? '1px solid rgba(15, 23, 42, 0.08)' : '1px solid rgba(255, 255, 255, 0.05)'
|
||||
borderBottom: activeSection === 'products' ? '1px solid rgba(15, 23, 42, 0.08)' : '1px solid rgba(255, 255, 255, 0.05)',
|
||||
transition: 'top 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-bottom 0.3s ease, padding 0.3s ease'
|
||||
}}>
|
||||
<div style={{ maxWidth: '1440px', margin: '0 auto', width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user