Spaces:
Running
Running
| // 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 = ` | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-2 h-2 bg-green-500 rounded-full live-indicator"></div> | |
| <span class="font-medium">Processed ${job.file}</span> | |
| <span class="text-gray-600">– ${job.threat}</span> | |
| </div> | |
| <span class="text-gray-500 text-sm">${job.time}</span> | |
| `; | |
| // 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 | |
| }; |