|
@@ -0,0 +1,228 @@
|
|
|
+/**
|
|
|
+ * 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);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+})();
|