Add JavaScript utilities

This commit is contained in:
2025-12-10 10:46:31 +11:00
parent e93f3101c6
commit 446414da3e

61
static/js/app.js Normal file
View File

@@ -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');
}
});