import 'swiper/css'; import 'swiper/css/navigation'; import 'swiper/css/pagination'; import Swiper from 'swiper'; import { Navigation, Pagination } from 'swiper/modules'; // Navbar scalable document.addEventListener('DOMContentLoaded', () => { // Calculate 3% of the viewport height const threshold = window.innerHeight * 0.03; // Select the elements const headerBar = document.querySelector('.header-bar') as HTMLElement; const navbar = document.querySelector('.navbar') as HTMLElement; const navLogo = document.querySelector('.nav_logo'); // Ensure elements are found if (!headerBar || !navbar || !navLogo) { console.error('Elements not found: Ensure .header-bar and .navbar exist in the DOM.'); return; } // Track scroll state to avoid redundant updates let isScrolled = false; // Get initial heights const defaultHeaderHeight = getComputedStyle(headerBar).height; const defaultNavbarHeight = getComputedStyle(navbar).height; const defaultNavLogoSize = getComputedStyle(navLogo).height; // Optimize scroll handling with requestAnimationFrame let ticking = false; window.addEventListener('scroll', () => { if (!ticking) { requestAnimationFrame(() => { const scrolledPastThreshold = window.scrollY > threshold; if (scrolledPastThreshold && !isScrolled) { isScrolled = true; // Update styles for header-bar headerBar.style.height = '2.5rem'; // Update styles for navbar navbar.style.backgroundColor = 'rgba(255, 255, 255, 0.5)'; navbar.style.height = '4.5rem'; navbar.style.boxShadow = '0 0 4px 2px #00000014'; navbar.style.backdropFilter = 'blur(15px)'; // Update styles for nav_logo navLogo.style.height = '3rem'; // Resizing from 4rem to 3rem navLogo.style.width = '3rem'; // Maintain aspect ratio, adjust if necessary } else if (!scrolledPastThreshold && isScrolled) { isScrolled = false; // Revert styles for header-bar headerBar.style.height = defaultHeaderHeight; // Revert styles for navbar navbar.style.backgroundColor = 'transparent'; navbar.style.height = defaultNavbarHeight; navbar.style.boxShadow = 'none'; navbar.style.backdropFilter = 'none'; // Revert styles for nav_logo navLogo.style.height = defaultNavLogoSize; // Reverting back to original size navLogo.style.width = defaultNavLogoSize; // Maintain aspect ratio, adjust if necessary } ticking = false; }); ticking = true; } }); }); // Tab on hover for desktop document.addEventListener('DOMContentLoaded', () => { // Select all elements with the 'und-tab="hover"' attribute const tabs = document.querySelectorAll('[und-tab="hover"]') as NodeListOf; // Add an event listener to each element to trigger a click on hover tabs.forEach((tab) => { tab.addEventListener('mouseenter', () => { tab.click(); }); }); }); // Duplicate desktop navigation to mobile document.addEventListener('DOMContentLoaded', () => { // Select all desktop navigation dropdowns const desktopNavDropdowns = document.querySelectorAll('.nav-link_dd'); if (desktopNavDropdowns.length === 0) { console.error('No desktop navigation dropdowns found with class "nav-link_dd".'); return; } desktopNavDropdowns.forEach((dropdown, dropdownIndex) => { // Select all tab menu links and corresponding content panes within this dropdown const desktopTabLinks = dropdown.querySelectorAll('.nav-dd_tab-menu-link'); const desktopTabContents = dropdown.querySelectorAll('.nav-dd_tabs-pane-grid'); // Select the mobile navigation container within this dropdown const mobileNavContainer = dropdown.querySelector('.nav-mobile_nav_btm'); if (!mobileNavContainer) { console.warn( `Mobile navigation container with class "nav-mobile_nav_btm" not found in dropdown index ${dropdownIndex}.` ); return; } // Clear existing mobile navigation content mobileNavContainer.innerHTML = ''; // Create a DocumentFragment to improve performance const fragment = document.createDocumentFragment(); desktopTabLinks.forEach((tabLink, index) => { const tabContent = desktopTabContents[index]; if (!tabContent) { console.warn( `No corresponding content found for tab link at index ${index} in dropdown index ${dropdownIndex}.` ); return; } // Create the mobile dropdown container const mobileDd = document.createElement('div'); mobileDd.classList.add('nav-mobile-dd'); // Create the toggle element and duplicate the tab link content const toggle = document.createElement('div'); toggle.classList.add('nav-mobile-dd_toggle'); toggle.innerHTML = tabLink.innerHTML; // Clone the inner HTML // Assign unique IDs for accessibility const toggleId = `nav-mobile-dd-toggle-${dropdownIndex}-${index}`; const contentId = `nav-mobile-dd-content-${dropdownIndex}-${index}`; toggle.setAttribute('id', toggleId); toggle.setAttribute('role', 'button'); toggle.setAttribute('aria-controls', contentId); toggle.setAttribute('aria-expanded', 'false'); toggle.setAttribute('tabindex', '0'); // Create the bottom/content element const btm = document.createElement('div'); btm.classList.add('nav-mobile-dd_btm'); btm.setAttribute('id', contentId); btm.setAttribute('aria-labelledby', toggleId); btm.setAttribute('role', 'region'); btm.style.display = 'none'; // Initially hide the content // Create the list container and duplicate the tab content const list = document.createElement('div'); list.classList.add('nav-mobile-dd_list'); list.innerHTML = tabContent.innerHTML; // Clone the inner HTML // Append the list to the bottom/content element btm.appendChild(list); // Append toggle and content to the mobile dropdown container mobileDd.appendChild(toggle); mobileDd.appendChild(btm); // Append the mobile dropdown to the DocumentFragment fragment.appendChild(mobileDd); }); // Append all mobile dropdowns at once mobileNavContainer.appendChild(fragment); }); // Event Delegation for Mobile Dropdown Toggles desktopNavDropdowns.forEach((dropdown) => { const mobileNavContainer = dropdown.querySelector('.nav-mobile_nav_btm'); if (!mobileNavContainer) return; mobileNavContainer.addEventListener('click', (event) => { const toggle = event.target.closest('.nav-mobile-dd_toggle'); if (!toggle) return; const btm = toggle.nextElementSibling; const isExpanded = toggle.getAttribute('aria-expanded') === 'true'; // Close all other open accordions within this mobileNavContainer mobileNavContainer.querySelectorAll('.nav-mobile-dd_btm').forEach((el) => { el.style.display = 'none'; }); mobileNavContainer.querySelectorAll('.nav-mobile-dd_toggle').forEach((el) => { el.setAttribute('aria-expanded', 'false'); }); // Toggle the current content if (isExpanded) { btm.style.display = 'none'; toggle.setAttribute('aria-expanded', 'false'); } else { btm.style.display = 'block'; toggle.setAttribute('aria-expanded', 'true'); } }); // Keyboard Accessibility for Toggles mobileNavContainer.addEventListener('keydown', (event) => { const toggle = event.target.closest('.nav-mobile-dd_toggle'); if (!toggle) return; if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); toggle.click(); } }); }); }); // UTM Addition to External link const HEADER_UTM = '?utm_source=dokucom&utm_content=header'; const FOOTER_UTM = '?utm_source=dokucom&utm_content=footer'; // Utility: Check if a link is external function isExternalLink(href: string): boolean { try { const linkUrl = new URL(href, window.location.origin); return linkUrl.hostname !== window.location.hostname; } catch { return false; } } // Add UTM to all external links inside a container function addUTMToLinks(container: HTMLElement, utm: string) { const links = container.querySelectorAll('a[href]'); links.forEach((link) => { if (isExternalLink(link.href)) { const url = new URL(link.href); url.searchParams.set('utm_source', 'dokucom'); url.searchParams.set('utm_content', utm.includes('header') ? 'header' : 'footer'); link.href = url.toString(); } }); } // Run when DOM is ready window.addEventListener('DOMContentLoaded', () => { const header = document.querySelector('header'); const footer = document.querySelector('footer'); if (header) addUTMToLinks(header, HEADER_UTM); if (footer) addUTMToLinks(footer, FOOTER_UTM); });