Backtun's picture
Add 2 files
fe6f28a verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tablero Kanban</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>
.kanban-column {
min-height: 300px;
transition: all 0.3s ease;
}
.kanban-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: grab;
user-select: none;
}
.kanban-card:active {
cursor: grabbing;
}
.kanban-card.dragging {
opacity: 0.5;
transform: scale(1.02);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
}
.kanban-column.drop-zone {
background-color: rgba(209, 250, 229, 0.3);
border: 2px dashed #10b981;
}
.add-card-input {
transition: all 0.3s ease;
max-height: 0;
overflow: hidden;
}
.add-card-input.active {
max-height: 100px;
padding: 8px;
margin-top: 8px;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen p-4">
<div class="container mx-auto">
<h1 class="text-3xl font-bold text-center mb-8 text-gray-800">Tablero Kanban</h1>
<div class="flex flex-col md:flex-row gap-4">
<!-- Columna Por hacer -->
<div class="kanban-column bg-white rounded-lg shadow-md flex-1" data-status="todo">
<div class="p-4 border-b border-gray-200 flex justify-between items-center bg-blue-50 rounded-t-lg">
<h2 class="font-semibold text-blue-700">Por hacer</h2>
<span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full">
<span id="todo-count">3</span> tareas
</span>
</div>
<div class="p-2 space-y-2 todo-cards">
<!-- Tarjetas de ejemplo -->
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="1">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Diseñar interfaz de usuario</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Crear wireframes para la nueva aplicación</p>
<div class="flex items-center mt-2 text-xs text-gray-400">
<i class="far fa-calendar-alt mr-1"></i>
<span>Para hoy</span>
</div>
</div>
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="2">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Reunión con el equipo</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Discutir los requerimientos del proyecto</p>
</div>
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="3">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Investigar tecnologías</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Comparar frameworks para el frontend</p>
</div>
</div>
<div class="p-2">
<button class="add-task-btn w-full py-2 text-sm text-blue-600 hover:text-blue-800 flex items-center justify-center">
<i class="fas fa-plus mr-2"></i> Añadir tarea
</button>
<div class="add-card-input">
<div class="flex">
<input type="text" class="flex-1 border border-gray-300 rounded-l px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500" placeholder="Título de la tarea">
<button class="bg-blue-500 text-white px-3 py-2 rounded-r text-sm hover:bg-blue-600 confirm-add">
<i class="fas fa-check"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Columna En progreso -->
<div class="kanban-column bg-white rounded-lg shadow-md flex-1" data-status="progress">
<div class="p-4 border-b border-gray-200 flex justify-between items-center bg-yellow-50 rounded-t-lg">
<h2 class="font-semibold text-yellow-700">En progreso</h2>
<span class="bg-yellow-100 text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded-full">
<span id="progress-count">2</span> tareas
</span>
</div>
<div class="p-2 space-y-2 progress-cards">
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="4">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Desarrollar funcionalidad principal</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Implementar el sistema de arrastrar y soltar</p>
<div class="flex items-center mt-2 text-xs text-gray-400">
<i class="fas fa-user mr-1"></i>
<span>Asignado a: Juan</span>
</div>
</div>
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="5">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Escribir documentación</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Documentar la API del backend</p>
</div>
</div>
<div class="p-2">
<button class="add-task-btn w-full py-2 text-sm text-yellow-600 hover:text-yellow-800 flex items-center justify-center">
<i class="fas fa-plus mr-2"></i> Añadir tarea
</button>
<div class="add-card-input">
<div class="flex">
<input type="text" class="flex-1 border border-gray-300 rounded-l px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-yellow-500" placeholder="Título de la tarea">
<button class="bg-yellow-500 text-white px-3 py-2 rounded-r text-sm hover:bg-yellow-600 confirm-add">
<i class="fas fa-check"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Columna Hecho -->
<div class="kanban-column bg-white rounded-lg shadow-md flex-1" data-status="done">
<div class="p-4 border-b border-gray-200 flex justify-between items-center bg-green-50 rounded-t-lg">
<h2 class="font-semibold text-green-700">Hecho</h2>
<span class="bg-green-100 text-green-800 text-xs font-medium px-2.5 py-0.5 rounded-full">
<span id="done-count">1</span> tarea
</span>
</div>
<div class="p-2 space-y-2 done-cards">
<div class="kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm" draggable="true" data-task-id="6">
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">Configurar entorno de desarrollo</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Instalar todas las dependencias necesarias</p>
<div class="flex items-center mt-2 text-xs text-gray-400">
<i class="far fa-check-circle mr-1 text-green-500"></i>
<span>Completado ayer</span>
</div>
</div>
</div>
<div class="p-2">
<button class="add-task-btn w-full py-2 text-sm text-green-600 hover:text-green-800 flex items-center justify-center">
<i class="fas fa-plus mr-2"></i> Añadir tarea
</button>
<div class="add-card-input">
<div class="flex">
<input type="text" class="flex-1 border border-gray-300 rounded-l px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-green-500" placeholder="Título de la tarea">
<button class="bg-green-500 text-white px-3 py-2 rounded-r text-sm hover:bg-green-600 confirm-add">
<i class="fas fa-check"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Variables para el arrastre
let draggedItem = null;
let currentColumn = null;
// Contadores de tareas
const todoCount = document.getElementById('todo-count');
const progressCount = document.getElementById('progress-count');
const doneCount = document.getElementById('done-count');
// Funciones para actualizar contadores
function updateCounters() {
todoCount.textContent = document.querySelector('.todo-cards').children.length;
progressCount.textContent = document.querySelector('.progress-cards').children.length;
doneCount.textContent = document.querySelector('.done-cards').children.length;
}
// Eventos de arrastre para las tarjetas
const cards = document.querySelectorAll('.kanban-card');
cards.forEach(card => {
card.addEventListener('dragstart', function() {
draggedItem = this;
currentColumn = this.parentElement;
setTimeout(() => {
this.classList.add('dragging');
}, 0);
});
card.addEventListener('dragend', function() {
this.classList.remove('dragging');
draggedItem = null;
currentColumn = null;
});
// Eliminar tarea
const deleteBtn = card.querySelector('.delete-task');
deleteBtn.addEventListener('click', function(e) {
e.stopPropagation();
if (confirm('¿Estás seguro de eliminar esta tarea?')) {
card.remove();
updateCounters();
}
});
});
// Eventos para las columnas
const columns = document.querySelectorAll('.kanban-column');
columns.forEach(column => {
column.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('drop-zone');
});
column.addEventListener('dragleave', function() {
this.classList.remove('drop-zone');
});
column.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('drop-zone');
if (draggedItem && this !== currentColumn) {
const cardsContainer = this.querySelector('.kanban-column > div:nth-child(2)');
cardsContainer.appendChild(draggedItem);
updateCounters();
}
});
});
// Funcionalidad para añadir nuevas tareas
const addTaskBtns = document.querySelectorAll('.add-task-btn');
addTaskBtns.forEach(btn => {
btn.addEventListener('click', function() {
const column = this.closest('.kanban-column');
const inputContainer = column.querySelector('.add-card-input');
inputContainer.classList.toggle('active');
});
});
const confirmAddBtns = document.querySelectorAll('.confirm-add');
confirmAddBtns.forEach(btn => {
btn.addEventListener('click', function() {
const column = this.closest('.kanban-column');
const input = column.querySelector('.add-card-input input');
const title = input.value.trim();
if (title) {
const status = column.dataset.status;
const cardsContainer = column.querySelector(`.${status}-cards`);
// Crear nueva tarjeta
const newCard = document.createElement('div');
newCard.className = 'kanban-card p-3 bg-white rounded border border-gray-200 shadow-sm';
newCard.setAttribute('draggable', 'true');
newCard.setAttribute('data-task-id', Date.now());
newCard.innerHTML = `
<div class="flex justify-between items-start">
<h3 class="font-medium text-gray-800">${title}</h3>
<button class="text-gray-400 hover:text-red-500 delete-task">
<i class="fas fa-times"></i>
</button>
</div>
<p class="text-sm text-gray-500 mt-1">Descripción de la tarea</p>
<div class="flex items-center mt-2 text-xs text-gray-400">
<i class="far fa-calendar-alt mr-1"></i>
<span>Nueva tarea</span>
</div>
`;
// Agregar evento de arrastre a la nueva tarjeta
newCard.addEventListener('dragstart', function() {
draggedItem = this;
currentColumn = this.parentElement;
setTimeout(() => {
this.classList.add('dragging');
}, 0);
});
newCard.addEventListener('dragend', function() {
this.classList.remove('dragging');
draggedItem = null;
currentColumn = null;
});
// Agregar evento para eliminar
const deleteBtn = newCard.querySelector('.delete-task');
deleteBtn.addEventListener('click', function(e) {
e.stopPropagation();
if (confirm('¿Estás seguro de eliminar esta tarea?')) {
newCard.remove();
updateCounters();
}
});
cardsContainer.appendChild(newCard);
input.value = '';
column.querySelector('.add-card-input').classList.remove('active');
updateCounters();
}
});
});
// Permitir añadir tareas con Enter
const inputs = document.querySelectorAll('.add-card-input input');
inputs.forEach(input => {
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
this.closest('.kanban-column').querySelector('.confirm-add').click();
}
});
});
});
</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=Backtun/tablero-kanban-deepsite" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>