diff --git a/admin-dashboard.html b/admin-dashboard.html index 0e67eb0..3467a36 100644 --- a/admin-dashboard.html +++ b/admin-dashboard.html @@ -206,10 +206,16 @@ z-index: 9999; padding: 2rem; overflow-y: auto; + opacity: 0; + transition: opacity 0.2s ease-in-out; + will-change: opacity; + pointer-events: none; } #iconPickerModal.show { display: block; + opacity: 1; + pointer-events: auto; } #iconPickerContainer { @@ -222,6 +228,13 @@ max-height: calc(100vh - 4rem); display: flex; flex-direction: column; + transform: translateY(20px); + transition: transform 0.2s ease-in-out; + will-change: transform; + } + + #iconPickerModal.show #iconPickerContainer { + transform: translateY(0); } #iconPickerHeader { @@ -2424,47 +2437,82 @@ function initIconPicker() { const iconPickerModal = document.getElementById('iconPickerModal'); const closeButton = document.getElementById('closeIconPicker'); const iconSearch = document.getElementById('iconSearch'); + const iconListContainer = document.getElementById('iconListContainer'); if (!iconInput || !iconPickerModal) return; + // Track if modal is open to prevent multiple clicks + let isModalOpen = false; + // Open modal when clicking the icon input - iconInput.addEventListener('click', function(e) { - e.preventDefault(); - iconPickerModal.classList.add('show'); - document.body.style.overflow = 'hidden'; + const openModal = (e) => { + if (e) e.preventDefault(); + if (isModalOpen) return; - // Focus search input after a short delay to ensure modal is visible + isModalOpen = true; + iconPickerModal.style.display = 'block'; setTimeout(() => { + iconPickerModal.classList.add('show'); + document.body.style.overflow = 'hidden'; + + // Focus search input after a short delay to ensure modal is visible if (iconSearch) { - iconSearch.focus(); + setTimeout(() => { + iconSearch.focus(); + }, 50); } - }, 100); + }, 10); + }; + + // Close modal + const closeModal = () => { + if (!isModalOpen) return; + + iconPickerModal.classList.remove('show'); + setTimeout(() => { + iconPickerModal.style.display = 'none'; + document.body.style.overflow = ''; + isModalOpen = false; + }, 200); // Match this with CSS transition + }; + + // Toggle modal on icon input click + iconInput.addEventListener('click', (e) => { + e.preventDefault(); + if (isModalOpen) { + closeModal(); + } else { + openModal(); + } }); // Close modal when clicking the close button if (closeButton) { - closeButton.addEventListener('click', function() { - iconPickerModal.classList.remove('show'); - document.body.style.overflow = ''; - }); + closeButton.addEventListener('click', closeModal); } - // Close modal when clicking on the overlay (outside the modal) - iconPickerModal.addEventListener('click', function(e) { + // Close modal when clicking outside the modal content + iconPickerModal.addEventListener('click', (e) => { if (e.target === iconPickerModal) { - iconPickerModal.classList.remove('show'); - document.body.style.overflow = ''; + closeModal(); } }); + // Prevent clicks inside the modal from closing it + if (iconListContainer) { + iconListContainer.addEventListener('click', (e) => { + e.stopPropagation(); + }); + } + // Handle search functionality if (iconSearch) { iconSearch.addEventListener('input', function() { renderIcons(this.value.toLowerCase()); }); - // Prevent click events on search input from closing the modal - iconSearch.addEventListener('click', function(e) { + // Prevent click events on search input from propagating + iconSearch.addEventListener('click', (e) => { e.stopPropagation(); }); } @@ -2473,10 +2521,10 @@ function initIconPicker() { renderIcons(''); // Close modal when pressing Escape key - document.addEventListener('keydown', function(e) { - if (e.key === 'Escape' && iconPickerModal.classList.contains('show')) { - iconPickerModal.classList.remove('show'); - document.body.style.overflow = ''; + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && isModalOpen) { + e.preventDefault(); + closeModal(); } }); }