Spaces:
Running
Running
/** | |
* Main JavaScript file for AI Document Analyzer | |
*/ | |
document.addEventListener('DOMContentLoaded', () => { | |
// Initialize tabs | |
initTabs(); | |
// Initialize animations | |
initAnimations(); | |
}); | |
/** | |
* Initialize tab functionality | |
*/ | |
function initTabs() { | |
const tabBtns = document.querySelectorAll('.tab-btn'); | |
const tabContents = document.querySelectorAll('.tab-content'); | |
tabBtns.forEach(btn => { | |
btn.addEventListener('click', () => { | |
// Remove active class from all buttons and contents | |
tabBtns.forEach(b => b.classList.remove('active')); | |
tabContents.forEach(c => c.classList.remove('active')); | |
// Add active class to clicked button and corresponding content | |
btn.classList.add('active'); | |
const tabId = `${btn.dataset.tab}-tab`; | |
document.getElementById(tabId).classList.add('active'); | |
}); | |
}); | |
} | |
/** | |
* Initialize animations | |
*/ | |
function initAnimations() { | |
// Intersection Observer for scroll animations | |
const observer = new IntersectionObserver((entries) => { | |
entries.forEach(entry => { | |
if (entry.isIntersecting) { | |
entry.target.classList.add('appear'); | |
} | |
}); | |
}, { | |
threshold: 0.2 | |
}); | |
// Observe elements that should animate on scroll | |
const animatedElements = document.querySelectorAll('.section-title, .feature-card, .about-content p'); | |
animatedElements.forEach(element => { | |
observer.observe(element); | |
}); | |
} | |
/** | |
* Show loading overlay | |
*/ | |
function showLoading() { | |
const loadingOverlay = document.getElementById('loading-overlay'); | |
loadingOverlay.style.display = 'flex'; | |
} | |
/** | |
* Hide loading overlay | |
*/ | |
function hideLoading() { | |
const loadingOverlay = document.getElementById('loading-overlay'); | |
loadingOverlay.style.display = 'none'; | |
} | |
/** | |
* Display error message | |
* @param {string} message - The error message to display | |
*/ | |
function showError(message) { | |
// Create error notification | |
const notification = document.createElement('div'); | |
notification.className = 'error-notification fade-in'; | |
notification.innerHTML = ` | |
<div class="error-icon"><i class="fas fa-exclamation-circle"></i></div> | |
<div class="error-message">${message}</div> | |
`; | |
// Add to DOM | |
document.body.appendChild(notification); | |
// Remove after delay | |
setTimeout(() => { | |
notification.classList.add('fade-out'); | |
setTimeout(() => { | |
document.body.removeChild(notification); | |
}, 500); | |
}, 4000); | |
} | |
/** | |
* Format file size in human-readable format | |
* @param {number} bytes - File size in bytes | |
* @returns {string} Formatted file size | |
*/ | |
function formatFileSize(bytes) { | |
if (bytes === 0) return '0 Bytes'; | |
const k = 1024; | |
const sizes = ['Bytes', 'KB', 'MB', 'GB']; | |
const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
} | |
/** | |
* Get file extension from filename | |
* @param {string} filename - The name of the file | |
* @returns {string} The file extension | |
*/ | |
function getFileExtension(filename) { | |
return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2).toLowerCase(); | |
} | |
/** | |
* Check if file type is allowed | |
* @param {string} fileType - The type of file | |
* @param {string} allowedTypes - Comma-separated list of allowed types | |
* @returns {boolean} Whether the file type is allowed | |
*/ | |
function isFileTypeAllowed(filename, allowedTypes) { | |
const extension = getFileExtension(filename); | |
const allowedExtensions = allowedTypes.split(',').map(type => type.trim().replace('.', '').toLowerCase()); | |
return allowedExtensions.includes(extension); | |
} |