Spaces:
Running
Running

Crea una aplicación web de compartición de archivos minimalista similar a PicoShare, que permita subir archivos y generar enlaces para compartir, con las siguientes características clave: Funcionalidad principal: • Subida y almacenamiento seguro de archivos (imágenes, documentos, etc.). • Generación de enlaces únicos para compartir archivos. • Interfaz web simple y ligera. • Opción de agregar fecha de expiración y protección por contraseña a los enlaces. Autenticación: • Autenticación de usuarios mediante SAML2 (compatible con Azure AD, Okta, etc.) o OpenID Connect (compatible con proveedores como Auth0, Google, Authentik). • Elige una librería moderna y bien mantenida para implementar el flujo de autenticación (según el lenguaje/framework). Requisitos técnicos: • Código base en un lenguaje moderno como Go, Python (FastAPI), Node.js (Express o Next.js) o Rust. • Persistencia de archivos en disco o en S3 compatible. • Configuración vía variables de entorno (ideal para ejecución en contenedor Docker). • Compatible con ejecución detrás de un proxy inverso (ej. Traefik). Extras opcionales: • Administración de usuarios autenticados (crear/editar usuarios si no se usa SSO completo). • Dashboard básico para gestionar archivos propios. • API RESTful para subir/borrar archivos. Entregables: • Código fuente completo. • Dockerfile funcional. • Archivo docker-compose.yml de ejemplo. • Archivo README con instrucciones de despliegue y configuración del proveedor SAML/OpenID. - Follow Up Deployment
22b5242
verified
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>PicoShare - Minimal File Sharing</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"> | |
<script> | |
tailwind.config = { | |
theme: { | |
extend: { | |
colors: { | |
primary: '#3b82f6', | |
secondary: '#1e40af', | |
accent: '#60a5fa', | |
dark: '#0f172a', | |
light: '#f8fafc' | |
} | |
} | |
} | |
} | |
</script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
body { | |
font-family: 'Inter', sans-serif; | |
background-color: #f1f5f9; | |
} | |
.file-upload-label { | |
transition: all 0.3s ease; | |
} | |
.file-upload-label:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
} | |
.file-item { | |
transition: all 0.2s ease; | |
} | |
.file-item:hover { | |
transform: translateX(5px); | |
} | |
.fade-in { | |
animation: fadeIn 0.5s ease-in; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(10px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.pulse { | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); } | |
70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } | |
100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } | |
} | |
</style> | |
</head> | |
<body class="min-h-screen flex flex-col"> | |
<!-- Header --> | |
<header class="bg-white shadow-sm"> | |
<div class="container mx-auto px-4 py-4 flex justify-between items-center"> | |
<div class="flex items-center space-x-2"> | |
<div class="bg-primary w-10 h-10 rounded-lg flex items-center justify-center"> | |
<i class="fas fa-share-alt text-white text-xl"></i> | |
</div> | |
<h1 class="text-2xl font-bold text-dark">PicoShare</h1> | |
</div> | |
<div class="flex items-center space-x-4"> | |
<button id="authBtn" class="bg-primary hover:bg-secondary text-white px-4 py-2 rounded-lg transition flex items-center"> | |
<i class="fas fa-user mr-2"></i> | |
<span id="authText">Sign In</span> | |
</button> | |
<button id="themeToggle" class="text-gray-600 hover:text-primary"> | |
<i class="fas fa-moon"></i> | |
</button> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content --> | |
<main class="flex-grow container mx-auto px-4 py-8"> | |
<div class="max-w-4xl mx-auto"> | |
<!-- Hero Section --> | |
<section class="text-center mb-12 fade-in"> | |
<h1 class="text-4xl md:text-5xl font-bold text-dark mb-4">Simple, Secure File Sharing</h1> | |
<p class="text-lg text-gray-600 max-w-2xl mx-auto mb-8"> | |
Upload files and generate shareable links with optional expiration dates and password protection. | |
</p> | |
<div class="bg-white rounded-xl shadow-lg p-6 mb-8"> | |
<div class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer file-upload-label bg-light" id="dropZone"> | |
<i class="fas fa-cloud-upload-alt text-primary text-4xl mb-4"></i> | |
<h3 class="text-xl font-semibold text-dark mb-2">Drag & Drop files here</h3> | |
<p class="text-gray-500 mb-4">or</p> | |
<button class="bg-primary hover:bg-secondary text-white px-6 py-3 rounded-lg transition font-medium"> | |
Browse Files | |
</button> | |
<input type="file" id="fileInput" class="hidden" multiple> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12"> | |
<div class="bg-white p-6 rounded-xl shadow"> | |
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4"> | |
<i class="fas fa-shield-alt text-primary text-xl"></i> | |
</div> | |
<h3 class="font-semibold text-lg mb-2">Secure Sharing</h3> | |
<p class="text-gray-600">All files are encrypted during transfer and storage.</p> | |
</div> | |
<div class="bg-white p-6 rounded-xl shadow"> | |
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4"> | |
<i class="fas fa-link text-primary text-xl"></i> | |
</div> | |
<h3 class="font-semibold text-lg mb-2">Unique Links</h3> | |
<p class="text-gray-600">Each file gets a unique shareable link that you control.</p> | |
</div> | |
<div class="bg-white p-6 rounded-xl shadow"> | |
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4"> | |
<i class="fas fa-clock text-primary text-xl"></i> | |
</div> | |
<h3 class="font-semibold text-lg mb-2">Expiration Control</h3> | |
<p class="text-gray-600">Set custom expiration dates for your shared files.</p> | |
</div> | |
</div> | |
</section> | |
<!-- File Upload Form --> | |
<section class="bg-white rounded-xl shadow-lg p-6 mb-12 fade-in"> | |
<h2 class="text-2xl font-bold text-dark mb-6">Upload & Share</h2> | |
<form id="uploadForm" class="space-y-6"> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">File</label> | |
<div class="flex items-center space-x-4"> | |
<div class="flex-grow"> | |
<div class="border border-gray-300 rounded-lg p-4 bg-gray-50"> | |
<p id="fileName" class="text-gray-600">No file selected</p> | |
</div> | |
</div> | |
<button type="button" id="browseBtn" class="bg-primary hover:bg-secondary text-white px-4 py-2 rounded-lg transition"> | |
Browse | |
</button> | |
</div> | |
</div> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Expiration Date</label> | |
<input type="date" id="expirationDate" class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-primary focus:border-transparent"> | |
</div> | |
<div> | |
<label class="block text-gray-700 font-medium mb-2">Password Protection</label> | |
<div class="relative"> | |
<input type="password" id="password" placeholder="Optional" class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-primary focus:border-transparent pr-10"> | |
<button type="button" class="absolute right-3 top-3 text-gray-400 hover:text-gray-600"> | |
<i class="fas fa-eye"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="flex justify-end"> | |
<button type="submit" class="bg-primary hover:bg-secondary text-white px-6 py-3 rounded-lg transition font-medium flex items-center pulse"> | |
<i class="fas fa-upload mr-2"></i> | |
Upload & Generate Link | |
</button> | |
</div> | |
</form> | |
</section> | |
<!-- Shared Files Section --> | |
<section class="bg-white rounded-xl shadow-lg p-6 fade-in"> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-2xl font-bold text-dark">Your Shared Files</h2> | |
<span class="bg-gray-100 text-gray-800 px-3 py-1 rounded-full text-sm">3 files</span> | |
</div> | |
<div class="space-y-4" id="fileList"> | |
<!-- File items will be added here dynamically --> | |
<div class="file-item border border-gray-200 rounded-lg p-4 flex items-center"> | |
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mr-4"> | |
<i class="fas fa-file-pdf text-primary text-xl"></i> | |
</div> | |
<div class="flex-grow"> | |
<h3 class="font-semibold">Project_Proposal.pdf</h3> | |
<p class="text-gray-500 text-sm">Shared 2 hours ago • Expires in 5 days</p> | |
</div> | |
<div class="flex space-x-2"> | |
<button class="text-gray-500 hover:text-primary"> | |
<i class="fas fa-copy"></i> | |
</button> | |
<button class="text-gray-500 hover:text-red-500"> | |
<i class="fas fa-trash"></i> | |
</button> | |
</div> | |
</div> | |
<div class="file-item border border-gray-200 rounded-lg p-4 flex items-center"> | |
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mr-4"> | |
<i class="fas fa-file-image text-green-500 text-xl"></i> | |
</div> | |
<div class="flex-grow"> | |
<h3 class="font-semibold">Vacation_Photos.zip</h3> | |
<p class="text-gray-500 text-sm">Shared yesterday • Expires in 3 days</p> | |
</div> | |
<div class="flex space-x-2"> | |
<button class="text-gray-500 hover:text-primary"> | |
<i class="fas fa-copy"></i> | |
</button> | |
<button class="text-gray-500 hover:text-red-500"> | |
<i class="fas fa-trash"></i> | |
</button> | |
</div> | |
</div> | |
<div class="file-item border border-gray-200 rounded-lg p-4 flex items-center"> | |
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mr-4"> | |
<i class="fas fa-file-video text-purple-500 text-xl"></i> | |
</div> | |
<div class="flex-grow"> | |
<h3 class="font-semibold">Presentation.mp4</h3> | |
<p class="text-gray-500 text-sm">Shared 3 days ago • Expires in 1 day</p> | |
</div> | |
<div class="flex space-x-2"> | |
<button class="text-gray-500 hover:text-primary"> | |
<i class="fas fa-copy"></i> | |
</button> | |
<button class="text-gray-500 hover:text-red-500"> | |
<i class="fas fa-trash"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
</section> | |
</div> | |
</main> | |
<!-- Footer --> | |
<footer class="bg-white border-t mt-12"> | |
<div class="container mx-auto px-4 py-8"> | |
<div class="flex flex-col md:flex-row justify-between items-center"> | |
<div class="mb-4 md:mb-0"> | |
<div class="flex items-center space-x-2"> | |
<div class="bg-primary w-8 h-8 rounded-lg flex items-center justify-center"> | |
<i class="fas fa-share-alt text-white"></i> | |
</div> | |
<span class="font-bold text-dark">PicoShare</span> | |
</div> | |
<p class="text-gray-600 mt-2 text-sm">Minimal file sharing made simple</p> | |
</div> | |
<div class="flex space-x-6"> | |
<a href="#" class="text-gray-600 hover:text-primary"> | |
<i class="fab fa-github"></i> | |
</a> | |
<a href="#" class="text-gray-600 hover:text-primary"> | |
<i class="fab fa-twitter"></i> | |
</a> | |
<a href="#" class="text-gray-600 hover:text-primary"> | |
<i class="fab fa-discord"></i> | |
</a> | |
</div> | |
</div> | |
<div class="border-t border-gray-200 mt-6 pt-6 text-center text-gray-500 text-sm"> | |
<p>© 2023 PicoShare. All rights reserved. Secure file sharing for everyone.</p> | |
</div> | |
</div> | |
</footer> | |
<!-- Authentication Modal --> | |
<div id="authModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md p-6"> | |
<div class="flex justify-between items-center mb-6"> | |
<h3 class="text-2xl font-bold text-dark">Authentication</h3> | |
<button id="closeModal" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="space-y-4"> | |
<button class="w-full flex items-center justify-center space-x-3 border border-gray-300 rounded-lg p-3 hover:bg-gray-50 transition"> | |
<i class="fab fa-google text-red-500 text-xl"></i> | |
<span>Sign in with Google</span> | |
</button> | |
<button class="w-full flex items-center justify-center space-x-3 border border-gray-300 rounded-lg p-3 hover:bg-gray-50 transition"> | |
<i class="fab fa-microsoft text-blue-500 text-xl"></i> | |
<span>Sign in with Microsoft</span> | |
</button> | |
<button class="w-full flex items-center justify-center space-x-3 border border-gray-300 rounded-lg p-3 hover:bg-gray-50 transition"> | |
<i class="fab fa-github text-gray-800 text-xl"></i> | |
<span>Sign in with GitHub</span> | |
</button> | |
<div class="relative my-6"> | |
<div class="absolute inset-0 flex items-center"> | |
<div class="w-full border-t border-gray-300"></div> | |
</div> | |
<div class="relative flex justify-center text-sm"> | |
<span class="px-2 bg-white text-gray-500">Or continue with</span> | |
</div> | |
</div> | |
<form class="space-y-4"> | |
<div> | |
<label class="block text-gray-700 mb-2">Email</label> | |
<input type="email" class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-primary focus:border-transparent"> | |
</div> | |
<div> | |
<label class="block text-gray-700 mb-2">Password</label> | |
<input type="password" class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-primary focus:border-transparent"> | |
</div> | |
<button class="w-full bg-primary hover:bg-secondary text-white py-3 rounded-lg transition font-medium"> | |
Sign In | |
</button> | |
</form> | |
</div> | |
</div> | |
</div> | |
<script> | |
// DOM Elements | |
const authBtn = document.getElementById('authBtn'); | |
const authText = document.getElementById('authText'); | |
const authModal = document.getElementById('authModal'); | |
const closeModal = document.getElementById('closeModal'); | |
const themeToggle = document.getElementById('themeToggle'); | |
const fileInput = document.getElementById('fileInput'); | |
const browseBtn = document.getElementById('browseBtn'); | |
const dropZone = document.getElementById('dropZone'); | |
const fileName = document.getElementById('fileName'); | |
const uploadForm = document.getElementById('uploadForm'); | |
const fileList = document.getElementById('fileList'); | |
// Authentication state | |
let isAuthenticated = false; | |
// Event Listeners | |
authBtn.addEventListener('click', () => { | |
if (isAuthenticated) { | |
// Logout | |
isAuthenticated = false; | |
authText.textContent = 'Sign In'; | |
authBtn.innerHTML = '<i class="fas fa-user mr-2"></i> Sign In'; | |
} else { | |
// Show auth modal | |
authModal.classList.remove('hidden'); | |
} | |
}); | |
closeModal.addEventListener('click', () => { | |
authModal.classList.add('hidden'); | |
}); | |
browseBtn.addEventListener('click', () => { | |
fileInput.click(); | |
}); | |
fileInput.addEventListener('change', (e) => { | |
if (e.target.files.length > 0) { | |
fileName.textContent = e.target.files[0].name; | |
} else { | |
fileName.textContent = 'No file selected'; | |
} | |
}); | |
// Drag and drop functionality | |
dropZone.addEventListener('dragover', (e) => { | |
e.preventDefault(); | |
dropZone.classList.add('border-primary', 'bg-blue-50'); | |
}); | |
dropZone.addEventListener('dragleave', () => { | |
dropZone.classList.remove('border-primary', 'bg-blue-50'); | |
}); | |
dropZone.addEventListener('drop', (e) => { | |
e.preventDefault(); | |
dropZone.classList.remove('border-primary', 'bg-blue-50'); | |
if (e.dataTransfer.files.length > 0) { | |
fileInput.files = e.dataTransfer.files; | |
fileName.textContent = e.dataTransfer.files[0].name; | |
} | |
}); | |
// Form submission | |
uploadForm.addEventListener('submit', (e) => { | |
e.preventDefault(); | |
if (fileInput.files.length === 0) { | |
alert('Please select a file to upload'); | |
return; | |
} | |
// Simulate file upload | |
const file = fileInput.files[0]; | |
const expiration = document.getElementById('expirationDate').value || 'Never'; | |
const password = document.getElementById('password').value || 'None'; | |
// Create new file item | |
const fileItem = document.createElement('div'); | |
fileItem.className = 'file-item border border-gray-200 rounded-lg p-4 flex items-center fade-in'; | |
fileItem.innerHTML = ` | |
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mr-4"> | |
<i class="fas fa-file text-primary text-xl"></i> | |
</div> | |
<div class="flex-grow"> | |
<h3 class="font-semibold">${file.name}</h3> | |
<p class="text-gray-500 text-sm">Just now • Expires in ${expiration || 'Never'}</p> | |
</div> | |
<div class="flex space-x-2"> | |
<button class="text-gray-500 hover:text-primary copy-btn"> | |
<i class="fas fa-copy"></i> | |
</button> | |
<button class="text-gray-500 hover:text-red-500 delete-btn"> | |
<i class="fas fa-trash"></i> | |
</button> | |
</div> | |
`; | |
// Add to top of file list | |
fileList.insertBefore(fileItem, fileList.firstChild); | |
// Reset form | |
fileInput.value = ''; | |
fileName.textContent = 'No file selected'; | |
document.getElementById('password').value = ''; | |
// Show success message | |
alert(`File "${file.name}" uploaded successfully!`); | |
}); | |
// Theme toggle | |
themeToggle.addEventListener('click', () => { | |
document.body.classList.toggle('dark'); | |
const icon = themeToggle.querySelector('i'); | |
if (document.body.classList.contains('dark')) { | |
icon.classList.remove('fa-moon'); | |
icon.classList.add('fa-sun'); | |
} else { | |
icon.classList.remove('fa-sun'); | |
icon.classList.add('fa-moon'); | |
} | |
}); | |
// Simulate authentication | |
setTimeout(() => { | |
isAuthenticated = true; | |
authText.textContent = 'Sign Out'; | |
authBtn.innerHTML = '<i class="fas fa-sign-out-alt mr-2"></i> Sign Out'; | |
}, 2000); | |
</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=IITheLordII/6-61551561" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |