Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Smart Report Creator</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* Custom CSS for elements that need more precise control */ | |
| .file-upload-input { | |
| position: absolute; | |
| width: 0.1px; | |
| height: 0.1px; | |
| opacity: 0; | |
| overflow: hidden; | |
| z-index: -1; | |
| } | |
| .file-upload-label { | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.3s; | |
| } | |
| .file-upload-label:hover { | |
| transform: translateY(-2px); | |
| } | |
| .preview-image { | |
| transition: all 0.3s; | |
| } | |
| .preview-image:hover { | |
| transform: scale(1.03); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); | |
| } | |
| #videoElement { | |
| transform: scaleX(-1); /* Mirror the camera preview */ | |
| } | |
| .summary-loading { | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .summary-loading::after { | |
| content: ""; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(255,255,255,0.7), transparent); | |
| animation: loading 1.5s infinite; | |
| } | |
| @keyframes loading { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| /* Custom scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #888; | |
| border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #555; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <header class="mb-8 text-center"> | |
| <h1 class="text-4xl font-bold text-indigo-700 mb-2">Smart Report Creator</h1> | |
| <p class="text-gray-600">Create professional reports with ease - upload files, capture photos, and get AI-powered summaries</p> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> | |
| <!-- Left Column - Report Form --> | |
| <div class="lg:col-span-2 bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="p-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-6">Create New Report</h2> | |
| <!-- Report Title --> | |
| <div class="mb-6"> | |
| <label for="reportTitle" class="block text-sm font-medium text-gray-700 mb-2">Report Title</label> | |
| <input type="text" id="reportTitle" placeholder="Enter report title" | |
| class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition"> | |
| </div> | |
| <!-- Report Content --> | |
| <div class="mb-6"> | |
| <label for="reportContent" class="block text-sm font-medium text-gray-700 mb-2">Report Content</label> | |
| <textarea id="reportContent" rows="8" placeholder="Write your report content here..." | |
| class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition"></textarea> | |
| </div> | |
| <!-- File Upload Section --> | |
| <div class="mb-6"> | |
| <label class="block text-sm font-medium text-gray-700 mb-2">Attachments</label> | |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> | |
| <!-- File Upload --> | |
| <div> | |
| <input type="file" id="fileUpload" class="file-upload-input" multiple> | |
| <label for="fileUpload" class="file-upload-label bg-indigo-50 text-indigo-700 px-4 py-8 rounded-lg border-2 border-dashed border-indigo-300"> | |
| <div class="text-center"> | |
| <i class="fas fa-file-upload text-3xl mb-2"></i> | |
| <p class="font-medium">Upload Files</p> | |
| <p class="text-xs text-gray-500 mt-1">PDF, Word, Excel, etc.</p> | |
| </div> | |
| </label> | |
| </div> | |
| <!-- Photo Capture --> | |
| <div> | |
| <button id="openCameraBtn" class="file-upload-label w-full bg-blue-50 text-blue-700 px-4 py-8 rounded-lg border-2 border-dashed border-blue-300"> | |
| <div class="text-center"> | |
| <i class="fas fa-camera text-3xl mb-2"></i> | |
| <p class="font-medium">Capture Photo</p> | |
| <p class="text-xs text-gray-500 mt-1">Use your camera</p> | |
| </div> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Preview Area --> | |
| <div id="previewArea" class="mt-4 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 hidden"> | |
| <!-- Preview items will be added here dynamically --> | |
| </div> | |
| </div> | |
| <!-- Submit Button --> | |
| <div class="flex justify-end"> | |
| <button id="generateSummaryBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg font-medium flex items-center transition"> | |
| <i class="fas fa-magic mr-2"></i> Generate Summary | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Column - Summary and Actions --> | |
| <div class="space-y-6"> | |
| <!-- AI Summary Card --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="bg-indigo-600 px-4 py-3"> | |
| <h3 class="text-white font-medium flex items-center"> | |
| <i class="fas fa-robot mr-2"></i> AI Summary | |
| </h3> | |
| </div> | |
| <div class="p-4"> | |
| <div id="summaryContent" class="text-gray-700 min-h-40 summary-loading hidden"> | |
| <!-- Summary will appear here --> | |
| </div> | |
| <div id="emptySummary" class="text-gray-500 text-center py-8"> | |
| <i class="fas fa-comment-alt text-3xl mb-2 opacity-30"></i> | |
| <p>Your AI-generated summary will appear here</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Quick Actions --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="bg-gray-800 px-4 py-3"> | |
| <h3 class="text-white font-medium flex items-center"> | |
| <i class="fas fa-bolt mr-2"></i> Quick Actions | |
| </h3> | |
| </div> | |
| <div class="p-4 grid grid-cols-2 gap-3"> | |
| <button class="bg-green-50 text-green-700 px-3 py-2 rounded-lg flex items-center justify-center text-sm font-medium"> | |
| <i class="fas fa-save mr-2"></i> Save Draft | |
| </button> | |
| <button class="bg-purple-50 text-purple-700 px-3 py-2 rounded-lg flex items-center justify-center text-sm font-medium"> | |
| <i class="fas fa-share-alt mr-2"></i> Share | |
| </button> | |
| <button class="bg-yellow-50 text-yellow-700 px-3 py-2 rounded-lg flex items-center justify-center text-sm font-medium"> | |
| <i class="fas fa-print mr-2"></i> Print | |
| </button> | |
| <button class="bg-red-50 text-red-700 px-3 py-2 rounded-lg flex items-center justify-center text-sm font-medium"> | |
| <i class="fas fa-file-pdf mr-2"></i> Export PDF | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Recent Reports --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="bg-gray-100 px-4 py-3 border-b"> | |
| <h3 class="text-gray-800 font-medium flex items-center"> | |
| <i class="fas fa-history mr-2"></i> Recent Reports | |
| </h3> | |
| </div> | |
| <div class="p-4 space-y-3"> | |
| <div class="flex items-start"> | |
| <div class="bg-indigo-100 text-indigo-800 p-2 rounded-lg mr-3"> | |
| <i class="fas fa-file-alt"></i> | |
| </div> | |
| <div> | |
| <p class="font-medium text-sm">Quarterly Sales Report</p> | |
| <p class="text-xs text-gray-500">Yesterday, 3:45 PM</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 text-blue-800 p-2 rounded-lg mr-3"> | |
| <i class="fas fa-chart-line"></i> | |
| </div> | |
| <div> | |
| <p class="font-medium text-sm">Marketing Analysis</p> | |
| <p class="text-xs text-gray-500">Monday, 10:20 AM</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-green-100 text-green-800 p-2 rounded-lg mr-3"> | |
| <i class="fas fa-clipboard-check"></i> | |
| </div> | |
| <div> | |
| <p class="font-medium text-sm">Project Status Update</p> | |
| <p class="text-xs text-gray-500">Last week</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Camera Modal --> | |
| <div id="cameraModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-lg overflow-hidden w-full max-w-md"> | |
| <div class="bg-gray-800 px-4 py-3 flex justify-between items-center"> | |
| <h3 class="text-white font-medium">Capture Photo</h3> | |
| <button id="closeCameraBtn" class="text-white hover:text-gray-300"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-4"> | |
| <div class="relative bg-gray-200 rounded-lg overflow-hidden mb-4" style="padding-top: 56.25%;"> | |
| <video id="videoElement" autoplay playsinline class="absolute top-0 left-0 w-full h-full object-cover"></video> | |
| <canvas id="canvasElement" class="hidden"></canvas> | |
| </div> | |
| <div class="flex justify-center"> | |
| <button id="captureBtn" class="bg-red-500 hover:bg-red-600 text-white p-3 rounded-full mx-2"> | |
| <i class="fas fa-camera text-xl"></i> | |
| </button> | |
| <button id="retakeBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg hidden"> | |
| Retake | |
| </button> | |
| <button id="usePhotoBtn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg ml-2 hidden"> | |
| Use Photo | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Success Toast --> | |
| <div id="successToast" class="fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg flex items-center transform translate-y-10 opacity-0 transition-all duration-300 z-50"> | |
| <i class="fas fa-check-circle mr-2"></i> | |
| <span>Report saved successfully!</span> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const fileUploadInput = document.getElementById('fileUpload'); | |
| const previewArea = document.getElementById('previewArea'); | |
| const openCameraBtn = document.getElementById('openCameraBtn'); | |
| const cameraModal = document.getElementById('cameraModal'); | |
| const closeCameraBtn = document.getElementById('closeCameraBtn'); | |
| const videoElement = document.getElementById('videoElement'); | |
| const canvasElement = document.getElementById('canvasElement'); | |
| const captureBtn = document.getElementById('captureBtn'); | |
| const retakeBtn = document.getElementById('retakeBtn'); | |
| const usePhotoBtn = document.getElementById('usePhotoBtn'); | |
| const generateSummaryBtn = document.getElementById('generateSummaryBtn'); | |
| const summaryContent = document.getElementById('summaryContent'); | |
| const emptySummary = document.getElementById('emptySummary'); | |
| const successToast = document.getElementById('successToast'); | |
| let stream = null; | |
| let capturedImage = null; | |
| // File Upload Handling | |
| fileUploadInput.addEventListener('change', function(e) { | |
| const files = e.target.files; | |
| if (files.length > 0) { | |
| previewArea.classList.remove('hidden'); | |
| for (let i = 0; i < files.length; i++) { | |
| const file = files[i]; | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| const previewItem = document.createElement('div'); | |
| previewItem.className = 'preview-item bg-gray-100 rounded-lg overflow-hidden relative'; | |
| let previewContent = ''; | |
| let iconClass = 'fas fa-file'; | |
| let bgClass = 'bg-gray-200'; | |
| if (file.type.startsWith('image/')) { | |
| previewContent = `<img src="${e.target.result}" alt="Preview" class="w-full h-24 object-cover preview-image">`; | |
| iconClass = 'fas fa-image'; | |
| bgClass = 'bg-blue-200'; | |
| } else if (file.type.includes('pdf')) { | |
| previewContent = `<div class="w-full h-24 flex items-center justify-center ${bgClass}"> | |
| <i class="${iconClass} text-3xl text-gray-600"></i> | |
| </div>`; | |
| iconClass = 'fas fa-file-pdf'; | |
| bgClass = 'bg-red-200'; | |
| } else if (file.type.includes('word') || file.type.includes('document')) { | |
| previewContent = `<div class="w-full h-24 flex items-center justify-center ${bgClass}"> | |
| <i class="${iconClass} text-3xl text-gray-600"></i> | |
| </div>`; | |
| iconClass = 'fas fa-file-word'; | |
| bgClass = 'bg-blue-200'; | |
| } else if (file.type.includes('excel') || file.type.includes('spreadsheet')) { | |
| previewContent = `<div class="w-full h-24 flex items-center justify-center ${bgClass}"> | |
| <i class="${iconClass} text-3xl text-gray-600"></i> | |
| </div>`; | |
| iconClass = 'fas fa-file-excel'; | |
| bgClass = 'bg-green-200'; | |
| } else { | |
| previewContent = `<div class="w-full h-24 flex items-center justify-center ${bgClass}"> | |
| <i class="${iconClass} text-3xl text-gray-600"></i> | |
| </div>`; | |
| } | |
| previewItem.innerHTML = ` | |
| ${previewContent} | |
| <div class="p-2"> | |
| <p class="text-xs font-medium truncate">${file.name}</p> | |
| <p class="text-xs text-gray-500">${formatFileSize(file.size)}</p> | |
| </div> | |
| <button class="absolute top-1 right-1 bg-white bg-opacity-80 rounded-full p-1 text-xs hover:bg-red-100 hover:text-red-600 transition"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| `; | |
| previewArea.appendChild(previewItem); | |
| // Add click event for remove button | |
| const removeBtn = previewItem.querySelector('button'); | |
| removeBtn.addEventListener('click', function() { | |
| previewItem.remove(); | |
| if (previewArea.children.length === 0) { | |
| previewArea.classList.add('hidden'); | |
| } | |
| }); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| } | |
| }); | |
| // Camera Modal Handling | |
| openCameraBtn.addEventListener('click', openCameraModal); | |
| closeCameraBtn.addEventListener('click', closeCameraModal); | |
| function openCameraModal() { | |
| cameraModal.classList.remove('hidden'); | |
| startCamera(); | |
| } | |
| function closeCameraModal() { | |
| cameraModal.classList.add('hidden'); | |
| stopCamera(); | |
| resetCameraUI(); | |
| } | |
| // Camera Functions | |
| async function startCamera() { | |
| try { | |
| stream = await navigator.mediaDevices.getUserMedia({ | |
| video: { | |
| width: { ideal: 1280 }, | |
| height: { ideal: 720 }, | |
| facingMode: 'environment' | |
| } | |
| }); | |
| videoElement.srcObject = stream; | |
| } catch (err) { | |
| console.error("Error accessing camera: ", err); | |
| alert("Could not access the camera. Please make sure you've granted camera permissions."); | |
| } | |
| } | |
| function stopCamera() { | |
| if (stream) { | |
| stream.getTracks().forEach(track => track.stop()); | |
| stream = null; | |
| } | |
| } | |
| // Capture Photo | |
| captureBtn.addEventListener('click', function() { | |
| const videoWidth = videoElement.videoWidth; | |
| const videoHeight = videoElement.videoHeight; | |
| canvasElement.width = videoWidth; | |
| canvasElement.height = videoHeight; | |
| const ctx = canvasElement.getContext('2d'); | |
| ctx.drawImage(videoElement, 0, 0, videoWidth, videoHeight); | |
| capturedImage = canvasElement.toDataURL('image/jpeg'); | |
| // Update UI | |
| videoElement.classList.add('hidden'); | |
| canvasElement.classList.remove('hidden'); | |
| captureBtn.classList.add('hidden'); | |
| retakeBtn.classList.remove('hidden'); | |
| usePhotoBtn.classList.remove('hidden'); | |
| }); | |
| // Retake Photo | |
| retakeBtn.addEventListener('click', function() { | |
| videoElement.classList.remove('hidden'); | |
| canvasElement.classList.add('hidden'); | |
| captureBtn.classList.remove('hidden'); | |
| retakeBtn.classList.add('hidden'); | |
| usePhotoBtn.classList.add('hidden'); | |
| }); | |
| // Use Photo | |
| usePhotoBtn.addEventListener('click', function() { | |
| if (capturedImage) { | |
| previewArea.classList.remove('hidden'); | |
| const previewItem = document.createElement('div'); | |
| previewItem.className = 'preview-item bg-gray-100 rounded-lg overflow-hidden relative'; | |
| previewItem.innerHTML = ` | |
| <img src="${capturedImage}" alt="Captured Photo" class="w-full h-24 object-cover preview-image"> | |
| <div class="p-2"> | |
| <p class="text-xs font-medium">Photo ${new Date().toLocaleTimeString()}</p> | |
| <p class="text-xs text-gray-500">JPEG Image</p> | |
| </div> | |
| <button class="absolute top-1 right-1 bg-white bg-opacity-80 rounded-full p-1 text-xs hover:bg-red-100 hover:text-red-600 transition"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| `; | |
| previewArea.appendChild(previewItem); | |
| // Add click event for remove button | |
| const removeBtn = previewItem.querySelector('button'); | |
| removeBtn.addEventListener('click', function() { | |
| previewItem.remove(); | |
| if (previewArea.children.length === 0) { | |
| previewArea.classList.add('hidden'); | |
| } | |
| }); | |
| closeCameraModal(); | |
| } | |
| }); | |
| function resetCameraUI() { | |
| videoElement.classList.remove('hidden'); | |
| canvasElement.classList.add('hidden'); | |
| captureBtn.classList.remove('hidden'); | |
| retakeBtn.classList.add('hidden'); | |
| usePhotoBtn.classList.add('hidden'); | |
| capturedImage = null; | |
| } | |
| // Generate Summary | |
| generateSummaryBtn.addEventListener('click', function() { | |
| const reportTitle = document.getElementById('reportTitle').value; | |
| const reportContent = document.getElementById('reportContent').value; | |
| if (!reportTitle && !reportContent) { | |
| alert('Please enter some content to generate a summary'); | |
| return; | |
| } | |
| // Show loading state | |
| emptySummary.classList.add('hidden'); | |
| summaryContent.classList.remove('hidden'); | |
| summaryContent.innerHTML = '<div class="animate-pulse space-y-2"><div class="h-4 bg-gray-200 rounded w-full"></div><div class="h-4 bg-gray-200 rounded w-5/6"></div><div class="h-4 bg-gray-200 rounded w-4/6"></div><div class="h-4 bg-gray-200 rounded w-5/6"></div></div>'; | |
| // Simulate AI processing (in a real app, this would be an API call) | |
| setTimeout(() => { | |
| const mockSummary = generateMockSummary(reportTitle, reportContent); | |
| summaryContent.innerHTML = mockSummary; | |
| // Show success toast | |
| showToast(); | |
| }, 2000); | |
| }); | |
| function generateMockSummary(title, content) { | |
| if (!content) content = "No content provided"; | |
| const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 0); | |
| const summarySentences = sentences.slice(0, Math.min(3, sentences.length)); | |
| let summary = `<h4 class="font-medium text-lg mb-2">Summary of "${title || 'Untitled Report'}"</h4>`; | |
| if (summarySentences.length > 0) { | |
| summary += '<ul class="list-disc pl-5 space-y-1">'; | |
| summarySentences.forEach(s => { | |
| summary += `<li>${s.trim()}.</li>`; | |
| }); | |
| summary += '</ul>'; | |
| } else { | |
| summary += '<p>This report appears to be very short. Consider adding more details for a comprehensive summary.</p>'; | |
| } | |
| // Add key points | |
| const words = content.toLowerCase().split(/\s+/).filter(w => w.length > 3); | |
| const wordCount = {}; | |
| words.forEach(w => { | |
| wordCount[w] = (wordCount[w] || 0) + 1; | |
| }); | |
| const sortedWords = Object.keys(wordCount).sort((a, b) => wordCount[b] - wordCount[a]); | |
| const keyWords = sortedWords.slice(0, 5).filter(w => !['that', 'this', 'with', 'your', 'they', 'have'].includes(w)); | |
| if (keyWords.length > 0) { | |
| summary += `<div class="mt-4"> | |
| <h5 class="font-medium mb-1">Key Topics:</h5> | |
| <div class="flex flex-wrap gap-2">`; | |
| keyWords.forEach(w => { | |
| summary += `<span class="bg-indigo-100 text-indigo-800 text-xs px-2 py-1 rounded">${w}</span>`; | |
| }); | |
| summary += `</div></div>`; | |
| } | |
| // Add sentiment analysis | |
| const positiveWords = ['good', 'great', 'excellent', 'success', 'improve', 'happy']; | |
| const negativeWords = ['bad', 'poor', 'failure', 'problem', 'issue', 'unhappy']; | |
| let positiveCount = 0; | |
| let negativeCount = 0; | |
| words.forEach(w => { | |
| if (positiveWords.includes(w)) positiveCount++; | |
| if (negativeWords.includes(w)) negativeCount++; | |
| }); | |
| summary += `<div class="mt-4"> | |
| <h5 class="font-medium mb-1">Sentiment Analysis:</h5> | |
| <div class="flex items-center"> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div class="bg-green-500 h-2.5 rounded-full" style="width: ${Math.min(100, (positiveCount / (positiveCount + negativeCount + 1)) * 100)}%"></div> | |
| </div> | |
| <span class="ml-2 text-sm text-gray-600">${positiveCount > negativeCount ? 'Mostly Positive' : positiveCount < negativeCount ? 'Mostly Negative' : 'Neutral'}</span> | |
| </div> | |
| </div>`; | |
| return summary; | |
| } | |
| // Helper Functions | |
| 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]; | |
| } | |
| function showToast() { | |
| successToast.classList.remove('translate-y-10', 'opacity-0'); | |
| successToast.classList.add('translate-y-0', 'opacity-100'); | |
| setTimeout(() => { | |
| successToast.classList.remove('translate-y-0', 'opacity-100'); | |
| successToast.classList.add('translate-y-10', 'opacity-0'); | |
| }, 3000); | |
| } | |
| // Close modal when clicking outside | |
| cameraModal.addEventListener('click', function(e) { | |
| if (e.target === cameraModal) { | |
| closeCameraModal(); | |
| } | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://deepsite.hf.co/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://deepsite.hf.co" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://deepsite.hf.co?remix=soiler01/smart-report" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |