Fix navigation menu closing too quickly with transition delay and keyboard support
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
This commit is contained in:
parent
a1e2afabb5
commit
c4a45ef8fd
|
@ -79,10 +79,99 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
const footerElement = document.getElementById('footer-include');
|
const footerElement = document.getElementById('footer-include');
|
||||||
|
|
||||||
if (headerElement) {
|
if (headerElement) {
|
||||||
includeHTML('header-include', '/includes/header.html', setActiveNavItem);
|
includeHTML('header-include', '/includes/header.html', () => {
|
||||||
|
setActiveNavItem();
|
||||||
|
setupNavDropdowns();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (footerElement) {
|
if (footerElement) {
|
||||||
includeHTML('footer-include', '/includes/footer.html');
|
includeHTML('footer-include', '/includes/footer.html');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup dropdown behavior with delay
|
||||||
|
function setupNavDropdowns() {
|
||||||
|
const dropdowns = document.querySelectorAll('.main-nav .dropdown');
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
|
dropdowns.forEach(dropdown => {
|
||||||
|
// Mouse interactions
|
||||||
|
dropdown.addEventListener('mouseenter', () => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
dropdowns.forEach(d => {
|
||||||
|
if (d !== dropdown) {
|
||||||
|
d.querySelector('.dropdown-content').style.display = 'none';
|
||||||
|
d.querySelector('.dropdown-content').style.opacity = '0';
|
||||||
|
d.querySelector('.dropdown-content').style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const dropdownContent = dropdown.querySelector('.dropdown-content');
|
||||||
|
dropdownContent.style.display = 'block';
|
||||||
|
// Small delay to allow CSS transition to work properly
|
||||||
|
setTimeout(() => {
|
||||||
|
dropdownContent.style.opacity = '1';
|
||||||
|
dropdownContent.style.visibility = 'visible';
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
dropdown.addEventListener('mouseleave', () => {
|
||||||
|
const dropdownContent = dropdown.querySelector('.dropdown-content');
|
||||||
|
// Add delay before hiding the dropdown
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
dropdownContent.style.opacity = '0';
|
||||||
|
dropdownContent.style.visibility = 'hidden';
|
||||||
|
// Wait for transition to complete before changing display
|
||||||
|
setTimeout(() => {
|
||||||
|
if (dropdownContent.style.opacity === '0') {
|
||||||
|
dropdownContent.style.display = 'none';
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
}, 300); // 300ms delay before starting to close
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keyboard interactions
|
||||||
|
const dropdownLink = dropdown.querySelector('a');
|
||||||
|
dropdownLink.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
const dropdownContent = dropdown.querySelector('.dropdown-content');
|
||||||
|
dropdownContent.style.display = 'block';
|
||||||
|
setTimeout(() => {
|
||||||
|
dropdownContent.style.opacity = '1';
|
||||||
|
dropdownContent.style.visibility = 'visible';
|
||||||
|
|
||||||
|
// Focus the first link in the dropdown
|
||||||
|
const firstLink = dropdownContent.querySelector('a');
|
||||||
|
if (firstLink) firstLink.focus();
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add keyboard navigation for dropdown items
|
||||||
|
const dropdownLinks = dropdown.querySelectorAll('.dropdown-content a');
|
||||||
|
dropdownLinks.forEach((link, index) => {
|
||||||
|
link.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
const nextLink = dropdownLinks[index + 1] || dropdownLinks[0];
|
||||||
|
nextLink.focus();
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
const prevLink = dropdownLinks[index - 1] || dropdownLinks[dropdownLinks.length - 1];
|
||||||
|
prevLink.focus();
|
||||||
|
} else if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
dropdown.querySelector('a').focus();
|
||||||
|
const dropdownContent = dropdown.querySelector('.dropdown-content');
|
||||||
|
dropdownContent.style.opacity = '0';
|
||||||
|
dropdownContent.style.visibility = 'hidden';
|
||||||
|
setTimeout(() => {
|
||||||
|
dropdownContent.style.display = 'none';
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
|
@ -302,11 +302,17 @@ hr {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.2s ease, visibility 0s linear 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-nav .dropdown:hover .dropdown-content,
|
.main-nav .dropdown:hover .dropdown-content,
|
||||||
.main-nav .dropdown:focus-within .dropdown-content {
|
.main-nav .dropdown:focus-within .dropdown-content {
|
||||||
display: block;
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transition: opacity 0.2s ease, visibility 0s linear 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-nav .dropdown-content a {
|
.main-nav .dropdown-content a {
|
||||||
|
|
Loading…
Reference in New Issue