Update dropdown style

This commit is contained in:
2026-07-31 11:51:05 +10:00
parent fcff9039ae
commit 9cefe20a26
2 changed files with 58 additions and 20 deletions
+22 -17
View File
@@ -6,18 +6,29 @@ document.addEventListener('DOMContentLoaded', function() {
const languageOptions = document.getElementById('language-options');
const isMobile = () => window.innerWidth < 768; // matches Tailwind's md breakpoint
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const ANIM_MS = reduceMotion ? 0 : 320;
function isOpen(dropdown) {
return dropdown ? dropdown.classList.contains('menu-open') : false;
}
function openDropdown(dropdown) {
dropdown.classList.remove('hidden');
dropdown.classList.add('menu-open');
if (isMobile()) {
document.body.style.overflow = 'hidden';
}
}
function closeDropdown(dropdown) {
dropdown.classList.add('hidden');
dropdown.classList.remove('menu-open');
if (isMobile()) {
document.body.style.overflow = '';
// Release body scroll only after the slide-up animation finishes
setTimeout(() => {
if (!isOpen(moreMenuDropdown) && !isOpen(languageOptions)) {
document.body.style.overflow = '';
}
}, ANIM_MS);
}
}
@@ -25,12 +36,12 @@ document.addEventListener('DOMContentLoaded', function() {
button.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (dropdown.classList.contains('hidden')) {
if (!isOpen(dropdown)) {
// Close other dropdown first
if (dropdown === moreMenuDropdown && languageOptions && !languageOptions.classList.contains('hidden')) {
if (dropdown === moreMenuDropdown && isOpen(languageOptions)) {
closeDropdown(languageOptions);
}
if (dropdown === languageOptions && moreMenuDropdown && !moreMenuDropdown.classList.contains('hidden')) {
if (dropdown === languageOptions && isOpen(moreMenuDropdown)) {
closeDropdown(moreMenuDropdown);
}
openDropdown(dropdown);
@@ -58,31 +69,25 @@ document.addEventListener('DOMContentLoaded', function() {
// Close dropdowns when clicking outside
document.addEventListener('click', function(e) {
if (moreMenuDropdown && !moreMenuButton.contains(e.target) && !moreMenuDropdown.contains(e.target)) {
closeDropdown(moreMenuDropdown);
if (isOpen(moreMenuDropdown)) closeDropdown(moreMenuDropdown);
}
if (languageOptions && !languageSelectorButton.contains(e.target) && !languageOptions.contains(e.target)) {
closeDropdown(languageOptions);
if (isOpen(languageOptions)) closeDropdown(languageOptions);
}
});
// Close dropdowns on Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
if (moreMenuDropdown && !moreMenuDropdown.classList.contains('hidden')) {
closeDropdown(moreMenuDropdown);
}
if (languageOptions && !languageOptions.classList.contains('hidden')) {
closeDropdown(languageOptions);
}
if (isOpen(moreMenuDropdown)) closeDropdown(moreMenuDropdown);
if (isOpen(languageOptions)) closeDropdown(languageOptions);
}
});
// Handle window resize: close mobile overlay if resizing to desktop
window.addEventListener('resize', function() {
if (!isMobile()) {
if (moreMenuDropdown && !moreMenuDropdown.classList.contains('hidden')) {
document.body.style.overflow = '';
}
document.body.style.overflow = '';
}
});
+35 -2
View File
@@ -46,6 +46,39 @@
transition: top 0.3s ease-in-out;
}
/* Animated nav dropdowns.
We toggle a `.menu-open` class instead of `hidden` so that CSS
opacity/transform transitions run on open and close. */
#more-menu-dropdown,
#language-options {
opacity: 0;
pointer-events: none;
transform: translateY(-10px);
transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.28, 0.11, 0.32, 1);
}
#more-menu-dropdown.menu-open,
#language-options.menu-open {
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
/* Mobile: full-screen overlay slides down from the top */
@media (max-width: 767px) {
#more-menu-dropdown {
transform: translateY(-12px);
transition: opacity 0.28s ease, transform 0.32s cubic-bezier(0.28, 0.11, 0.32, 1);
}
}
@media (prefers-reduced-motion: reduce) {
#more-menu-dropdown,
#language-options,
#more-menu-dropdown.menu-open,
#language-options.menu-open {
transition: none;
transform: none;
}
}
/* Line clamp utilities for truncating text */
.line-clamp-2 {
display: -webkit-box;
@@ -71,7 +104,7 @@
<i class="fas fa-bars mr-2"></i>
{% trans "Menu" %}
</button>
<div id="more-menu-dropdown" class="fixed inset-0 top-[57px] w-full rounded-none overflow-y-auto md:absolute md:inset-auto md:top-auto md:right-0 md:mt-2 md:w-48 md:rounded-md md:overflow-visible bg-white shadow-xl z-20 hidden">
<div id="more-menu-dropdown" class="fixed inset-0 top-[57px] w-full rounded-none overflow-y-auto md:absolute md:inset-auto md:top-auto md:right-0 md:mt-2 md:w-48 md:rounded-md md:overflow-visible bg-white shadow-xl z-20">
<div class="grid grid-cols-3 gap-0.5 p-1.5 md:grid-cols-1 md:gap-0 md:p-0">
<a href="{% url 'search' %}" class="flex flex-col items-center justify-center p-2.5 rounded-lg md:flex-row md:justify-start md:px-4 md:py-2 md:rounded-none transition-colors text-gray-700 hover:bg-gray-100">
<svg class="w-6 h-6 mb-1 md:w-5 md:h-5 md:mr-2 md:mb-0 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -233,7 +266,7 @@
{% get_language_info for LANGUAGE_CODE as current_language %}
{{ current_language.code|upper }}
</button>
<div id="language-options" class="absolute right-0 mt-2 py-2 w-48 bg-white rounded-md shadow-xl z-20 hidden">
<div id="language-options" class="absolute right-0 mt-2 py-2 w-48 bg-white rounded-md shadow-xl z-20">
<form action="{% url 'set_language' %}" method="post" id="language-form">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">