GoGma's picture
🐳 22/02 - 12:18 - no funciona pero primero queiro que me arregles estee space para que funcione sin errores
eebe985 verified
Raw
History Blame Contribute Delete
23.1 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sofia Cloud - Tu espacio en la nube</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* { font-family: 'Inter', sans-serif; }
.glass {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.glass-dark {
background: rgba(17, 24, 39, 0.8);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.file-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 40px -10px rgba(0,0,0,0.2);
}
.storage-bar {
background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 100%);
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.floating { animation: float 3s ease-in-out infinite; }
</style>
</head>
<body class="bg-gray-50 text-gray-800">
<!-- Sidebar -->
<aside class="fixed left-0 top-0 h-full w-64 glass border-r border-gray-200 z-50 hidden md:block">
<div class="p-6 flex items-center gap-3 mb-6">
<div class="w-10 h-10 gradient-bg rounded-xl flex items-center justify-center text-white shadow-lg">
<i data-lucide="cloud" class="w-6 h-6"></i>
</div>
<div>
<h1 class="font-bold text-xl text-gray-900">Sofia Cloud</h1>
<p class="text-xs text-gray-500">Tu espacio seguro</p>
</div>
</div>
<nav class="px-4 space-y-2">
<button onclick="showSection('files')" class="nav-item w-full flex items-center gap-3 px-4 py-3 rounded-xl bg-blue-50 text-blue-600 font-medium transition-all">
<i data-lucide="folder-open" class="w-5 h-5"></i>
Mis Archivos
</button>
<button onclick="showSection('recent')" class="nav-item w-full flex items-center gap-3 px-4 py-3 rounded-xl text-gray-600 hover:bg-gray-100 transition-all">
<i data-lucide="clock" class="w-5 h-5"></i>
Recientes
</button>
<button onclick="showSection('favorites')" class="nav-item w-full flex items-center gap-3 px-4 py-3 rounded-xl text-gray-600 hover:bg-gray-100 transition-all">
<i data-lucide="star" class="w-5 h-5"></i>
Favoritos
</button>
<button onclick="showSection('trash')" class="nav-item w-full flex items-center gap-3 px-4 py-3 rounded-xl text-gray-600 hover:bg-gray-100 transition-all">
<i data-lucide="trash-2" class="w-5 h-5"></i>
Papelera
</button>
</nav>
<!-- Storage Widget -->
<div class="absolute bottom-0 left-0 right-0 p-6">
<div class="bg-gradient-to-br from-blue-500 to-purple-600 rounded-2xl p-4 text-white">
<div class="flex items-center justify-between mb-3">
<span class="text-sm font-medium">Almacenamiento</span>
<span class="text-xs bg-white/20 px-2 py-1 rounded-full">75%</span>
</div>
<div class="w-full bg-white/20 rounded-full h-2 mb-2">
<div class="storage-bar h-2 rounded-full" style="width: 75%"></div>
</div>
<p class="text-xs text-blue-100">15 GB de 20 GB usados</p>
</div>
</div>
</aside>
<!-- Main Content -->
<main class="md:ml-64 min-h-screen">
<!-- Header -->
<header class="sticky top-0 z-40 glass border-b border-gray-200 px-6 py-4">
<div class="flex items-center justify-between max-w-7xl mx-auto">
<div class="flex items-center gap-4 flex-1">
<button class="md:hidden p-2 hover:bg-gray-100 rounded-lg">
<i data-lucide="menu" class="w-6 h-6"></i>
</button>
<div class="relative flex-1 max-w-xl">
<i data-lucide="search" class="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
<input type="text" id="searchInput" placeholder="Buscar archivos..."
class="w-full pl-10 pr-4 py-2.5 bg-gray-100 border-none rounded-xl focus:ring-2 focus:ring-blue-500 focus:bg-white transition-all"
oninput="filterFiles()">
</div>
</div>
<div class="flex items-center gap-4 ml-4">
<button onclick="createFolder()" class="hidden sm:flex items-center gap-2 px-4 py-2.5 bg-gray-100 hover:bg-gray-200 rounded-xl font-medium transition-all">
<i data-lucide="folder-plus" class="w-4 h-4"></i>
Nueva Carpeta
</button>
<button onclick="triggerUpload()" class="flex items-center gap-2 px-4 py-2.5 gradient-bg text-white rounded-xl font-medium hover:shadow-lg transition-all">
<i data-lucide="upload-cloud" class="w-4 h-4"></i>
<span class="hidden sm:inline">Subir</span>
</button>
<input type="file" id="fileInput" class="hidden" multiple onchange="handleFiles(this.files)">
<button class="relative p-2 hover:bg-gray-100 rounded-xl">
<i data-lucide="bell" class="w-6 h-6 text-gray-600"></i>
<span class="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
</button>
<img src="https://static.photos/people/200x200/42" alt="User" class="w-10 h-10 rounded-xl object-cover border-2 border-white shadow-md cursor-pointer">
</div>
</div>
</header>
<!-- Content Area -->
<div class="p-6 max-w-7xl mx-auto">
<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-2xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between mb-4">
<div class="p-3 bg-blue-50 rounded-xl">
<i data-lucide="files" class="w-6 h-6 text-blue-600"></i>
</div>
<span class="text-xs font-medium text-green-600 bg-green-50 px-2 py-1 rounded-full">+12%</span>
</div>
<h3 class="text-2xl font-bold text-gray-900">1,247</h3>
<p class="text-sm text-gray-500">Archivos totales</p>
</div>
<div class="bg-white rounded-2xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between mb-4">
<div class="p-3 bg-purple-50 rounded-xl">
<i data-lucide="hard-drive" class="w-6 h-6 text-purple-600"></i>
</div>
<span class="text-xs font-medium text-gray-600 bg-gray-100 px-2 py-1 rounded-full">75%</span>
</div>
<h3 class="text-2xl font-bold text-gray-900">15.2 GB</h3>
<p class="text-sm text-gray-500">Espacio usado</p>
</div>
<div class="bg-white rounded-2xl p-6 shadow-sm border border-gray-100">
<div class="flex items-center justify-between mb-4">
<div class="p-3 bg-orange-50 rounded-xl">
<i data-lucide="share-2" class="w-6 h-6 text-orange-600"></i>
</div>
<span class="text-xs font-medium text-green-600 bg-green-50 px-2 py-1 rounded-full">+5%</span>
</div>
<h3 class="text-2xl font-bold text-gray-900">48</h3>
<p class="text-sm text-gray-500">Archivos compartidos</p>
</div>
</div>
<!-- Quick Access -->
<div class="mb-8">
<h2 class="text-lg font-semibold text-gray-900 mb-4">Acceso rápido</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4" id="quickAccess">
<!-- Generated by JS -->
</div>
</div>
<!-- File List Header -->
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900">Todos los archivos</h2>
<div class="flex items-center gap-2">
<button onclick="toggleView('grid')" id="gridBtn" class="p-2 rounded-lg bg-blue-50 text-blue-600">
<i data-lucide="grid-3x3" class="w-5 h-5"></i>
</button>
<button onclick="toggleView('list')" id="listBtn" class="p-2 rounded-lg text-gray-400 hover:bg-gray-100">
<i data-lucide="list" class="w-5 h-5"></i>
</button>
</div>
</div>
<!-- Files Container -->
<div id="filesContainer" class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4">
<!-- Files will be rendered here -->
</div>
</div>
</main>
<!-- Upload Progress Modal -->
<div id="uploadModal" class="fixed bottom-4 right-4 w-80 bg-white rounded-2xl shadow-2xl border border-gray-200 p-4 hidden transform transition-all">
<div class="flex items-center justify-between mb-3">
<span class="font-medium text-gray-900">Subiendo archivos...</span>
<button onclick="closeUploadModal()" class="text-gray-400 hover:text-gray-600">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="space-y-3" id="uploadList">
<!-- Upload items -->
</div>
</div>
<script>
// Initialize Lucide icons when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
renderQuickAccess();
renderFiles();
});
// Sample data
let files = [
{ id: 1, name: 'Proyecto_Final.pdf', type: 'pdf', size: '2.4 MB', date: '2024-01-15', color: 'red' },
{ id: 2, name: 'Fotos_Vacaciones', type: 'folder', size: '156 archivos', date: '2024-01-14', color: 'blue' },
{ id: 3, name: 'Presupuesto_2024.xlsx', type: 'excel', size: '456 KB', date: '2024-01-13', color: 'green' },
{ id: 4, name: 'Logo_Design.png', type: 'image', size: '3.2 MB', date: '2024-01-12', color: 'purple' },
{ id: 5, name: 'Contrato_Clientes.docx', type: 'word', size: '128 KB', date: '2024-01-11', color: 'blue' },
{ id: 6, name: 'Presentación_Ventas.pptx', type: 'powerpoint', size: '5.8 MB', date: '2024-01-10', color: 'orange' },
{ id: 7, name: 'Backup_Sistema.zip', type: 'zip', size: '1.2 GB', date: '2024-01-09', color: 'gray' },
{ id: 8, name: 'Reunión_Team.mp4', type: 'video', size: '245 MB', date: '2024-01-08', color: 'pink' },
];
const quickAccess = [
{ name: 'Documentos', icon: 'file-text', color: 'blue', count: '124' },
{ name: 'Imágenes', icon: 'image', color: 'purple', count: '48' },
{ name: 'Videos', icon: 'video', color: 'pink', count: '12' },
{ name: 'Audio', icon: 'music', color: 'orange', count: '36' },
];
let currentView = 'grid';
function getIcon(type) {
const icons = {
pdf: 'file-text',
folder: 'folder',
excel: 'table',
word: 'file-text',
powerpoint: 'presentation',
image: 'image',
zip: 'archive',
video: 'video',
audio: 'music'
};
return icons[type] || 'file';
}
function getColor(type) {
const colors = {
pdf: 'bg-red-100 text-red-600',
folder: 'bg-blue-100 text-blue-600',
excel: 'bg-green-100 text-green-600',
word: 'bg-blue-100 text-blue-600',
powerpoint: 'bg-orange-100 text-orange-600',
image: 'bg-purple-100 text-purple-600',
zip: 'bg-gray-100 text-gray-600',
video: 'bg-pink-100 text-pink-600'
};
return colors[type] || 'bg-gray-100 text-gray-600';
}
function getQuickAccessColor(color) {
const colorMap = {
blue: 'bg-blue-100 text-blue-600',
purple: 'bg-purple-100 text-purple-600',
pink: 'bg-pink-100 text-pink-600',
orange: 'bg-orange-100 text-orange-600'
};
return colorMap[color] || 'bg-gray-100 text-gray-600';
}
function renderQuickAccess() {
const container = document.getElementById('quickAccess');
if (!container) return;
container.innerHTML = quickAccess.map(item => `
<div class="bg-white p-4 rounded-2xl border border-gray-100 hover:shadow-md transition-all cursor-pointer group">
<div class="w-12 h-12 ${getQuickAccessColor(item.color)} rounded-xl flex items-center justify-center mb-3 group-hover:scale-110 transition-transform">
<i data-lucide="${item.icon}" class="w-6 h-6"></i>
</div>
<h3 class="font-medium text-gray-900 mb-1">${item.name}</h3>
<p class="text-xs text-gray-500">${item.count} archivos</p>
</div>
`).join('');
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
}
function renderFiles() {
const container = document.getElementById('filesContainer');
if (!container) return;
const searchInput = document.getElementById('searchInput');
const searchTerm = searchInput ? searchInput.value.toLowerCase() : '';
const filtered = files.filter(f => f.name.toLowerCase().includes(searchTerm));
if (currentView === 'grid') {
container.className = 'grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4';
container.innerHTML = filtered.map(file => `
<div class="file-card bg-white rounded-2xl p-4 border border-gray-100 cursor-pointer group transition-all">
<div class="flex items-start justify-between mb-3">
<div class="w-12 h-12 ${getColor(file.type)} rounded-xl flex items-center justify-center">
<i data-lucide="${getIcon(file.type)}" class="w-6 h-6"></i>
</div>
<button onclick="event.stopPropagation(); toggleMenu(${file.id})" class="p-1 hover:bg-gray-100 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity">
<i data-lucide="more-vertical" class="w-4 h-4 text-gray-400"></i>
</button>
</div>
<h3 class="font-medium text-gray-900 truncate mb-1" title="${file.name}">${file.name}</h3>
<div class="flex items-center justify-between text-xs text-gray-500">
<span>${file.size}</span>
<span>${file.date}</span>
</div>
</div>
`).join('');
} else {
container.className = 'space-y-2';
container.innerHTML = filtered.map(file => `
<div class="file-card bg-white rounded-xl p-4 border border-gray-100 cursor-pointer flex items-center gap-4 group hover:bg-gray-50 transition-all">
<div class="w-10 h-10 ${getColor(file.type)} rounded-lg flex items-center justify-center flex-shrink-0">
<i data-lucide="${getIcon(file.type)}" class="w-5 h-5"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="font-medium text-gray-900 truncate">${file.name}</h3>
<p class="text-xs text-gray-500">${file.date}</p>
</div>
<span class="text-sm text-gray-500 hidden sm:block">${file.size}</span>
<button onclick="event.stopPropagation(); toggleMenu(${file.id})" class="p-2 hover:bg-gray-200 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity">
<i data-lucide="more-vertical" class="w-4 h-4 text-gray-400"></i>
</button>
</div>
`).join('');
}
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
}
function toggleView(view) {
currentView = view;
const gridBtn = document.getElementById('gridBtn');
const listBtn = document.getElementById('listBtn');
if (gridBtn && listBtn) {
if (view === 'grid') {
gridBtn.className = 'p-2 rounded-lg bg-blue-50 text-blue-600';
listBtn.className = 'p-2 rounded-lg text-gray-400 hover:bg-gray-100';
} else {
gridBtn.className = 'p-2 rounded-lg text-gray-400 hover:bg-gray-100';
listBtn.className = 'p-2 rounded-lg bg-blue-50 text-blue-600';
}
}
renderFiles();
}
function filterFiles() {
renderFiles();
}
function triggerUpload() {
const fileInput = document.getElementById('fileInput');
if (fileInput) fileInput.click();
}
function handleFiles(selectedFiles) {
const modal = document.getElementById('uploadModal');
const list = document.getElementById('uploadList');
if (!modal || !list) return;
modal.classList.remove('hidden');
Array.from(selectedFiles).forEach(file => {
const id = Date.now() + Math.random();
const item = document.createElement('div');
item.className = 'flex items-center gap-3 upload-item-' + id;
item.innerHTML = `
<div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center flex-shrink-0">
<i data-lucide="file" class="w-4 h-4 text-blue-600"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">${file.name}</p>
<div class="w-full bg-gray-200 rounded-full h-1.5 mt-1">
<div class="bg-blue-600 h-1.5 rounded-full transition-all duration-300" style="width: 0%" id="progress-${id}"></div>
</div>
</div>
<span class="text-xs text-gray-500" id="status-${id}">0%</span>
`;
list.appendChild(item);
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
// Simulate upload
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 30;
if (progress >= 100) {
progress = 100;
clearInterval(interval);
const statusEl = document.getElementById(`status-${id}`);
if (statusEl) {
statusEl.textContent = '✓';
statusEl.className = 'text-xs text-green-600 font-medium';
}
setTimeout(() => {
item.remove();
if (list.children.length === 0) closeUploadModal();
}, 1000);
}
const progressEl = document.getElementById(`progress-${id}`);
const statusEl = document.getElementById(`status-${id}`);
if (progressEl) progressEl.style.width = progress + '%';
if (statusEl) statusEl.textContent = Math.floor(progress) + '%';
}, 300);
});
}
function closeUploadModal() {
const modal = document.getElementById('uploadModal');
if (modal) modal.classList.add('hidden');
}
function createFolder() {
const name = prompt('Nombre de la nueva carpeta:');
if (name && name.trim()) {
files.unshift({
id: Date.now(),
name: name.trim(),
type: 'folder',
size: '0 archivos',
date: new Date().toISOString().split('T')[0],
color: 'blue'
});
renderFiles();
}
}
function showSection(section) {
// Visual feedback only for demo
const buttons = document.querySelectorAll('.nav-item');
buttons.forEach(btn => {
btn.classList.remove('bg-blue-50', 'text-blue-600');
btn.classList.add('text-gray-600');
});
// Get the clicked button from event
const clickedBtn = event ? event.currentTarget : null;
if (clickedBtn) {
clickedBtn.classList.remove('text-gray-600');
clickedBtn.classList.add('bg-blue-50', 'text-blue-600');
}
// Here you would typically load different content based on section
console.log('Section:', section);
}
function toggleMenu(id) {
// Context menu logic - prevent errors
console.log('Menu for file:', id);
}
</script>
</body>
</html>