Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Extension Updater Tool</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> | |
| .drag-area { | |
| border: 2px dashed #ccc; | |
| transition: all 0.3s ease; | |
| } | |
| .drag-area.active { | |
| border-color: #4f46e5; | |
| background-color: #eef2ff; | |
| } | |
| .feature-card { | |
| transition: transform 0.2s ease, box-shadow 0.2s ease; | |
| } | |
| .feature-card:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
| } | |
| .progress-bar { | |
| transition: width 0.5s ease; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.5; } | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| </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-3xl md:text-4xl font-bold text-indigo-700 mb-2">Extension Updater</h1> | |
| <p class="text-gray-600 max-w-2xl mx-auto">Analyze and incorporate features from other extensions into your own</p> | |
| </header> | |
| <!-- Main Content --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> | |
| <!-- Left Panel - Upload and Analyze --> | |
| <div class="lg:col-span-2 space-y-6"> | |
| <!-- Upload Section --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Upload Extension Data</h2> | |
| <div class="drag-area border-2 border-dashed rounded-lg p-8 text-center cursor-pointer mb-4" | |
| id="dropZone"> | |
| <div class="icon text-indigo-500 mb-3"> | |
| <i class="fas fa-cloud-upload-alt text-4xl"></i> | |
| </div> | |
| <header class="font-medium text-gray-700">Drag & Drop to Upload</header> | |
| <span class="text-gray-500 block my-2">or</span> | |
| <button class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition"> | |
| Browse Files | |
| </button> | |
| <input type="file" id="fileInput" class="hidden" accept=".json,.zip,.crx" multiple> | |
| </div> | |
| <div class="flex flex-wrap gap-2 mb-4"> | |
| <span class="bg-indigo-100 text-indigo-800 px-3 py-1 rounded-full text-sm">.json</span> | |
| <span class="bg-indigo-100 text-indigo-800 px-3 py-1 rounded-full text-sm">.zip</span> | |
| <span class="bg-indigo-100 text-indigo-800 px-3 py-1 rounded-full text-sm">.crx</span> | |
| </div> | |
| </div> | |
| <!-- Analysis Results --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Analysis Results</h2> | |
| <div class="space-y-4" id="analysisResults"> | |
| <div class="p-4 bg-gray-100 rounded-lg text-center text-gray-500"> | |
| <i class="fas fa-microscope text-2xl mb-2"></i> | |
| <p>Upload extension files to begin analysis</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Panel - Your Extension --> | |
| <div class="space-y-6"> | |
| <!-- Your Extension Info --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Your Extension</h2> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mr-3"> | |
| <i class="fas fa-puzzle-piece text-indigo-600 text-xl"></i> | |
| </div> | |
| <div> | |
| <h3 class="font-medium" id="extensionName">My Awesome Extension</h3> | |
| <p class="text-sm text-gray-500" id="extensionVersion">v1.0.0</p> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Version</label> | |
| <input type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" id="versionInput" value="1.0.0"> | |
| </div> | |
| <div class="mb-4"> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Description</label> | |
| <textarea class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" rows="3" id="descriptionInput">My custom browser extension</textarea> | |
| </div> | |
| </div> | |
| <!-- Update Progress --> | |
| <div class="bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Update Progress</h2> | |
| <div class="mb-4"> | |
| <div class="flex justify-between text-sm text-gray-600 mb-1"> | |
| <span>Update Status</span> | |
| <span id="progressPercent">0%</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%" id="progressBar"></div> | |
| </div> | |
| </div> | |
| <button class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition flex items-center justify-center gap-2 disabled:opacity-50" id="updateButton" disabled> | |
| <i class="fas fa-sync-alt"></i> | |
| <span>Update Extension</span> | |
| </button> | |
| <div class="mt-4 text-sm text-gray-500 hidden" id="updateMessage"> | |
| <i class="fas fa-info-circle mr-1"></i> | |
| <span id="messageText"></span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Feature Comparison --> | |
| <div class="mt-8 bg-white rounded-xl shadow-md p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Feature Comparison</h2> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Feature</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Source Extension</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Your Extension</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200" id="featureTable"> | |
| <tr> | |
| <td colspan="4" class="px-6 py-4 text-center text-gray-500"> | |
| Upload files to compare features | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const dropZone = document.getElementById('dropZone'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const analysisResults = document.getElementById('analysisResults'); | |
| const featureTable = document.getElementById('featureTable'); | |
| const updateButton = document.getElementById('updateButton'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const progressPercent = document.getElementById('progressPercent'); | |
| const updateMessage = document.getElementById('updateMessage'); | |
| const messageText = document.getElementById('messageText'); | |
| // Drag and drop functionality | |
| dropZone.addEventListener('click', () => fileInput.click()); | |
| ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
| dropZone.addEventListener(eventName, preventDefaults, false); | |
| }); | |
| function preventDefaults(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| } | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| dropZone.addEventListener(eventName, highlight, false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| dropZone.addEventListener(eventName, unhighlight, false); | |
| }); | |
| function highlight() { | |
| dropZone.classList.add('active'); | |
| } | |
| function unhighlight() { | |
| dropZone.classList.remove('active'); | |
| } | |
| dropZone.addEventListener('drop', handleDrop, false); | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| handleFiles(files); | |
| } | |
| fileInput.addEventListener('change', function() { | |
| handleFiles(this.files); | |
| }); | |
| function handleFiles(files) { | |
| if (files.length === 0) return; | |
| // Simulate analysis (in a real app, you would process the files) | |
| analysisResults.innerHTML = ` | |
| <div class="p-4 bg-blue-50 rounded-lg flex items-start"> | |
| <div class="mr-3 text-blue-500"> | |
| <i class="fas fa-spinner fa-spin text-xl"></i> | |
| </div> | |
| <div> | |
| <h3 class="font-medium text-blue-800">Analyzing ${files.length} file(s)...</h3> | |
| <p class="text-sm text-blue-600">This may take a few moments</p> | |
| </div> | |
| </div> | |
| `; | |
| setTimeout(() => { | |
| showAnalysisResults(files); | |
| updateButton.disabled = false; | |
| }, 2000); | |
| } | |
| function showAnalysisResults(files) { | |
| // Mock data - in a real app this would come from actual analysis | |
| const mockFeatures = [ | |
| { | |
| name: "Dark Mode", | |
| description: "Adds dark theme support", | |
| sourceHas: true, | |
| yourHas: false, | |
| compatible: true | |
| }, | |
| { | |
| name: "Keyboard Shortcuts", | |
| description: "Customizable keyboard commands", | |
| sourceHas: true, | |
| yourHas: true, | |
| compatible: true | |
| }, | |
| { | |
| name: "Data Export", | |
| description: "Export extension data to JSON", | |
| sourceHas: true, | |
| yourHas: false, | |
| compatible: true | |
| }, | |
| { | |
| name: "Cloud Sync", | |
| description: "Sync settings across devices", | |
| sourceHas: true, | |
| yourHas: false, | |
| compatible: false, | |
| reason: "Requires backend service" | |
| } | |
| ]; | |
| // Update analysis results | |
| analysisResults.innerHTML = ` | |
| <div class="p-4 bg-green-50 rounded-lg mb-4"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <h3 class="font-medium text-green-800">Analysis Complete</h3> | |
| <span class="bg-green-100 text-green-800 px-2 py-1 rounded-full text-xs">${files.length} file(s)</span> | |
| </div> | |
| <p class="text-sm text-green-600 mb-3">Found ${mockFeatures.length} features to analyze</p> | |
| <div class="flex flex-wrap gap-2"> | |
| <span class="bg-green-100 text-green-800 px-2 py-1 rounded-full text-xs">${mockFeatures.filter(f => f.compatible).length} compatible</span> | |
| <span class="bg-yellow-100 text-yellow-800 px-2 py-1 rounded-full text-xs">${mockFeatures.filter(f => !f.compatible).length} incompatible</span> | |
| </div> | |
| </div> | |
| `; | |
| // Update feature comparison table | |
| featureTable.innerHTML = mockFeatures.map(feature => ` | |
| <tr class="${feature.compatible ? '' : 'bg-gray-50'}"> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="font-medium text-gray-900">${feature.name}</div> | |
| <div class="text-sm text-gray-500">${feature.description}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| ${feature.sourceHas ? | |
| '<span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">Available</span>' : | |
| '<span class="px-2 py-1 bg-gray-100 text-gray-800 rounded-full text-xs">Not Available</span>'} | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| ${feature.yourHas ? | |
| '<span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">Available</span>' : | |
| '<span class="px-2 py-1 bg-gray-100 text-gray-800 rounded-full text-xs">Not Available</span>'} | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| ${feature.compatible ? | |
| (feature.yourHas ? | |
| '<span class="text-sm text-gray-500">Already implemented</span>' : | |
| '<button class="text-indigo-600 hover:text-indigo-900 text-sm font-medium add-feature" data-feature="${feature.name}">Add to extension</button>') : | |
| `<span class="text-sm text-gray-500">Incompatible: ${feature.reason}</span>`} | |
| </td> | |
| </tr> | |
| `).join(''); | |
| } | |
| // Update button functionality | |
| updateButton.addEventListener('click', function() { | |
| updateButton.disabled = true; | |
| updateButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i><span>Updating...</span>'; | |
| // Simulate update progress | |
| let progress = 0; | |
| const interval = setInterval(() => { | |
| progress += Math.random() * 10; | |
| if (progress > 100) progress = 100; | |
| progressBar.style.width = `${progress}%`; | |
| progressPercent.textContent = `${Math.round(progress)}%`; | |
| if (progress === 100) { | |
| clearInterval(interval); | |
| updateComplete(); | |
| } | |
| }, 300); | |
| }); | |
| function updateComplete() { | |
| updateButton.innerHTML = '<i class="fas fa-check"></i><span>Update Complete</span>'; | |
| updateButton.classList.remove('bg-indigo-600', 'hover:bg-indigo-700'); | |
| updateButton.classList.add('bg-green-600', 'hover:bg-green-700'); | |
| messageText.textContent = 'Extension updated successfully! New features have been added.'; | |
| updateMessage.classList.remove('hidden'); | |
| updateMessage.classList.add('text-green-500'); | |
| // Update version | |
| const versionInput = document.getElementById('versionInput'); | |
| const currentVersion = versionInput.value.split('.'); | |
| currentVersion[1] = parseInt(currentVersion[1]) + 1; | |
| versionInput.value = currentVersion.join('.'); | |
| // Change extension name to indicate update | |
| const extensionName = document.getElementById('extensionName'); | |
| extensionName.textContent = "My Awesome Extension (Updated)"; | |
| } | |
| // Feature addition (delegated event for dynamic elements) | |
| document.addEventListener('click', function(e) { | |
| if (e.target.classList.contains('add-feature')) { | |
| const featureName = e.target.getAttribute('data-feature'); | |
| e.target.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Adding...'; | |
| e.target.disabled = true; | |
| // Simulate adding feature | |
| setTimeout(() => { | |
| e.target.innerHTML = '<i class="fas fa-check"></i> Added'; | |
| e.target.classList.remove('text-indigo-600', 'hover:text-indigo-900'); | |
| e.target.classList.add('text-green-600'); | |
| // Update the "Your Extension" column | |
| const row = e.target.closest('tr'); | |
| const yourExtensionCell = row.querySelector('td:nth-child(3)'); | |
| yourExtensionCell.innerHTML = '<span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">Available</span>'; | |
| }, 1500); | |
| } | |
| }); | |
| }); | |
| </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://enzostvs-deepsite.hf.space/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://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dwirafastd/extention-updater" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |