This commit is contained in:
Tomas Dvorak
2025-05-30 12:34:50 +02:00
parent d16a3e938b
commit d8f2257db2
+60 -129
View File
@@ -1214,21 +1214,23 @@
</div> </div>
</div> </div>
<!-- Icon Picker Dropdown --> <!-- Icon Picker Container -->
<div id="iconPickerDropdown" class="hidden absolute z-50 bg-white rounded-lg shadow-lg border border-gray-200 w-full max-w-[400px]"> <div id="iconPickerContainer" class="relative">
<div class="p-4"> <div id="iconPickerDropdown" class="hidden absolute z-50 bg-white rounded-lg shadow-lg border border-gray-200 w-full max-w-[400px]">
<div class="flex justify-between items-center mb-4"> <div class="p-4">
<h3 class="text-sm font-medium text-gray-700">Vyberte ikonu</h3> <div class="flex justify-between items-center mb-4">
<button id="closeIconPicker" class="text-gray-400 hover:text-gray-500 p-1"> <h3 class="text-sm font-medium text-gray-700">Vyberte ikonu</h3>
<i class="fas fa-times"></i> <button id="closeIconPicker" class="text-gray-400 hover:text-gray-500 p-1">
</button> <i class="fas fa-times"></i>
</div> </button>
<div class="mb-4"> </div>
<input type="text" id="iconSearch" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Hledat ikony..." autocomplete="off"> <div class="mb-4">
</div> <input type="text" id="iconSearch" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Hledat ikony..." autocomplete="off">
<div class="max-h-[400px] overflow-y-auto"> </div>
<div id="iconList" class="grid grid-cols-4 gap-3"> <div class="max-h-[400px] overflow-y-auto">
<!-- Icons will be populated by JavaScript --> <div id="iconList" class="grid grid-cols-4 gap-3">
<!-- Icons will be populated by JavaScript -->
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -2443,96 +2445,67 @@ function initIconPicker() {
if (!iconInput || !iconDropdown) return; if (!iconInput || !iconDropdown) return;
let isDropdownOpen = false; // Simple toggle function
let isMouseOverDropdown = false; function toggleDropdown() {
let isMouseOverInput = false; iconDropdown.classList.toggle('hidden');
if (!iconDropdown.classList.contains('hidden')) {
// Position dropdown relative to input // Position and focus
function positionDropdown() { const rect = iconInput.getBoundingClientRect();
const rect = iconInput.getBoundingClientRect(); iconDropdown.style.top = `${rect.bottom + window.scrollY}px`;
iconDropdown.style.top = `${rect.bottom + window.scrollY}px`; iconDropdown.style.left = `${rect.left + window.scrollX}px`;
iconDropdown.style.left = `${rect.left + window.scrollX}px`; iconDropdown.style.width = `${rect.width}px`;
iconDropdown.style.width = `${rect.width}px`;
} if (iconSearch) {
iconSearch.value = '';
// Toggle dropdown renderIcons('');
function toggleDropdown(open) { iconSearch.focus();
if (open !== undefined) { }
isDropdownOpen = open;
} else {
isDropdownOpen = !isDropdownOpen;
}
iconDropdown.classList.toggle('hidden', !isDropdownOpen);
if (isDropdownOpen) {
positionDropdown();
requestAnimationFrame(() => {
if (iconSearch) {
iconSearch.value = '';
renderIcons('');
iconSearch.focus();
}
});
} }
} }
// Handle mouse enter/leave events // Close dropdown
iconInput.addEventListener('mouseenter', () => { function closeDropdown() {
isMouseOverInput = true; iconDropdown.classList.add('hidden');
});
iconInput.addEventListener('mouseleave', () => {
isMouseOverInput = false;
});
iconDropdown.addEventListener('mouseenter', () => {
isMouseOverDropdown = true;
});
iconDropdown.addEventListener('mouseleave', () => {
isMouseOverDropdown = false;
});
// Handle click outside
function handleClickOutside(e) {
if (isDropdownOpen && !isMouseOverDropdown && !isMouseOverInput) {
toggleDropdown(false);
}
} }
// Handle icon input click // Handle icon input click
iconInput.addEventListener('click', (e) => { iconInput.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
toggleDropdown(true); toggleDropdown();
}); });
// Close dropdown handlers
if (closeButton) {
closeButton.addEventListener('click', (e) => {
e.stopPropagation();
toggleDropdown(false);
});
}
// Close when clicking outside // Close when clicking outside
document.addEventListener('click', handleClickOutside); document.addEventListener('click', (e) => {
if (!iconDropdown.classList.contains('hidden') &&
!iconDropdown.contains(e.target) &&
e.target !== iconInput) {
closeDropdown();
}
});
// Close on Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !iconDropdown.classList.contains('hidden')) {
closeDropdown();
}
});
// Handle icon selection // Handle icon selection
if (iconList) { if (iconList) {
iconList.addEventListener('click', (e) => { iconList.addEventListener('click', (e) => {
const iconOption = e.target.closest('.icon-option'); const iconOption = e.target.closest('.icon-option');
if (iconOption && isDropdownOpen) { if (iconOption && !iconDropdown.classList.contains('hidden')) {
const iconClass = iconOption.getAttribute('data-icon'); const iconClass = iconOption.getAttribute('data-icon');
if (iconClass) { if (iconClass) {
selectIcon(iconClass); selectIcon(iconClass);
toggleDropdown(false); closeDropdown();
} }
} }
}); });
} }
// Handle search with improved debounce // Handle search
if (iconSearch) { if (iconSearch) {
let searchTimeout; let searchTimeout;
iconSearch.addEventListener('input', (e) => { iconSearch.addEventListener('input', (e) => {
@@ -2547,56 +2520,14 @@ function initIconPicker() {
// Initial render // Initial render
renderIcons(''); renderIcons('');
// Close on Escape // Cleanup on window unload
document.addEventListener('keydown', (e) => { window.addEventListener('unload', () => {
if (e.key === 'Escape' && isDropdownOpen) { iconInput.removeEventListener('click', toggleDropdown);
toggleDropdown(false); document.removeEventListener('click', closeDropdown);
} document.removeEventListener('keydown', closeDropdown);
if (iconList) iconList.removeEventListener('click', selectIcon);
if (iconSearch) iconSearch.removeEventListener('input', renderIcons);
}); });
// Update position on scroll
window.addEventListener('scroll', () => {
if (isDropdownOpen) {
positionDropdown();
}
});
// Update position on window resize
window.addEventListener('resize', () => {
if (isDropdownOpen) {
positionDropdown();
}
});
// Clean up event listeners when component is removed
const cleanup = () => {
iconInput.removeEventListener('mouseenter', () => {
isMouseOverInput = true;
});
iconInput.removeEventListener('mouseleave', () => {
isMouseOverInput = false;
});
iconDropdown.removeEventListener('mouseenter', () => {
isMouseOverDropdown = true;
});
iconDropdown.removeEventListener('mouseleave', () => {
isMouseOverDropdown = false;
});
document.removeEventListener('click', handleClickOutside);
window.removeEventListener('scroll', () => {
if (isDropdownOpen) {
positionDropdown();
}
});
window.removeEventListener('resize', () => {
if (isDropdownOpen) {
positionDropdown();
}
});
};
// Add cleanup to window beforeunload
window.addEventListener('beforeunload', cleanup);
} }
// Render icons based on search term // Render icons based on search term