undefined / index.html
NimbleAINinja's picture
continue building the page
2707bf9 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tasky McTaskface - Your Magical Task Manager</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#7C3AED',
secondary: '#10B981'
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
}
.task-card {
transition: all 0.3s ease;
}
.task-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #c4b5fd;
border-radius: 10px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #8b5cf6;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<!-- Header -->
<header class="flex flex-col md:flex-row justify-between items-center mb-10">
<div>
<h1 class="text-3xl md:text-4xl font-bold text-primary">Tasky McTaskface</h1>
<p class="text-gray-600 mt-1">Your magical task manager ✨</p>
</div>
<div class="mt-4 md:mt-0 flex items-center space-x-4">
<button id="historyBtn" class="flex items-center text-gray-600 hover:text-primary transition-colors">
<i data-feather="clock"></i>
<span class="ml-2">History</span>
</button>
<button id="themeToggle" class="p-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 transition-colors">
<i data-feather="moon"></i>
</button>
</div>
</header>
<!-- Main Content -->
<main class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Add Task Section -->
<div class="lg:col-span-1 bg-white p-6 rounded-xl shadow-sm">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Add New Task</h2>
<form id="taskForm" class="space-y-4">
<div>
<label for="taskTitle" class="block text-sm font-medium text-gray-700 mb-1">Task Title</label>
<input type="text" id="taskTitle" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="What needs to be done?" required>
</div>
<div>
<label for="taskPriority" class="block text-sm font-medium text-gray-700 mb-1">Priority</label>
<select id="taskPriority" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="low">Low</option>
<option value="medium" selected>Medium</option>
<option value="high">High</option>
</select>
</div>
<div>
<label for="taskDueDate" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
<input type="date" id="taskDueDate" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div>
<label for="taskDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label>
<textarea id="taskDescription" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="Any additional details..."></textarea>
</div>
<button type="submit" class="w-full bg-primary hover:bg-purple-700 text-white font-medium py-2 px-4 rounded-lg transition-colors flex items-center justify-center">
<i data-feather="plus" class="mr-2"></i>
Add Task
</button>
</form>
</div>
<!-- Task List Section -->
<div class="lg:col-span-2 space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-xl font-semibold text-gray-800">Your Tasks</h2>
<div class="flex space-x-2">
<button id="filterAll" class="px-3 py-1 text-xs bg-primary text-white rounded-full">All</button>
<button id="filterActive" class="px-3 py-1 text-xs bg-gray-200 text-gray-700 rounded-full hover:bg-gray-300">Active</button>
<button id="filterCompleted" class="px-3 py-1 text-xs bg-gray-200 text-gray-700 rounded-full hover:bg-gray-300">Completed</button>
</div>
</div>
<div id="taskList" class="space-y-4 max-h-[600px] overflow-y-auto custom-scrollbar">
<!-- Task items will be dynamically inserted here -->
<div class="task-card bg-white p-4 rounded-lg shadow-sm border-l-4 border-primary">
<div class="flex justify-between items-start">
<div class="flex items-start space-x-3">
<button class="task-checkbox mt-1">
<i data-feather="circle" class="text-gray-300 hover:text-primary"></i>
</button>
<div>
<h3 class="font-medium text-gray-800">Example Task</h3>
<p class="text-sm text-gray-500 mt-1">This is an example task description that shows how tasks will appear.</p>
<div class="flex items-center mt-2 space-x-4">
<span class="text-xs px-2 py-1 bg-purple-100 text-primary rounded-full">Medium</span>
<span class="text-xs text-gray-500"><i data-feather="calendar" class="inline w-3 h-3 mr-1"></i> Tomorrow</span>
</div>
</div>
</div>
<button class="task-delete text-gray-400 hover:text-red-500">
<i data-feather="trash-2"></i>
</button>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- History Modal -->
<div id="historyModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white rounded-xl w-full max-w-2xl max-h-[80vh] overflow-hidden flex flex-col">
<div class="p-6 border-b border-gray-200">
<div class="flex justify-between items-center">
<h2 class="text-xl font-semibold text-gray-800">Task History</h2>
<button id="closeHistoryModal" class="text-gray-500 hover:text-gray-700">
<i data-feather="x"></i>
</button>
</div>
</div>
<div id="historyList" class="overflow-y-auto p-6 space-y-4">
<!-- History items will be dynamically inserted here -->
<div class="bg-gray-50 p-4 rounded-lg">
<div class="flex justify-between">
<span class="font-medium text-gray-700 line-through">Example Completed Task</span>
<span class="text-sm text-gray-500">Completed: Today</span>
</div>
<div class="flex items-center mt-2">
<span class="text-xs px-2 py-1 bg-green-100 text-secondary rounded-full mr-2">Medium</span>
<span class="text-xs text-gray-500">Completed in 2 days</span>
</div>
</div>
</div>
<div class="p-4 border-t border-gray-200 flex justify-end">
<button id="clearHistory" class="text-sm text-red-500 hover:text-red-700 flex items-center">
<i data-feather="trash-2" class="w-4 h-4 mr-1"></i>
Clear History
</button>
</div>
</div>
</div>
<script>
// Initialize Feather Icons
feather.replace();
// DOM Elements
const taskForm = document.getElementById('taskForm');
const taskTitle = document.getElementById('taskTitle');
const taskPriority = document.getElementById('taskPriority');
const taskDueDate = document.getElementById('taskDueDate');
const taskDescription = document.getElementById('taskDescription');
const taskList = document.getElementById('taskList');
const historyBtn = document.getElementById('historyBtn');
const historyModal = document.getElementById('historyModal');
const closeHistoryModal = document.getElementById('closeHistoryModal');
const historyList = document.getElementById('historyList');
const clearHistory = document.getElementById('clearHistory');
const themeToggle = document.getElementById('themeToggle');
const filterAll = document.getElementById('filterAll');
const filterActive = document.getElementById('filterActive');
const filterCompleted = document.getElementById('filterCompleted');
// Sample tasks data
let tasks = [
{
id: 1,
title: 'Complete project proposal',
description: 'Finish the draft and send for review',
priority: 'high',
dueDate: '2023-05-20',
completed: false,
createdAt: new Date().toISOString()
},
{
id: 2,
title: 'Buy groceries',
description: 'Milk, eggs, bread, fruits',
priority: 'medium',
dueDate: '2023-05-18',
completed: false,
createdAt: new Date().toISOString()
}
];
let completedTasks = [
{
id: 3,
title: 'Call mom',
description: 'Wish her happy birthday',
priority: 'high',
dueDate: '2023-05-15',
completed: true,
completedAt: new Date().toISOString(),
createdAt: new Date('2023-05-10').toISOString()
}
];
// Theme management
function toggleTheme() {
document.documentElement.classList.toggle('dark');
const isDark = document.documentElement.classList.contains('dark');
localStorage.setItem('darkMode', isDark);
feather.replace();
}
// Initialize theme
if (localStorage.getItem('darkMode') === 'true') {
document.documentElement.classList.add('dark');
}
themeToggle.addEventListener('click', toggleTheme);
// Task rendering functions
function renderTasks(filter = 'all') {
taskList.innerHTML = '';
const filteredTasks = tasks.filter(task => {
if (filter === 'active') return !task.completed;
if (filter === 'completed') return task.completed;
return true;
});
if (filteredTasks.length === 0) {
taskList.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i data-feather="inbox" class="w-12 h-12 mx-auto text-gray-300"></i>
<p class="mt-2">No tasks found</p>
</div>
`;
feather.replace();
return;
}
filteredTasks.forEach(task => {
const taskElement = document.createElement('div');
taskElement.className = `task-card bg-white p-4 rounded-lg shadow-sm border-l-4 ${task.priority === 'high' ? 'border-red-500' : task.priority === 'medium' ? 'border-primary' : 'border-blue-500'}`;
const priorityColors = {
high: 'bg-red-100 text-red-800',
medium: 'bg-purple-100 text-primary',
low: 'bg-blue-100 text-blue-800'
};
taskElement.innerHTML = `
<div class="flex justify-between items-start">
<div class="flex items-start space-x-3">
<button class="task-checkbox mt-1" data-id="${task.id}">
<i data-feather="${task.completed ? 'check-circle' : 'circle'}" class="${task.completed ? 'text-secondary' : 'text-gray-300 hover:text-primary'}"></i>
</button>
<div>
<h3 class="font-medium text-gray-800 ${task.completed ? 'line-through text-gray-500' : ''}">${task.title}</h3>
<p class="text-sm text-gray-500 mt-1 ${task.completed ? 'line-through' : ''}">${task.description}</p>
<div class="flex items-center mt-2 space-x-4">
<span class="text-xs px-2 py-1 ${priorityColors[task.priority]} rounded-full">${task.priority.charAt(0).toUpperCase() + task.priority.slice(1)}</span>
${task.dueDate ? `<span class="text-xs text-gray-500"><i data-feather="calendar" class="inline w-3 h-3 mr-1"></i> ${formatDate(task.dueDate)}</span>` : ''}
</div>
</div>
</div>
<button class="task-delete text-gray-400 hover:text-red-500" data-id="${task.id}">
<i data-feather="trash-2"></i>
</button>
</div>
`;
taskList.appendChild(taskElement);
});
feather.replace();
}
function formatDate(dateString) {
const date = new Date(dateString);
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
if (date.toDateString() === today.toDateString()) {
return 'Today';
} else if (date.toDateString() === tomorrow.toDateString()) {
return 'Tomorrow';
} else {
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}
}
// Handle form submission
taskForm.addEventListener('submit', function(e) {
e.preventDefault();
const newTask = {
id: Date.now(),
title: taskTitle.value,
description: taskDescription.value,
priority: taskPriority.value,
dueDate: taskDueDate.value,
completed: false,
createdAt: new Date().toISOString()
};
tasks.unshift(newTask);
renderTasks();
taskForm.reset();
});
// Event delegation for task actions
taskList.addEventListener('click', function(e) {
const target = e.target.closest('.task-checkbox') || e.target.closest('.task-delete');
if (!target) return;
const taskId = parseInt(target.dataset.id);
const taskIndex = tasks.findIndex(task => task.id === taskId);
if (target.classList.contains('task-checkbox')) {
tasks[taskIndex].completed = !tasks[taskIndex].completed;
if (tasks[taskIndex].completed) {
tasks[taskIndex].completedAt = new Date().toISOString();
}
renderTasks();
} else if (target.classList.contains('task-delete')) {
tasks.splice(taskIndex, 1);
renderTasks();
}
});
// Filter buttons
filterAll.addEventListener('click', () => {
filterAll.classList.add('bg-primary', 'text-white');
filterAll.classList.remove('bg-gray-200', 'text-gray-700');
filterActive.classList.add('bg-gray-200', 'text-gray-700');
filterActive.classList.remove('bg-primary', 'text-white');
filterCompleted.classList.add('bg-gray-200', 'text-gray-700');
filterCompleted.classList.remove('bg-primary', 'text-white');
renderTasks('all');
});
filterActive.addEventListener('click', () => {
filterActive.classList.add('bg-primary', 'text-white');
filterActive.classList.remove('bg-gray-200', 'text-gray-700');
filterAll.classList.add('bg-gray-200', 'text-gray-700');
filterAll.classList.remove('bg-primary', 'text-white');
filterCompleted.classList.add('bg-gray-200', 'text-gray-700');
filterCompleted.classList.remove('bg-primary', 'text-white');
renderTasks('active');
});
filterCompleted.addEventListener('click', () => {
filterCompleted.classList.add('bg-primary', 'text-white');
filterCompleted.classList.remove('bg-gray-200', 'text-gray-700');
filterAll.classList.add('bg-gray-200', 'text-gray-700');
filterAll.classList.remove('bg-primary', 'text-white');
filterActive.classList.add('bg-gray-200', 'text-gray-700');
filterActive.classList.remove('bg-primary', 'text-white');
renderTasks('completed');
});
// History modal
historyBtn.addEventListener('click', () => {
renderHistory();
historyModal.classList.remove('hidden');
});
closeHistoryModal.addEventListener('click', () => {
historyModal.classList.add('hidden');
});
function renderHistory() {
historyList.innerHTML = '';
if (completedTasks.length === 0) {
historyList.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i data-feather="clock" class="w-12 h-12 mx-auto text-gray-300"></i>
<p class="mt-2">No completed tasks yet</p>
</div>
`;
feather.replace();
return;
}
completedTasks.forEach(task => {
const historyElement = document.createElement('div');
historyElement.className = 'bg-gray-50 p-4 rounded-lg';
const completedDate = new Date(task.completedAt);
const createdAt = new Date(task.createdAt);
const daysToComplete = Math.floor((completedDate - createdAt) / (1000 * 60 * 60 * 24));
historyElement.innerHTML = `
<div class="flex justify-between">
<span class="font-medium text-gray-700 line-through">${task.title}</span>
<span class="text-sm text-gray-500">Completed: ${formatDate(task.completedAt)}</span>
</div>
<div class="flex items-center mt-2">
<span class="text-xs px-2 py-1 ${task.priority === 'high' ? 'bg-red-100 text-red-800' : task.priority === 'medium' ? 'bg-purple-100 text-primary' : 'bg-blue-100 text-blue-800'} rounded-full mr-2">
${task.priority.charAt(0).toUpperCase() + task.priority.slice(1)}
</span>
<span class="text-xs text-gray-500">Completed in ${daysToComplete} day${daysToComplete !== 1 ? 's' : ''}</span>
</div>
${task.description ? `<p class="text-sm text-gray-500 mt-2 line-through">${task.description}</p>` : ''}
`;
historyList.appendChild(historyElement);
});
feather.replace();
}
clearHistory.addEventListener('click', () => {
completedTasks = [];
renderHistory();
});
// Initialize
renderTasks();
</script>
</body>
</html>