summaryrefslogtreecommitdiffstats
path: root/themes/danix-xyz-hacker/assets/js/menu.js
blob: 3f326425e214474291940fbc537d64c79eaf68a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
document.addEventListener('DOMContentLoaded', () => {
  const menuToggle = document.getElementById('menu-toggle');
  const menuOverlay = document.getElementById('menu-overlay');
  const menuPanel = document.getElementById('hamburger-menu');

  function openMenu() {
    if (!menuOverlay || !menuPanel) return;

    // Show overlay
    menuOverlay.classList.remove('opacity-0');
    menuOverlay.classList.remove('invisible');

    // Slide menu in
    menuPanel.classList.remove('translate-x-full');

    // Manage accessibility
    menuToggle.setAttribute('aria-expanded', 'true');
    menuPanel.removeAttribute('aria-hidden');

    // Control body overflow
    document.body.style.overflow = 'hidden';

    // Focus first focusable element in menu
    const firstFocusable = menuPanel.querySelector('a, button');
    if (firstFocusable) {
      setTimeout(() => firstFocusable.focus(), 50);
    }
  }

  function closeMenu() {
    if (!menuOverlay || menuOverlay.classList.contains('opacity-0')) return;

    // Hide overlay
    menuOverlay.classList.add('opacity-0');
    menuOverlay.classList.add('invisible');

    // Slide menu out
    menuPanel.classList.add('translate-x-full');

    // Manage accessibility
    menuToggle.setAttribute('aria-expanded', 'false');
    menuPanel.setAttribute('aria-hidden', 'true');

    // Restore body overflow
    document.body.style.overflow = '';

    // Return focus to toggle button
    menuToggle.focus();
  }

  function toggleMenu() {
    if (menuOverlay && menuOverlay.classList.contains('opacity-0')) {
      openMenu();
    } else {
      closeMenu();
    }
  }

  // Toggle menu when clicking the hamburger button
  if (menuToggle) {
    menuToggle.addEventListener('click', toggleMenu);
  }

  // Close menu when clicking on the overlay
  if (menuOverlay) {
    menuOverlay.addEventListener('click', (e) => {
      if (e.target === menuOverlay) {
        closeMenu();
      }
    });
  }

  // Close menu when clicking menu items
  const menuLinks = document.querySelectorAll('#hamburger-menu a, #hamburger-menu button');
  menuLinks.forEach(link => {
    link.addEventListener('click', closeMenu);
  });

  // Close menu on Escape key
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && menuOverlay && !menuOverlay.classList.contains('opacity-0')) {
      closeMenu();
    }
  });

  // Focus trap: keep tab within menu when open
  if (menuPanel) {
    menuPanel.addEventListener('keydown', (e) => {
      if (e.key !== 'Tab') return;

      const focusableElements = menuPanel.querySelectorAll('a, button, [tabindex]:not([tabindex="-1"])');
      if (focusableElements.length === 0) return;

      const firstElement = focusableElements[0];
      const lastElement = focusableElements[focusableElements.length - 1];
      const isMenuOpen = !menuOverlay.classList.contains('opacity-0');

      if (!isMenuOpen) return;

      // Shift+Tab on first element: move to last
      if (e.shiftKey && document.activeElement === firstElement) {
        e.preventDefault();
        lastElement.focus();
      }
      // Tab on last element: move to first
      else if (!e.shiftKey && document.activeElement === lastElement) {
        e.preventDefault();
        firstElement.focus();
      }
    });
  }
});