// Global functionality for wash.dev
// Initialize the app
document.addEventListener('DOMContentLoaded', function() {
initLiveFeed();
initSmoothScrolling();
initPricingButtons();
});
// Live feed simulation
function initLiveFeed() {
const feed = document.getElementById('live-feed');
if (!feed) return;
const jobs = [
{ file: 'contract.pdf', threat: 'removed 12 zero-width chars, embedded JS', time: '2s ago' },
{ file: 'resume.docx', threat: 'stripped VBA macro, removed metadata', time: '5s ago' },
{ file: 'presentation.pptx', threat: 'cleaned embedded objects, removed scripts', time: '8s ago' },
{ file: 'image.jpg', threat: 'LSB stego in red channel detected', time: '12s ago' },
{ file: 'document.txt', threat: 'removed zero-width injections', time: '15s ago' },
{ file: 'invoice.pdf', threat: 'cleaned form fields, removed JavaScript', time: '18s ago' },
{ file: 'report.docx', threat: 'stripped macros, cleaned metadata', time: '22s ago' },
{ file: 'spreadsheet.xlsx', threat: 'removed embedded scripts', time: '25s ago' }
];
let currentIndex = 0;
function addNewJob() {
const job = jobs[currentIndex % jobs.length];
currentIndex++;
const jobElement = document.createElement('div');
jobElement.className = 'flex items-center justify-between py-3 px-4 bg-green-50 rounded border border-green-200 animate-fade-in-up';
jobElement.innerHTML = `
Processed ${job.file}
– ${job.threat}
${job.time}
`;
// Add to top of feed
feed.insertBefore(jobElement, feed.firstChild);
// Remove jobs older than 10
const jobsElements = feed.children;
if (jobsElements.length > 10) {
feed.removeChild(jobsElements[jobsElements.length - 1]);
}
// Update timestamps
updateTimestamps();
}
function updateTimestamps() {
const jobsElements = feed.children;
let timeCounter = 2;
for (let i = 0; i < jobsElements.length; i++) {
const timeElement = jobsElements[i].querySelector('.text-gray-500');
if (timeElement && !timeElement.textContent.includes('ago')) {
timeElement.textContent = `${timeCounter}s ago`;
timeCounter += 3;
}
}
}
// Add new job every 2 seconds
setInterval(addNewJob, 2000);
}
// Smooth scrolling for navigation
function initSmoothScrolling() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
}
// Pricing button interactions
function initPricingButtons() {
document.querySelectorAll('button').forEach(button => {
button.addEventListener('click', function(e) {
if (this.textContent.includes('Start with') || this.textContent.includes('Buy Credits')) {
e.preventDefault();
// In a real app, this would redirect to checkout
showNotification('Redirecting to secure checkout...', 'success');
setTimeout(() => {
window.location.href = 'app.wash.dev';
}, 1500);
}
});
});
}
// Notification system
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 z-50 px-6 py-4 rounded-lg shadow-lg notification ${
type === 'success' ? 'bg-green-500 text-white' :
type === 'error' ? 'bg-red-500 text-white' :
'bg-blue-500 text-white'
}`;
notification.textContent = message;
document.body.appendChild(notification);
// Auto remove after 3 seconds
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 3000);
}
// Utility functions
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
function formatTime(seconds) {
if (seconds < 60) {
return `${seconds.toFixed(1)}s`;
} else {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = (seconds % 60).toFixed(1);
return `${minutes}m ${remainingSeconds}s`;
}
}
// API simulation
const mockAPI = {
async cleanDocument(file) {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, Math.random() * 3000 + 1000));
const threats = [
'zero-width characters',
'embedded JavaScript',
'LSB steganography',
'VBA macros',
'metadata injections',
'hidden text',
'form field scripts'
];
const foundThreats = [];
const threatCount = Math.floor(Math.random() * 3) + 1;
for (let i = 0; i < threatCount; i++) {
foundThreats.push(threats[Math.floor(Math.random() * threats.length)]);
}
return {
success: true,
threats: foundThreats,
processingTime: Math.random() * 4 + 1,
cleanText: 'Clean document text...',
cleanPDF: 'blob:clean-pdf-data',
metadata: {
originalSize: file.size,
cleanedSize: Math.floor(file.size * 0.85),
threatsRemoved: foundThreats.length
}
};
}
};
// Export for use in other scripts
window.Wash = {
showNotification,
formatBytes,
formatTime,
mockAPI
};