// Custom dropdown component with liquid glass styling // Replaces native select elements with styled custom dropdowns /** * Initialize custom dropdowns for all select elements */ function initCustomDropdowns() { const selects = document.querySelectorAll('select'); selects.forEach(select => { // Skip if already converted if (select.dataset.customDropdown === 'true') { return; } createCustomDropdown(select); }); } /** * Create a custom dropdown for a select element */ function createCustomDropdown(select) { // Mark as converted select.dataset.customDropdown = 'true'; // Create dropdown container const dropdownContainer = document.createElement('div'); dropdownContainer.className = 'relative'; // Create button const button = document.createElement('button'); button.type = 'button'; button.className = 'w-full px-3 py-2 border-2 border-gray-300/60 rounded-xl backdrop-blur-sm bg-white/40 focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/70 outline-none text-base transition-all shadow-sm text-left flex items-center justify-between'; button.id = select.id + '_button'; // Get selected option text const selectedOption = select.options[select.selectedIndex]; const buttonText = document.createElement('span'); buttonText.className = 'flex-1 text-gray-900'; buttonText.textContent = selectedOption ? selectedOption.text : 'Select...'; button.appendChild(buttonText); // Add chevron icon const chevron = document.createElement('svg'); chevron.className = 'w-5 h-5 text-gray-400 flex-shrink-0 ml-2 transition-transform'; chevron.id = select.id + '_chevron'; chevron.fill = 'none'; chevron.stroke = 'currentColor'; chevron.viewBox = '0 0 24 24'; chevron.innerHTML = ''; button.appendChild(chevron); // Create dropdown menu const menu = document.createElement('div'); menu.className = 'hidden absolute z-50 w-full mt-1 backdrop-blur-xl bg-white/80 rounded-2xl shadow-2xl border border-white/30 overflow-hidden max-h-60 overflow-y-auto'; menu.id = select.id + '_menu'; // Create options Array.from(select.options).forEach((option, index) => { const menuItem = document.createElement('button'); menuItem.type = 'button'; menuItem.className = 'w-full text-left px-4 py-2.5 text-sm text-gray-700 hover:bg-white/40 focus:outline-none focus:bg-white/40 transition-colors'; if (option.value === select.value) { menuItem.className += ' bg-indigo-50/50 text-indigo-600'; } menuItem.textContent = option.text; menuItem.dataset.value = option.value; menuItem.addEventListener('click', () => { select.value = option.value; buttonText.textContent = option.text; select.dispatchEvent(new Event('change', { bubbles: true })); closeDropdown(select.id); // Update selected state menu.querySelectorAll('button').forEach(item => { if (item.dataset.value === option.value) { item.className = 'w-full text-left px-4 py-2.5 text-sm text-indigo-600 bg-indigo-50/50 hover:bg-white/40 focus:outline-none focus:bg-white/40 transition-colors'; } else { item.className = 'w-full text-left px-4 py-2.5 text-sm text-gray-700 hover:bg-white/40 focus:outline-none focus:bg-white/40 transition-colors'; } }); }); menu.appendChild(menuItem); }); // Toggle dropdown button.addEventListener('click', (e) => { e.stopPropagation(); const isOpen = !menu.classList.contains('hidden'); // Close all other dropdowns document.querySelectorAll('[id$="_menu"]').forEach(m => { if (m.id !== menu.id) { m.classList.add('hidden'); const otherChevron = document.getElementById(m.id.replace('_menu', '_chevron')); if (otherChevron) { otherChevron.classList.remove('rotate-180'); } } }); if (isOpen) { closeDropdown(select.id); } else { openDropdown(select.id); } }); // Close on outside click document.addEventListener('click', (e) => { if (!dropdownContainer.contains(e.target)) { closeDropdown(select.id); } }); // Wrap select and add custom elements select.style.display = 'none'; select.style.position = 'absolute'; select.style.opacity = '0'; select.style.pointerEvents = 'none'; dropdownContainer.appendChild(button); dropdownContainer.appendChild(menu); select.parentNode.insertBefore(dropdownContainer, select); dropdownContainer.appendChild(select); // Listen for programmatic changes to select select.addEventListener('change', () => { updateCustomDropdown(select.id); }); } /** * Open dropdown */ function openDropdown(selectId) { const menu = document.getElementById(selectId + '_menu'); const chevron = document.getElementById(selectId + '_chevron'); if (menu) { menu.classList.remove('hidden'); if (chevron) { chevron.classList.add('rotate-180'); } } } /** * Close dropdown */ function closeDropdown(selectId) { const menu = document.getElementById(selectId + '_menu'); const chevron = document.getElementById(selectId + '_chevron'); if (menu) { menu.classList.add('hidden'); if (chevron) { chevron.classList.remove('rotate-180'); } } } /** * Update custom dropdown when select value changes programmatically */ function updateCustomDropdown(selectId) { const select = document.getElementById(selectId); if (!select || select.dataset.customDropdown !== 'true') { return; } const button = document.getElementById(selectId + '_button'); const buttonText = button?.querySelector('span'); const selectedOption = select.options[select.selectedIndex]; if (buttonText && selectedOption) { buttonText.textContent = selectedOption.text; } // Update selected state in menu const menu = document.getElementById(selectId + '_menu'); if (menu) { menu.querySelectorAll('button').forEach(item => { if (item.dataset.value === select.value) { item.className = 'w-full text-left px-4 py-2.5 text-sm text-indigo-600 bg-indigo-50/50 hover:bg-white/40 focus:outline-none focus:bg-white/40 transition-colors'; } else { item.className = 'w-full text-left px-4 py-2.5 text-sm text-gray-700 hover:bg-white/40 focus:outline-none focus:bg-white/40 transition-colors'; } }); } } // Make functions globally accessible if (typeof window !== 'undefined') { window.initCustomDropdowns = initCustomDropdowns; window.createCustomDropdown = createCustomDropdown; window.updateCustomDropdown = updateCustomDropdown; }