diff --git a/static/js/app.js b/static/js/app.js new file mode 100644 index 0000000..66cf1d2 --- /dev/null +++ b/static/js/app.js @@ -0,0 +1,61 @@ +/* ===================================================== + Raccoon Timekeeper - JavaScript Utilities + ===================================================== */ + +// Format minutes to H:MM +function formatMinutes(totalMinutes) { + if (!totalMinutes) return '0:00'; + const hours = Math.floor(totalMinutes / 60); + const mins = totalMinutes % 60; + return `${hours}:${mins.toString().padStart(2, '0')}`; +} + +// Show toast notification +function showToast(message, type = 'success') { + const container = document.getElementById('toastContainer'); + if (!container) return; + + const toast = document.createElement('div'); + toast.className = `toast toast-${type}`; + toast.textContent = message; + container.appendChild(toast); + + setTimeout(() => { + toast.style.opacity = '0'; + setTimeout(() => toast.remove(), 300); + }, 3000); +} + +// Toggle user dropdown menu +function toggleUserMenu() { + const dropdown = document.getElementById('userDropdown'); + if (dropdown) { + dropdown.classList.toggle('active'); + } +} + +// Close dropdown when clicking outside +document.addEventListener('click', function(e) { + const userMenu = document.querySelector('.user-menu'); + const dropdown = document.getElementById('userDropdown'); + + if (userMenu && dropdown && !userMenu.contains(e.target)) { + dropdown.classList.remove('active'); + } +}); + +// Close modals with Escape key +document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + document.querySelectorAll('.modal.active').forEach(modal => { + modal.classList.remove('active'); + }); + } +}); + +// Close modal when clicking backdrop +document.addEventListener('click', function(e) { + if (e.target.classList.contains('modal')) { + e.target.classList.remove('active'); + } +});