auto-hide-nav.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /**
  2. * SRH Auto-Hide Navigation
  3. * Hides header when scrolling down, shows when scrolling up
  4. */
  5. (function($) {
  6. 'use strict';
  7. // Configuration
  8. const config = {
  9. scrollThreshold: 100, // Start hiding after this many pixels
  10. mouseRevealZone: 100, // Show header when mouse is within this many pixels from top
  11. animationDuration: 300, // Animation duration in ms
  12. debounceDelay: 10 // Scroll event debounce delay
  13. };
  14. // State management
  15. let state = {
  16. lastScrollTop: 0,
  17. isVisible: true,
  18. headerHeight: 0,
  19. ticking: false
  20. };
  21. // DOM elements
  22. let $header, $body;
  23. const headerSelectors = 'header, .srh-auto-hide-header, .wp-site-header, .wp-block-template-part[data-area="header"]';
  24. // Initialize when document is ready
  25. $(document).ready(function() {
  26. init();
  27. });
  28. function init() {
  29. // console.log('Auto-hide navigation: jQuery script loaded');
  30. // Find header elements - Try multiple selectors for Twenty Twenty-Five
  31. $header = $(headerSelectors).first();
  32. $body = $('body');
  33. // console.log('Header element found:', $header[0]);
  34. // console.log('Header length:', $header.length);
  35. if (!$header.length) {
  36. console.warn('Auto-hide navigation: No header element found');
  37. return;
  38. }
  39. // Add identifying class for our CSS
  40. $header.addClass('srh-auto-hide-header');
  41. // Setup
  42. calculateHeaderHeight();
  43. bindEvents();
  44. // Initial state
  45. updateHeaderState();
  46. // Wait for any dynamic content to load
  47. setTimeout(function() {
  48. state.headerHeight = calculateHeaderHeight();
  49. $('body').css('--header-height', state.headerHeight + 'px');
  50. }, 500);
  51. // console.log('Auto-hide navigation: Initialization complete');
  52. // console.log('Header height calculated:', state.headerHeight);
  53. }
  54. function calculateHeaderHeight() {
  55. if (!$header.length) return;
  56. state.headerHeight = $header.outerHeight() || 80;
  57. $('html').css('--header-height', state.headerHeight + 'px');
  58. // console.log('Header height:', state.headerHeight);
  59. return state.headerHeight;
  60. }
  61. function bindEvents() {
  62. // Scroll event with debouncing
  63. $(window).on('scroll', debounce(handleScroll, config.debounceDelay));
  64. // Resize event
  65. $(window).on('resize', debounce(calculateHeaderHeight, 100));
  66. // Mouse movement for revealing header
  67. $(document).on('mousemove', handleMouseMove);
  68. // Keyboard events for accessibility
  69. $(document).on('keydown', handleKeydown);
  70. // Focus events for accessibility
  71. $header.find('a, button, input, textarea, select, [tabindex]').on('focus', showHeader);
  72. // Smooth scroll for anchor links
  73. $(document).on('click', 'a[href^="#"]', handleAnchorClick);
  74. // console.log('Events bound successfully');
  75. }
  76. function handleScroll() {
  77. if (!state.ticking) {
  78. requestAnimationFrame(updateHeaderState);
  79. state.ticking = true;
  80. }
  81. }
  82. function updateHeaderState() {
  83. const scrollTop = $(window).scrollTop();
  84. // Add scrolled class for styling
  85. if (scrollTop > 10) {
  86. $header.addClass('header-scrolled');
  87. } else {
  88. $header.removeClass('header-scrolled');
  89. }
  90. // Hide/show logic
  91. if (scrollTop > config.scrollThreshold) {
  92. if (scrollTop > state.lastScrollTop && state.isVisible) {
  93. // Scrolling down - hide header
  94. hideHeader();
  95. } else if (scrollTop < state.lastScrollTop && !state.isVisible) {
  96. // Scrolling up - show header
  97. showHeader();
  98. }
  99. } else if (!state.isVisible) {
  100. // Near top - always show header
  101. showHeader();
  102. }
  103. state.lastScrollTop = scrollTop;
  104. state.ticking = false;
  105. }
  106. function hideHeader() {
  107. if (!state.isVisible) return;
  108. // console.log('Hiding header');
  109. state.isVisible = false;
  110. $header.removeClass('header-visible').addClass('header-hidden');
  111. // Dispatch custom event
  112. $(document).trigger('headerHidden', {
  113. headerElement: $header[0],
  114. isVisible: state.isVisible,
  115. scrollTop: state.lastScrollTop
  116. });
  117. }
  118. function showHeader() {
  119. if (state.isVisible) return;
  120. // console.log('Showing header');
  121. state.isVisible = true;
  122. $header.removeClass('header-hidden').addClass('header-visible');
  123. // Dispatch custom event
  124. $(document).trigger('headerVisible', {
  125. headerElement: $header[0],
  126. isVisible: state.isVisible,
  127. scrollTop: state.lastScrollTop
  128. });
  129. }
  130. function handleMouseMove(e) {
  131. if (e.clientY < config.mouseRevealZone &&
  132. $(window).scrollTop() > config.scrollThreshold &&
  133. !state.isVisible) {
  134. showHeader();
  135. }
  136. }
  137. function handleKeydown(e) {
  138. // Show header on Tab or Escape for accessibility
  139. if (e.key === 'Tab' || e.key === 'Escape') {
  140. showHeader();
  141. }
  142. }
  143. function handleAnchorClick(e) {
  144. const $link = $(e.currentTarget);
  145. const targetId = $link.attr('href').substring(1);
  146. const $target = $('#' + targetId);
  147. if ($target.length) {
  148. e.preventDefault();
  149. const offsetTop = $target.offset().top - state.headerHeight;
  150. $('html, body').animate({
  151. scrollTop: offsetTop
  152. }, 600);
  153. }
  154. }
  155. function debounce(func, wait) {
  156. let timeout;
  157. return function executedFunction() {
  158. const context = this;
  159. const args = arguments;
  160. const later = function() {
  161. clearTimeout(timeout);
  162. func.apply(context, args);
  163. };
  164. clearTimeout(timeout);
  165. timeout = setTimeout(later, wait);
  166. };
  167. }
  168. // Public API
  169. window.SRHNavigation = {
  170. show: showHeader,
  171. hide: hideHeader,
  172. toggle: function() {
  173. state.isVisible ? hideHeader() : showHeader();
  174. },
  175. getState: function() {
  176. return $.extend({}, state);
  177. },
  178. updateConfig: function(newConfig) {
  179. $.extend(config, newConfig);
  180. },
  181. getHeader: function() {
  182. return $header;
  183. }
  184. };
  185. })(jQuery);