123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- /**
- * Auto-Hide Navigation Script
- * Smoothly hides navigation when scrolling down and shows it when scrolling up
- */
- (function() {
- 'use strict';
-
- // Configuration
- const config = {
- scrollThreshold: 100, // Start hiding after this many pixels
- mouseRevealZone: 100, // Show header when mouse is within this many pixels from top
- animationDuration: 300, // Animation duration in ms
- debounceDelay: 10 // Scroll event debounce delay
- };
-
- // State management
- let state = {
- lastScrollTop: 0,
- isVisible: true,
- headerHeight: 0,
- ticking: false
- };
-
- // DOM elements
- let elements = {};
-
- // Initialize when DOM is ready
- document.addEventListener('DOMContentLoaded', init);
-
- function init() {
- // Find header elements - Twenty Twenty-Five specific selectors
- elements.header = document.querySelector('header') ||
- document.querySelector('.wp-site-header') ||
- document.querySelector('.wp-block-template-part[data-area="header"]') ||
- document.querySelector('.wp-block-group.is-layout-constrained') ||
- document.querySelector('[class*="header"]');
-
- elements.body = document.body;
-
- // Debug: Log found header element
- console.log('Auto-hide navigation: Header element found:', elements.header);
-
- if (!elements.header) {
- console.warn('Auto-hide navigation: No header element found');
- // Try to find any element that might be the header
- const possibleHeaders = document.querySelectorAll('nav, [class*="nav"], [class*="header"], [class*="menu"]');
- console.log('Possible header elements:', possibleHeaders);
- return;
- }
-
- // Add identifying class for our CSS
- elements.header.classList.add('srh-auto-hide-header');
-
- // Setup
- calculateHeaderHeight();
- bindEvents();
-
- // Initial state
- updateHeaderState();
-
- console.log('Auto-hide navigation initialized successfully');
- }
-
- function calculateHeaderHeight() {
- if (!elements.header) return;
-
- state.headerHeight = elements.header.offsetHeight || 80;
- document.documentElement.style.setProperty('--header-height', state.headerHeight + 'px');
- }
-
- function bindEvents() {
- // Scroll event with debouncing
- window.addEventListener('scroll', debounce(handleScroll, config.debounceDelay));
-
- // Resize event
- window.addEventListener('resize', debounce(calculateHeaderHeight, 100));
-
- // Mouse movement for revealing header
- document.addEventListener('mousemove', handleMouseMove);
-
- // Keyboard events for accessibility
- document.addEventListener('keydown', handleKeydown);
-
- // Focus events for accessibility
- if (elements.header) {
- const focusableElements = elements.header.querySelectorAll('a, button, input, textarea, select, [tabindex]');
- focusableElements.forEach(el => {
- el.addEventListener('focus', showHeader);
- });
- }
-
- // Smooth scroll for anchor links
- document.addEventListener('click', handleAnchorClick);
- }
-
- function handleScroll() {
- if (!state.ticking) {
- requestAnimationFrame(updateHeaderState);
- state.ticking = true;
- }
- }
-
- function updateHeaderState() {
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
-
- // Add scrolled class for styling
- if (scrollTop > 50) {
- elements.body.classList.add('header-offset');
- elements.header.classList.add('header-scrolled');
- } else {
- elements.body.classList.remove('header-offset');
- elements.header.classList.remove('header-scrolled');
- }
-
- // Hide/show logic
- if (scrollTop > config.scrollThreshold) {
- if (scrollTop > state.lastScrollTop && state.isVisible) {
- // Scrolling down - hide header
- hideHeader();
- } else if (scrollTop < state.lastScrollTop && !state.isVisible) {
- // Scrolling up - show header
- showHeader();
- }
- } else if (!state.isVisible) {
- // Near top - always show header
- showHeader();
- }
-
- state.lastScrollTop = scrollTop;
- state.ticking = false;
- }
-
- function hideHeader() {
- if (!state.isVisible) return;
-
- state.isVisible = false;
- elements.header.classList.remove('header-visible');
- elements.header.classList.add('header-hidden');
-
- // Dispatch custom event
- dispatchCustomEvent('headerHidden');
- }
-
- function showHeader() {
- if (state.isVisible) return;
-
- state.isVisible = true;
- elements.header.classList.remove('header-hidden');
- elements.header.classList.add('header-visible');
-
- // Dispatch custom event
- dispatchCustomEvent('headerVisible');
- }
-
- function handleMouseMove(e) {
- if (e.clientY < config.mouseRevealZone &&
- window.pageYOffset > config.scrollThreshold &&
- !state.isVisible) {
- showHeader();
- }
- }
-
- function handleKeydown(e) {
- // Show header on Tab or Escape for accessibility
- if (e.key === 'Tab' || e.key === 'Escape') {
- showHeader();
- }
- }
-
- function handleAnchorClick(e) {
- const link = e.target.closest('a[href^=\"#\"]');
- if (!link) return;
-
- const targetId = link.getAttribute('href').substring(1);
- const target = document.getElementById(targetId);
-
- if (target) {
- e.preventDefault();
-
- const offsetTop = target.getBoundingClientRect().top + window.pageYOffset - state.headerHeight;
-
- window.scrollTo({
- top: offsetTop,
- behavior: 'smooth'
- });
- }
- }
-
- function dispatchCustomEvent(eventName) {
- const event = new CustomEvent(eventName, {
- detail: {
- headerElement: elements.header,
- isVisible: state.isVisible,
- scrollTop: state.lastScrollTop
- }
- });
- document.dispatchEvent(event);
- }
-
- function debounce(func, wait) {
- let timeout;
- return function executedFunction(...args) {
- const later = () => {
- clearTimeout(timeout);
- func(...args);
- };
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- };
- }
-
- // Public API
- window.SRHNavigation = {
- show: showHeader,
- hide: hideHeader,
- toggle: function() {
- state.isVisible ? hideHeader() : showHeader();
- },
- getState: function() {
- return { ...state };
- },
- updateConfig: function(newConfig) {
- Object.assign(config, newConfig);
- }
- };
-
- })();
|