Browse Source

offcanvas

windhamdavid 5 days ago
parent
commit
9551c2f563
5 changed files with 271 additions and 348 deletions
  1. 4 4
      blocks/offcanvas-menu/block.json
  2. 16 22
      blocks/offcanvas-menu/index.js
  3. 2 26
      css/offcanvas-menu-editor.css
  4. 25 66
      functions.php
  5. 224 230
      js/auto-hide-nav.js

+ 4 - 4
blocks/offcanvas-menu/block.json

@@ -4,16 +4,16 @@
     "name": "srh/offcanvas-menu",
     "version": "0.1.0",
     "title": "Off Canvas Menu",
-    "category": "srh-blocks",
+    "category": "design",
     "icon": "menu",
     "description": "Add an off-canvas menu button to your navigation",
     "supports": {
         "html": false,
-        "multiple": false
+        "multiple": true,
+        "anchor": true
     },
     "textdomain": "srh",
     "editorScript": "file:./index.js",
     "viewScript": "file:./view.js",
-    "style": "file:./style.css",
-    "render": "file:./render.php"
+    "style": "file:./style.css"
 }

+ 16 - 22
blocks/offcanvas-menu/index.js

@@ -1,28 +1,22 @@
-import { registerBlockType } from '@wordpress/blocks';
-import { useBlockProps } from '@wordpress/block-editor';
+const { registerBlockType } = wp.blocks;
+const { createElement } = wp.element;
 
 registerBlockType('srh/offcanvas-menu', {
-    apiVersion: 3,
-    title: 'Off Canvas Menu',
-    icon: 'menu',
-    category: 'srh-blocks',
-    
     edit: function() {
-        const blockProps = useBlockProps({
-            className: 'wp-block-srh-offcanvas-menu'
-        });
-        
-        return (
-            <div { ...blockProps }>
-                <button className="hamburger-toggle is-editor" aria-label="Toggle Menu">
-                    <div className="hamburger-lines">
-                        <span></span>
-                        <span></span>
-                        <span></span>
-                    </div>
-                    <span className="menu-text">Menu</span>
-                </button>
-            </div>
+        return createElement('div', { className: 'wp-block-srh-offcanvas-menu' },
+            createElement('button', {
+                className: 'hamburger-toggle',
+                'aria-label': 'Toggle Menu'
+            },
+                createElement('span', {}),
+                createElement('span', {}),
+                createElement('span', {})
+            ),
+            createElement('div', { className: 'offcanvas-menu' },
+                createElement('div', { className: 'offcanvas-menu-inner' },
+                    createElement('p', {}, 'Menu will appear here on frontend')
+                )
+            )
         );
     },
     

+ 2 - 26
css/offcanvas-menu-editor.css

@@ -1,32 +1,8 @@
 .wp-block-srh-offcanvas-menu {
-    position: relative;
     display: flex;
     align-items: center;
-}
-
-.hamburger-toggle.is-editor {
-    cursor: default;
-    pointer-events: none;
-    opacity: 0.7;
-}
-
-.hamburger-toggle .hamburger-lines {
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    height: 24px;
-    width: 24px;
-}
-
-.hamburger-toggle .hamburger-lines span {
-    display: block;
-    height: 2px;
-    width: 100%;
-    background-color: currentColor;
-}
-
-.hamburger-toggle .menu-text {
-    margin-left: 8px;
+    padding: 10px;
+    border: 1px dashed #ccc;
 }
 
 .editor-styles-wrapper .hamburger-toggle {

+ 25 - 66
functions.php

@@ -1,59 +1,5 @@
 <?php 
 
-/**
- * Additional logging in WordPress 6.1+ that generates the following
- * message regarding cron schedules:
- *
- * Cron reschedule event error for hook:
- * action_scheduler_run_queue,
- * Error code: invalid_schedule,
- * Error message: Event schedule does not exist.,
- * Data: {"schedule":"every_minute","args":,"interval":60}
- *
- * This function needs to fire prior to loading Action Scheduler as its a
- * pre-requisite for it to schedule our tasks.
- *
- * This filter seeks to manually add the schedule to the list of schedules to
- * address this bug.
- */
-add_filter('cron_schedules', function ($schedules) {
-    $schedules = [
-        'interval' => 60,
-        'display'  => 'Every Minute',
-    ];
-    return $schedules;
-});
-
-/***********************************************************
-############### REST API and Iframe Support ################
-************************************************************/
-
-// Add REST API and iframe communication support
-add_action('after_setup_theme', 'srh25_setup_theme_support');
-function srh25_setup_theme_support() {
-    add_theme_support('editor-styles');
-    add_theme_support('responsive-embeds');
-    add_theme_support('custom-units');
-    
-    // Ensure proper communication for block editor
-    if (is_admin()) {
-        add_filter('allowed_http_origins', 'srh25_allow_local_origins');
-    }
-}
-
-function srh25_allow_local_origins($origins) {
-    $origins[] = home_url();
-    return array_unique($origins);
-}
-
-// Add headers for iframe communication
-add_action('send_headers', 'srh25_add_frame_headers');
-function srh25_add_frame_headers() {
-    if (is_admin()) {
-        header('Access-Control-Allow-Origin: ' . esc_url(home_url()));
-        header('Access-Control-Allow-Credentials: true');
-    }
-}
 
 /***********************************************************
 #################### SRH Theme #############################
@@ -279,20 +225,33 @@ add_filter('block_categories_all', 'srh_block_categories', 10, 2);
 
 // Register the block
 function register_offcanvas_menu_block() {
+    register_block_type( __DIR__ . '/blocks/offcanvas-menu', array(
+        'render_callback' => 'render_offcanvas_menu',
+        'editor_script' => 'offcanvas-menu-editor',
+        'editor_style'  => 'offcanvas-menu-editor',
+        'supports' => array(
+            'inserter' => true,
+            'multiple' => true,
+            'parent' => array('core/navigation')
+        )
+    ));
+
+    // Register editor assets
     wp_register_script(
-        'srh-offcanvas-menu-editor',
-        get_stylesheet_directory_uri() . '/blocks/offcanvas-menu/index.js',
-        array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'),
-        filemtime(get_stylesheet_directory() . '/blocks/offcanvas-menu/index.js')
+        'offcanvas-menu-editor',
+        get_stylesheet_directory_uri() . '/js/offcanvas-menu-editor.js',
+        array('wp-blocks', 'wp-element'),
+        '1.0.0'
     );
 
-    register_block_type(get_stylesheet_directory() . '/blocks/offcanvas-menu', array(
-        'api_version' => 3,
-        'editor_script' => 'srh-offcanvas-menu-editor',
-        'render_callback' => 'render_offcanvas_menu'
-    ));
+    wp_register_style(
+        'offcanvas-menu-editor',
+        get_stylesheet_directory_uri() . '/css/offcanvas-menu-editor.css',
+        array(),
+        '1.0.0'
+    );
 }
-add_action('init', 'register_offcanvas_menu_block', 5);
+add_action('init', 'register_offcanvas_menu_block');
 
 // Frontend assets remain the same
 function enqueue_offcanvas_menu_assets() {
@@ -314,7 +273,7 @@ function enqueue_offcanvas_menu_assets() {
 add_action('wp_enqueue_scripts', 'enqueue_offcanvas_menu_assets');
 
 function render_offcanvas_menu($attributes, $content) {
-    $pattern_content = do_blocks('<!-- wp:pattern {"slug":"srh/offcanvas-content"} /-->');
+    $template_part = do_blocks('<!-- wp:template-part {"slug":"offcanvas-content","theme":"edit-srh"} /-->');
     
     return sprintf(
         '<div class="wp-block-srh-offcanvas-menu">
@@ -330,7 +289,7 @@ function render_offcanvas_menu($attributes, $content) {
                 <div class="offcanvas-menu-inner">%s</div>
             </div>
         </div>',
-        $pattern_content
+        $template_part
     );
 }
 

+ 224 - 230
js/auto-hide-nav.js

@@ -1,236 +1,230 @@
 /**
- * Auto-Hide Navigation Script - jQuery Version
- * Smoothly hides navigation when scrolling down and shows it when scrolling up
+ * SRH Auto-Hide Navigation
+ * Hides header when scrolling down, shows 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 $header, $body;
-  
-  // Initialize when document is ready
-  $(document).ready(function() {
-      init();
-  });
-  
-  function init() {
-      // console.log('Auto-hide navigation: jQuery script loaded');
-      
-      // Find header elements - Try multiple selectors for Twenty Twenty-Five
-      $header = $('header').first();
-      if (!$header.length) {
-          $header = $('.wp-site-header').first();
-      }
-      if (!$header.length) {
-          $header = $('.wp-block-template-part[data-area="header"]').first();
-      }
-      if (!$header.length) {
-          $header = $('[class*="header"]').first();
-      }
-      if (!$header.length) {
-          $header = $('nav').first();
-      }
-      
-      $body = $('body');
-      
-      // console.log('Header element found:', $header[0]);
-      // console.log('Header length:', $header.length);
-      
-      if (!$header.length) {
-          console.warn('Auto-hide navigation: No header element found');
-          return;
-      }
-      
-      // Add identifying class for our CSS
-      $header.addClass('srh-auto-hide-header');
-      
-      // Setup
-      calculateHeaderHeight();
-      bindEvents();
-      
-      // Initial state
-      updateHeaderState();
-      
-      // console.log('Auto-hide navigation: Initialization complete');
-      // console.log('Header height calculated:', state.headerHeight);
-  }
-  
-  function calculateHeaderHeight() {
-      if (!$header.length) return;
-      
-      state.headerHeight = $header.outerHeight() || 80;
-      $('html').css('--header-height', state.headerHeight + 'px');
-      
-      // console.log('Header height:', state.headerHeight);
-  }
-  
-  function bindEvents() {
-      // Scroll event with debouncing
-      $(window).on('scroll', debounce(handleScroll, config.debounceDelay));
-      
-      // Resize event
-      $(window).on('resize', debounce(calculateHeaderHeight, 100));
-      
-      // Mouse movement for revealing header
-      $(document).on('mousemove', handleMouseMove);
-      
-      // Keyboard events for accessibility
-      $(document).on('keydown', handleKeydown);
-      
-      // Focus events for accessibility
-      $header.find('a, button, input, textarea, select, [tabindex]').on('focus', showHeader);
-      
-      // Smooth scroll for anchor links
-      $(document).on('click', 'a[href^="#"]', handleAnchorClick);
-      
-      // console.log('Events bound successfully');
-  }
-  
-  function handleScroll() {
-      if (!state.ticking) {
-          requestAnimationFrame(updateHeaderState);
-          state.ticking = true;
-      }
-  }
-  
-  function updateHeaderState() {
-      const scrollTop = $(window).scrollTop();
-      
-      // Add scrolled class for styling
-      if (scrollTop > 50) {
-          $body.addClass('header-offset');
-          $header.addClass('header-scrolled');
-      } else {
-          $body.removeClass('header-offset');
-          $header.removeClass('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;
-      
-      // console.log('Hiding header');
-      state.isVisible = false;
-      $header.removeClass('header-visible').addClass('header-hidden');
-      
-      // Dispatch custom event
-      $(document).trigger('headerHidden', {
-          headerElement: $header[0],
-          isVisible: state.isVisible,
-          scrollTop: state.lastScrollTop
-      });
-  }
-  
-  function showHeader() {
-      if (state.isVisible) return;
-      
-      // console.log('Showing header');
-      state.isVisible = true;
-      $header.removeClass('header-hidden').addClass('header-visible');
-      
-      // Dispatch custom event
-      $(document).trigger('headerVisible', {
-          headerElement: $header[0],
-          isVisible: state.isVisible,
-          scrollTop: state.lastScrollTop
-      });
-  }
-  
-  function handleMouseMove(e) {
-      if (e.clientY < config.mouseRevealZone && 
-          $(window).scrollTop() > 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.currentTarget);
-      const targetId = $link.attr('href').substring(1);
-      const $target = $('#' + targetId);
-      
-      if ($target.length) {
-          e.preventDefault();
-          
-          const offsetTop = $target.offset().top - state.headerHeight;
-          
-          $('html, body').animate({
-              scrollTop: offsetTop
-          }, 600);
-      }
-  }
-  
-  function debounce(func, wait) {
-      let timeout;
-      return function executedFunction() {
-          const context = this;
-          const args = arguments;
-          const later = function() {
-              clearTimeout(timeout);
-              func.apply(context, args);
-          };
-          clearTimeout(timeout);
-          timeout = setTimeout(later, wait);
-      };
-  }
-  
-  // Public API
-  window.SRHNavigation = {
-      show: showHeader,
-      hide: hideHeader,
-      toggle: function() {
-          state.isVisible ? hideHeader() : showHeader();
-      },
-      getState: function() {
-          return $.extend({}, state);
-      },
-      updateConfig: function(newConfig) {
-          $.extend(config, newConfig);
-      },
-      getHeader: function() {
-          return $header;
-      }
-  };
+    '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 $header, $body;
+    const headerSelectors = 'header, .srh-auto-hide-header, .wp-site-header, .wp-block-template-part[data-area="header"]';
+    
+    // Initialize when document is ready
+    $(document).ready(function() {
+        init();
+    });
+    
+    function init() {
+        // console.log('Auto-hide navigation: jQuery script loaded');
+        
+        // Find header elements - Try multiple selectors for Twenty Twenty-Five
+        $header = $(headerSelectors).first();
+        
+        $body = $('body');
+        
+        // console.log('Header element found:', $header[0]);
+        // console.log('Header length:', $header.length);
+        
+        if (!$header.length) {
+            console.warn('Auto-hide navigation: No header element found');
+            return;
+        }
+        
+        // Add identifying class for our CSS
+        $header.addClass('srh-auto-hide-header');
+        
+        // Setup
+        calculateHeaderHeight();
+        bindEvents();
+        
+        // Initial state
+        updateHeaderState();
+        
+        // Wait for any dynamic content to load
+        setTimeout(function() {
+            state.headerHeight = calculateHeaderHeight();
+            $('body').css('--header-height', state.headerHeight + 'px');
+        }, 500);
+        
+        // console.log('Auto-hide navigation: Initialization complete');
+        // console.log('Header height calculated:', state.headerHeight);
+    }
+    
+    function calculateHeaderHeight() {
+        if (!$header.length) return;
+        
+        state.headerHeight = $header.outerHeight() || 80;
+        $('html').css('--header-height', state.headerHeight + 'px');
+        
+        // console.log('Header height:', state.headerHeight);
+        return state.headerHeight;
+    }
+    
+    function bindEvents() {
+        // Scroll event with debouncing
+        $(window).on('scroll', debounce(handleScroll, config.debounceDelay));
+        
+        // Resize event
+        $(window).on('resize', debounce(calculateHeaderHeight, 100));
+        
+        // Mouse movement for revealing header
+        $(document).on('mousemove', handleMouseMove);
+        
+        // Keyboard events for accessibility
+        $(document).on('keydown', handleKeydown);
+        
+        // Focus events for accessibility
+        $header.find('a, button, input, textarea, select, [tabindex]').on('focus', showHeader);
+        
+        // Smooth scroll for anchor links
+        $(document).on('click', 'a[href^="#"]', handleAnchorClick);
+        
+        // console.log('Events bound successfully');
+    }
+    
+    function handleScroll() {
+        if (!state.ticking) {
+            requestAnimationFrame(updateHeaderState);
+            state.ticking = true;
+        }
+    }
+    
+    function updateHeaderState() {
+        const scrollTop = $(window).scrollTop();
+        
+        // Add scrolled class for styling
+        if (scrollTop > 10) {
+            $header.addClass('header-scrolled');
+        } else {
+            $header.removeClass('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;
+        
+        // console.log('Hiding header');
+        state.isVisible = false;
+        $header.removeClass('header-visible').addClass('header-hidden');
+        
+        // Dispatch custom event
+        $(document).trigger('headerHidden', {
+            headerElement: $header[0],
+            isVisible: state.isVisible,
+            scrollTop: state.lastScrollTop
+        });
+    }
+    
+    function showHeader() {
+        if (state.isVisible) return;
+        
+        // console.log('Showing header');
+        state.isVisible = true;
+        $header.removeClass('header-hidden').addClass('header-visible');
+        
+        // Dispatch custom event
+        $(document).trigger('headerVisible', {
+            headerElement: $header[0],
+            isVisible: state.isVisible,
+            scrollTop: state.lastScrollTop
+        });
+    }
+    
+    function handleMouseMove(e) {
+        if (e.clientY < config.mouseRevealZone && 
+            $(window).scrollTop() > 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.currentTarget);
+        const targetId = $link.attr('href').substring(1);
+        const $target = $('#' + targetId);
+        
+        if ($target.length) {
+            e.preventDefault();
+            
+            const offsetTop = $target.offset().top - state.headerHeight;
+            
+            $('html, body').animate({
+                scrollTop: offsetTop
+            }, 600);
+        }
+    }
+    
+    function debounce(func, wait) {
+        let timeout;
+        return function executedFunction() {
+            const context = this;
+            const args = arguments;
+            const later = function() {
+                clearTimeout(timeout);
+                func.apply(context, args);
+            };
+            clearTimeout(timeout);
+            timeout = setTimeout(later, wait);
+        };
+    }
+    
+    // Public API
+    window.SRHNavigation = {
+        show: showHeader,
+        hide: hideHeader,
+        toggle: function() {
+            state.isVisible ? hideHeader() : showHeader();
+        },
+        getState: function() {
+            return $.extend({}, state);
+        },
+        updateConfig: function(newConfig) {
+            $.extend(config, newConfig);
+        },
+        getHeader: function() {
+            return $header;
+        }
+    };
     
 })(jQuery);