Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Universal File Converter</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> | |
.dropzone { | |
border: 2px dashed #3b82f6; | |
transition: all 0.3s ease; | |
} | |
.dropzone.active { | |
border-color: #10b981; | |
background-color: #f0f9ff; | |
} | |
.progress-bar { | |
transition: width 0.3s ease; | |
} | |
.file-icon { | |
font-size: 2rem; | |
} | |
.file-card:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
} | |
.tooltip { | |
visibility: hidden; | |
opacity: 0; | |
transition: opacity 0.3s; | |
} | |
.has-tooltip:hover .tooltip { | |
visibility: visible; | |
opacity: 1; | |
} | |
.download-options { | |
max-height: 0; | |
overflow: hidden; | |
transition: max-height 0.3s ease-out; | |
} | |
.download-options.active { | |
max-height: 300px; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<div class="container mx-auto px-4 py-8"> | |
<header class="text-center mb-10"> | |
<h1 class="text-4xl font-bold text-blue-600 mb-2">Universal File Converter</h1> | |
<p class="text-gray-600">Auto-detect file types and convert to your desired format</p> | |
</header> | |
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mb-8"> | |
<div id="dropzone" class="dropzone rounded-lg p-10 text-center cursor-pointer"> | |
<div class="flex flex-col items-center justify-center"> | |
<i class="fas fa-cloud-upload-alt text-blue-500 text-5xl mb-4"></i> | |
<h3 class="text-xl font-semibold text-gray-700 mb-2">Drag & Drop files here</h3> | |
<p class="text-gray-500 mb-4">or click to browse your files</p> | |
<input type="file" id="fileInput" class="hidden" multiple> | |
<button id="browseBtn" class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition duration-300"> | |
Select Files | |
</button> | |
</div> | |
</div> | |
</div> | |
<div id="fileList" class="max-w-4xl mx-auto mb-8 hidden"> | |
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Selected Files</h2> | |
<div id="filesContainer" class="space-y-3"></div> | |
</div> | |
<div id="conversionOptions" class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6 mb-8 hidden"> | |
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Conversion Options</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6"> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Output Format</label> | |
<div class="grid grid-cols-2 gap-3"> | |
<button data-format="pdf" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-blue-100 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-pdf text-red-500 mr-2"></i> PDF | |
</button> | |
<button data-format="excel" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-green-100 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-excel text-green-600 mr-2"></i> Excel | |
</button> | |
<button data-format="word" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-blue-100 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-word text-blue-600 mr-2"></i> Word | |
</button> | |
<button data-format="xml" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-orange-100 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-code text-orange-500 mr-2"></i> XML | |
</button> | |
<button data-format="text" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-gray-200 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-alt text-gray-600 mr-2"></i> Text | |
</button> | |
<button data-format="csv" class="format-btn flex items-center justify-center bg-gray-100 hover:bg-green-100 border border-gray-200 rounded-lg p-3 transition"> | |
<i class="fas fa-file-csv text-green-700 mr-2"></i> CSV | |
</button> | |
</div> | |
</div> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Options</label> | |
<div class="space-y-3"> | |
<div class="flex items-center"> | |
<input type="checkbox" id="preserveLayout" class="rounded text-blue-600 mr-2"> | |
<label for="preserveLayout">Preserve original layout</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="mergeFiles" class="rounded text-blue-600 mr-2"> | |
<label for="mergeFiles">Merge all files into one</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="compressOutput" class="rounded text-blue-600 mr-2"> | |
<label for="compressOutput">Compress output files</label> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="flex justify-center"> | |
<button id="convertBtn" class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-8 rounded-lg transition duration-300 flex items-center"> | |
<i class="fas fa-exchange-alt mr-2"></i> Convert Files | |
</button> | |
</div> | |
</div> | |
<div id="progressSection" class="max-w-4xl mx-auto mb-8 hidden"> | |
<h2 class="text-2xl font-semibold text-gray-800 mb-4">Conversion Progress</h2> | |
<div class="bg-white rounded-xl shadow-md overflow-hidden p-6"> | |
<div id="progressContainer" class="space-y-4"></div> | |
</div> | |
</div> | |
<div id="downloadSection" class="max-w-4xl mx-auto hidden"> | |
<div class="flex justify-between items-center mb-4"> | |
<h2 class="text-2xl font-semibold text-gray-800">Download Converted Files</h2> | |
<button id="toggleDownloadOptions" class="text-blue-600 hover:text-blue-800 font-medium flex items-center"> | |
<i class="fas fa-cog mr-2"></i> Download Options | |
</button> | |
</div> | |
<div id="downloadOptions" class="download-options bg-white rounded-lg p-4 mb-4"> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Download Quality</label> | |
<select id="downloadQuality" class="w-full border border-gray-300 rounded-lg p-2"> | |
<option value="high">High Quality (Recommended)</option> | |
<option value="medium">Medium Quality</option> | |
<option value="low">Low Quality (Smaller Size)</option> | |
</select> | |
</div> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Download Method</label> | |
<select id="downloadMethod" class="w-full border border-gray-300 rounded-lg p-2"> | |
<option value="individual">Individual Files</option> | |
<option value="zip">ZIP Archive</option> | |
</select> | |
</div> | |
</div> | |
<div class="mt-4 flex justify-end"> | |
<button id="applyDownloadOptions" class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg"> | |
Apply Options | |
</button> | |
</div> | |
</div> | |
<div id="downloadContainer" class="grid grid-cols-1 md:grid-cols-2 gap-4"></div> | |
<div class="mt-6 flex justify-center"> | |
<button id="downloadAllBtn" class="bg-green-600 hover:bg-green-700 text-white font-medium py-3 px-6 rounded-lg flex items-center"> | |
<i class="fas fa-download mr-2"></i> Download All Files | |
</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// DOM elements | |
const dropzone = document.getElementById('dropzone'); | |
const fileInput = document.getElementById('fileInput'); | |
const browseBtn = document.getElementById('browseBtn'); | |
const fileList = document.getElementById('fileList'); | |
const filesContainer = document.getElementById('filesContainer'); | |
const conversionOptions = document.getElementById('conversionOptions'); | |
const convertBtn = document.getElementById('convertBtn'); | |
const progressSection = document.getElementById('progressSection'); | |
const progressContainer = document.getElementById('progressContainer'); | |
const downloadSection = document.getElementById('downloadSection'); | |
const downloadContainer = document.getElementById('downloadContainer'); | |
const formatBtns = document.querySelectorAll('.format-btn'); | |
const toggleDownloadOptions = document.getElementById('toggleDownloadOptions'); | |
const downloadOptions = document.getElementById('downloadOptions'); | |
const downloadAllBtn = document.getElementById('downloadAllBtn'); | |
const applyDownloadOptions = document.getElementById('applyDownloadOptions'); | |
let selectedFiles = []; | |
let selectedFormat = null; | |
let convertedFiles = []; | |
let downloadQuality = 'high'; | |
let downloadMethod = 'individual'; | |
// Event listeners | |
browseBtn.addEventListener('click', () => fileInput.click()); | |
fileInput.addEventListener('change', handleFileSelect); | |
// Drag and drop events | |
['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); | |
// Format selection | |
formatBtns.forEach(btn => { | |
btn.addEventListener('click', function() { | |
formatBtns.forEach(b => b.classList.remove('border-blue-500', 'bg-blue-50')); | |
this.classList.add('border-blue-500', 'bg-blue-50'); | |
selectedFormat = this.getAttribute('data-format'); | |
}); | |
}); | |
// Convert button | |
convertBtn.addEventListener('click', startConversion); | |
// Download options toggle | |
toggleDownloadOptions.addEventListener('click', function() { | |
downloadOptions.classList.toggle('active'); | |
}); | |
// Apply download options | |
applyDownloadOptions.addEventListener('click', function() { | |
downloadQuality = document.getElementById('downloadQuality').value; | |
downloadMethod = document.getElementById('downloadMethod').value; | |
showAlert('Download options updated successfully', 'success'); | |
downloadOptions.classList.remove('active'); | |
}); | |
// Download all files | |
downloadAllBtn.addEventListener('click', function() { | |
if (downloadMethod === 'zip') { | |
// Simulate downloading a ZIP archive | |
const zipName = `converted_files_${new Date().getTime()}.zip`; | |
showAlert(`Preparing ZIP archive: ${zipName}`, 'success'); | |
// In a real app, this would trigger the actual ZIP download | |
setTimeout(() => { | |
showAlert(`Downloading ${zipName}`, 'success'); | |
}, 1500); | |
} else { | |
// Simulate downloading all files individually | |
showAlert('Starting download of all files', 'success'); | |
// In a real app, this would trigger all individual downloads | |
document.querySelectorAll('.download-btn').forEach(btn => { | |
setTimeout(() => { | |
btn.click(); | |
}, 300); | |
}); | |
} | |
}); | |
// File handling functions | |
function handleFileSelect(e) { | |
const files = e.target.files || e.dataTransfer.files; | |
processFiles(files); | |
} | |
function handleDrop(e) { | |
const dt = e.dataTransfer; | |
const files = dt.files; | |
processFiles(files); | |
} | |
function processFiles(files) { | |
selectedFiles = Array.from(files); | |
if (selectedFiles.length > 0) { | |
fileList.classList.remove('hidden'); | |
conversionOptions.classList.remove('hidden'); | |
filesContainer.innerHTML = ''; | |
selectedFiles.forEach((file, index) => { | |
const fileCard = createFileCard(file, index); | |
filesContainer.appendChild(fileCard); | |
}); | |
} | |
} | |
function createFileCard(file, index) { | |
const fileType = getFileType(file.name); | |
const icon = getFileIcon(fileType); | |
const fileSize = formatFileSize(file.size); | |
const card = document.createElement('div'); | |
card.className = 'file-card bg-white rounded-lg border border-gray-200 p-4 flex items-center justify-between transition duration-300'; | |
card.innerHTML = ` | |
<div class="flex items-center"> | |
<div class="file-icon text-3xl mr-4 ${getFileIconColor(fileType)}"> | |
${icon} | |
</div> | |
<div> | |
<h3 class="font-medium text-gray-800 truncate max-w-xs">${file.name}</h3> | |
<p class="text-sm text-gray-500">${fileType.toUpperCase()} • ${fileSize}</p> | |
</div> | |
</div> | |
<div class="flex items-center"> | |
<button class="remove-file-btn text-red-500 hover:text-red-700 p-2 rounded-full" data-index="${index}"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
`; | |
// Add remove file functionality | |
card.querySelector('.remove-file-btn').addEventListener('click', function() { | |
const index = parseInt(this.getAttribute('data-index')); | |
selectedFiles.splice(index, 1); | |
if (selectedFiles.length === 0) { | |
fileList.classList.add('hidden'); | |
conversionOptions.classList.add('hidden'); | |
} else { | |
// Re-render file list | |
filesContainer.innerHTML = ''; | |
selectedFiles.forEach((file, idx) => { | |
filesContainer.appendChild(createFileCard(file, idx)); | |
}); | |
} | |
}); | |
return card; | |
} | |
function getFileType(filename) { | |
const extension = filename.split('.').pop().toLowerCase(); | |
const fileTypes = { | |
// Documents | |
'pdf': 'pdf', | |
'doc': 'word', | |
'docx': 'word', | |
'txt': 'text', | |
'rtf': 'text', | |
'odt': 'word', | |
// Spreadsheets | |
'xls': 'excel', | |
'xlsx': 'excel', | |
'csv': 'csv', | |
'ods': 'excel', | |
// Data | |
'xml': 'xml', | |
'json': 'json', | |
// Images | |
'jpg': 'image', | |
'jpeg': 'image', | |
'png': 'image', | |
'gif': 'image', | |
'svg': 'image', | |
'webp': 'image', | |
// Archives | |
'zip': 'archive', | |
'rar': 'archive', | |
'7z': 'archive', | |
'tar': 'archive', | |
'gz': 'archive' | |
}; | |
return fileTypes[extension] || 'file'; | |
} | |
function getFileIcon(fileType) { | |
const icons = { | |
'pdf': '<i class="fas fa-file-pdf"></i>', | |
'word': '<i class="fas fa-file-word"></i>', | |
'excel': '<i class="fas fa-file-excel"></i>', | |
'csv': '<i class="fas fa-file-csv"></i>', | |
'text': '<i class="fas fa-file-alt"></i>', | |
'xml': '<i class="fas fa-file-code"></i>', | |
'json': '<i class="fas fa-file-code"></i>', | |
'image': '<i class="fas fa-file-image"></i>', | |
'archive': '<i class="fas fa-file-archive"></i>', | |
'file': '<i class="fas fa-file"></i>' | |
}; | |
return icons[fileType] || icons['file']; | |
} | |
function getFileIconColor(fileType) { | |
const colors = { | |
'pdf': 'text-red-500', | |
'word': 'text-blue-600', | |
'excel': 'text-green-600', | |
'csv': 'text-green-700', | |
'text': 'text-gray-600', | |
'xml': 'text-orange-500', | |
'json': 'text-yellow-500', | |
'image': 'text-purple-500', | |
'archive': 'text-yellow-600', | |
'file': 'text-gray-500' | |
}; | |
return colors[fileType] || colors['file']; | |
} | |
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]; | |
} | |
// Conversion functions | |
function startConversion() { | |
if (!selectedFormat) { | |
showAlert('Please select an output format', 'error'); | |
return; | |
} | |
if (selectedFiles.length === 0) { | |
showAlert('No files selected for conversion', 'error'); | |
return; | |
} | |
// Show progress section | |
progressSection.classList.remove('hidden'); | |
progressContainer.innerHTML = ''; | |
// Hide download section if shown | |
downloadSection.classList.add('hidden'); | |
// Reset converted files array | |
convertedFiles = []; | |
// Simulate conversion process | |
selectedFiles.forEach((file, index) => { | |
const progressItem = document.createElement('div'); | |
progressItem.className = 'bg-gray-50 rounded-lg p-4'; | |
progressItem.innerHTML = ` | |
<div class="flex justify-between items-center mb-2"> | |
<div class="flex items-center truncate"> | |
<span class="font-medium text-gray-700 truncate max-w-xs">${file.name}</span> | |
<div class="has-tooltip relative ml-2"> | |
<i class="fas fa-info-circle text-blue-500"></i> | |
<div class="tooltip absolute z-10 w-48 bg-gray-800 text-white text-xs rounded p-2 -left-24 -top-10"> | |
Converting to ${selectedFormat.toUpperCase()} | |
</div> | |
</div> | |
</div> | |
<span class="text-sm font-medium text-gray-500" id="progressPercent-${index}">0%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2.5"> | |
<div id="progressBar-${index}" class="progress-bar h-2.5 rounded-full bg-blue-600" style="width: 0%"></div> | |
</div> | |
`; | |
progressContainer.appendChild(progressItem); | |
// Simulate progress | |
simulateConversionProgress(index, file); | |
}); | |
} | |
function simulateConversionProgress(index, file) { | |
let progress = 0; | |
const interval = setInterval(() => { | |
progress += Math.floor(Math.random() * 10) + 5; | |
if (progress >= 100) { | |
progress = 100; | |
clearInterval(interval); | |
// Store converted file info | |
const originalName = file.name; | |
const newName = originalName.substring(0, originalName.lastIndexOf('.')) + '.' + selectedFormat; | |
convertedFiles.push({ | |
originalName, | |
newName, | |
format: selectedFormat, | |
size: Math.floor(file.size * (0.7 + Math.random() * 0.3)) // Random size for demo | |
}); | |
// When all files are converted | |
if (convertedFiles.length === selectedFiles.length) { | |
setTimeout(showDownloadOptions, 1000); | |
} | |
} | |
document.getElementById(`progressBar-${index}`).style.width = `${progress}%`; | |
document.getElementById(`progressPercent-${index}`).textContent = `${progress}%`; | |
}, 200); | |
} | |
function showDownloadOptions() { | |
downloadSection.classList.remove('hidden'); | |
downloadContainer.innerHTML = ''; | |
convertedFiles.forEach((file, index) => { | |
const downloadCard = document.createElement('div'); | |
downloadCard.className = 'bg-white rounded-lg border border-gray-200 p-4 flex items-center justify-between'; | |
downloadCard.innerHTML = ` | |
<div class="flex items-center truncate"> | |
<div class="mr-3 text-2xl ${getFileIconColor(file.format)}"> | |
${getFileIcon(file.format)} | |
</div> | |
<div class="truncate"> | |
<h3 class="font-medium text-gray-800 truncate">${file.newName}</h3> | |
<p class="text-sm text-gray-500">${formatFileSize(file.size)} • From ${file.originalName}</p> | |
</div> | |
</div> | |
<div class="flex space-x-2"> | |
<button class="preview-btn text-blue-600 hover:text-blue-800 p-2 rounded-full" data-index="${index}"> | |
<i class="fas fa-eye"></i> | |
</button> | |
<button class="download-btn bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition duration-300" data-index="${index}"> | |
<i class="fas fa-download mr-2"></i> Download | |
</button> | |
</div> | |
`; | |
downloadContainer.appendChild(downloadCard); | |
}); | |
// Add preview functionality | |
document.querySelectorAll('.preview-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const index = parseInt(this.getAttribute('data-index')); | |
const file = convertedFiles[index]; | |
showAlert(`Previewing ${file.newName} (simulated)`, 'success'); | |
}); | |
}); | |
// Add download functionality | |
document.querySelectorAll('.download-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const index = parseInt(this.getAttribute('data-index')); | |
const file = convertedFiles[index]; | |
// In a real app, this would download the actual converted file | |
// Here we're just simulating the download | |
showAlert(`Downloading ${file.newName} (${downloadQuality} quality)`, 'success'); | |
}); | |
}); | |
} | |
function showAlert(message, type) { | |
const alert = document.createElement('div'); | |
alert.className = `fixed top-4 right-4 px-6 py-3 rounded-lg shadow-lg text-white font-medium ${ | |
type === 'error' ? 'bg-red-500' : 'bg-green-500' | |
}`; | |
alert.textContent = message; | |
document.body.appendChild(alert); | |
setTimeout(() => { | |
alert.classList.add('opacity-0', 'transition-opacity', 'duration-500'); | |
setTimeout(() => alert.remove(), 500); | |
}, 3000); | |
} | |
}); | |
</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=nkp/universefile" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |