PageSourceSearch

https://gh-network.net/assets/js/services-tabs.js

js gh-network.net collected 2026-10-08 17:30:52 UTC 5,232 bytes, 154 lines download raw bytes

1// Navigation scroll effect
2document.addEventListener('DOMContentLoaded', function() {
3    // Add scroll event for navigation
4    const header = document.querySelector('.main-navigation');
5    let lastScroll = 0;
6    
7    window.addEventListener('scroll', () => {
8        const currentScroll = window.pageYOffset;
9        
10        if (currentScroll <= 0) {
11            header.classList.remove('scrolled');
12            return;
13        }
14        
15        if (currentScroll > lastScroll && !header.classList.contains('scroll-down')) {
16            // Scroll down
17            header.classList.remove('scrolled-up');
18            header.classList.add('scrolled', 'scroll-down');
19        } else if (currentScroll < lastScroll && header.classList.contains('scroll-down')) {
20            // Scroll up
21            header.classList.remove('scroll-down');
22            header.classList.add('scrolled-up');
23        }
24        
25        lastScroll = currentScroll;
26    });
27    
28    // Smooth scrolling for anchor links
29    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
30        anchor.addEventListener('click', function(e) {
31            e.preventDefault();
32            
33            const targetId = this.getAttribute('href');
34            if (targetId === '#') return;
35            
36            const targetElement = document.querySelector(targetId);
37            if (targetElement) {
38                window.scrollTo({
39                    top: targetElement.offsetTop - 100,
40                    behavior: 'smooth'
41                });
42                
43                // Close mobile menu if open
44                const mobileMenu = document.getElementById('mobile-navigation');
45                const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
46                if (mobileMenu && mobileMenu.getAttribute('aria-hidden') === 'false') {
47                    mobileMenu.setAttribute('aria-hidden', 'true');
48                    mobileMenuBtn.setAttribute('aria-expanded', 'false');
49                    document.body.classList.remove('menu-open');
50                }
51            }
52        });
53    });
54    // Tab functionality
55    const tabButtons = document.querySelectorAll('.tab-btn');
56    const tabPanes = document.querySelectorAll('.tab-pane');
57    
58    // Set initial active tab
59    let activeTab = localStorage.getItem('activeTab') || 'superfast';
60    
61    // Function to activate a tab
62    function activateTab(tabId) {
63        // Hide all tab panes
64        tabPanes.forEach(pane => {
65            pane.classList.remove('active');
66        });
67        
68        // Deactivate all tab buttons
69        tabButtons.forEach(btn => {
70            btn.classList.remove('active');
71        });
72        
73        // Show the selected tab pane
74        const activePane = document.getElementById(tabId);
75        if (activePane) {
76            activePane.classList.add('active');
77        }
78        
79        // Activate the clicked button
80        const activeButton = document.querySelector(`.tab-btn[data-tab="${tabId}"]`);
81        if (activeButton) {
82            activeButton.classList.add('active');
83        }
84        
85        // Save active tab to localStorage
86        localStorage.setItem('activeTab', tabId);
87    }
88    
89    // Add click event listeners to tab buttons
90    tabButtons.forEach(button => {
91        button.addEventListener('click', () => {
92            const tabId = button.getAttribute('data-tab');
93            activateTab(tabId);
94        });
95    });
96    
97    // Initialize with the active tab
98    activateTab(activeTab);
99    
100    // Handle window resize for responsive behavior
101    let resizeTimer;
102    window.addEventListener('resize', () => {
103        clearTimeout(resizeTimer);
104        resizeTimer = setTimeout(() => {
105            // Update tab heights on resize
106            updateTabHeights();
107        }, 250);
108    });
109    
110    // Function to update tab heights for consistent height
111    function updateTabHeights() {
112        let maxHeight = 0;
113        tabPanes.forEach(pane => {
114            pane.style.height = 'auto';
115            const height = pane.offsetHeight;
116            if (height > maxHeight) {
117                maxHeight = height;
118            }
119        });
120        
121        // Set all tab panes to the height of the tallest one
122        tabPanes.forEach(pane => {
123            pane.style.minHeight = `${maxHeight}px`;
124        });
125    }
126    
127    // Initialize tab heights
128    updateTabHeights();
129    
130    // Add animation class to elements when they come into view
131    const animateOnScroll = () => {
132        const elements = document.querySelectorAll('.animate-on-scroll');
133        elements.forEach(element => {
134            const elementPosition = element.getBoundingClientRect().top;
135            const windowHeight = window.innerHeight;
136            
137            if (elementPosition < windowHeight - 50) {
138                element.classList.add('animate');
139            }
140        });
141    };
142    
143    // Initial check
144    animateOnScroll();
145    
146    // Check on scroll
147    window.addEventListener('scroll', animateOnScroll);
148    
149    // Add animation to hero content
150    const heroContent = document.querySelector('.hero-content');
151    if (heroContent) {
152        heroContent.classList.add('animate-on-scroll');
153    }
154});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.