testrun2 / index.html
Bencolliss's picture
https://huggingface.co/spaces/abdul12345sd/todolist1 - Initial Deployment
25764bb verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern To-Do List</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>
/* Custom scrollbar */
.task-list::-webkit-scrollbar {
width: 6px;
}
.task-list::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.task-list::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 10px;
}
.task-list::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* Animation for new tasks */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.task-item {
animation: fadeIn 0.3s ease-out;
}
/* Custom checkbox */
.custom-checkbox {
appearance: none;
-webkit-appearance: none;
width: 20px;
height: 20px;
border: 2px solid #cbd5e1;
border-radius: 4px;
cursor: pointer;
position: relative;
transition: all 0.2s;
}
.custom-checkbox:checked {
background-color: #4f46e5;
border-color: #4f46e5;
}
.custom-checkbox:checked::after {
content: '\2713';
position: absolute;
color: white;
font-size: 12px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
/* Dark mode toggle */
.dark-mode-toggle {
transition: all 0.3s;
}
.dark-mode-toggle:hover {
transform: rotate(30deg);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen transition-colors duration-300 dark:bg-gray-900">
<div class="container mx-auto px-4 py-8 max-w-3xl">
<!-- Header -->
<header class="flex justify-between items-center mb-8">
<h1 class="text-3xl font-bold text-indigo-600 dark:text-indigo-400">TaskMaster</h1>
<button id="darkModeToggle" class="dark-mode-toggle p-2 rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-yellow-300">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:inline"></i>
</button>
</header>
<!-- Add Task Form -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6 transition-all hover:shadow-lg">
<form id="taskForm" class="flex gap-3">
<input
type="text"
id="taskInput"
placeholder="Add a new task..."
class="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white"
autocomplete="off"
required
>
<button
type="submit"
class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition-colors flex items-center gap-2"
>
<i class="fas fa-plus"></i> Add
</button>
</form>
</div>
<!-- Task Filters -->
<div class="flex justify-between items-center mb-4">
<div class="text-gray-600 dark:text-gray-300">
<span id="taskCount">0</span> tasks
</div>
<div class="flex gap-2">
<button
id="filterAll"
class="filter-btn px-3 py-1 rounded-lg bg-indigo-600 text-white"
>
All
</button>
<button
id="filterActive"
class="filter-btn px-3 py-1 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
>
Active
</button>
<button
id="filterCompleted"
class="filter-btn px-3 py-1 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
>
Completed
</button>
</div>
</div>
<!-- Task List -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
<ul id="taskList" class="task-list max-h-96 overflow-y-auto">
<!-- Tasks will be added here dynamically -->
<li class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-tasks text-4xl mb-2"></i>
<p>No tasks yet. Add one above!</p>
</li>
</ul>
<!-- Task Actions -->
<div class="p-4 border-t border-gray-200 dark:border-gray-700 flex justify-between items-center">
<button
id="clearCompleted"
class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors"
>
Clear completed
</button>
<div class="text-sm text-gray-500 dark:text-gray-400">
<span id="completedCount">0</span> completed
</div>
</div>
</div>
<!-- Empty State Template (hidden by default) -->
<template id="emptyStateTemplate">
<li class="text-center py-8 text-gray-500 dark:text-gray-400">
<i class="fas fa-tasks text-4xl mb-2"></i>
<p>No tasks yet. Add one above!</p>
</li>
</template>
<!-- Task Item Template (hidden by default) -->
<template id="taskItemTemplate">
<li class="task-item border-b border-gray-200 dark:border-gray-700 last:border-0">
<div class="flex items-center px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
<input type="checkbox" class="custom-checkbox mr-3">
<span class="flex-1 text-gray-800 dark:text-gray-200 task-text"></span>
<button class="text-gray-400 hover:text-red-500 transition-colors delete-btn p-2 rounded-full">
<i class="fas fa-trash"></i>
</button>
</div>
</li>
</template>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const taskForm = document.getElementById('taskForm');
const taskInput = document.getElementById('taskInput');
const taskList = document.getElementById('taskList');
const taskCount = document.getElementById('taskCount');
const completedCount = document.getElementById('completedCount');
const clearCompletedBtn = document.getElementById('clearCompleted');
const filterAllBtn = document.getElementById('filterAll');
const filterActiveBtn = document.getElementById('filterActive');
const filterCompletedBtn = document.getElementById('filterCompleted');
const darkModeToggle = document.getElementById('darkModeToggle');
const emptyStateTemplate = document.getElementById('emptyStateTemplate');
const taskItemTemplate = document.getElementById('taskItemTemplate');
// State
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
let currentFilter = 'all';
// Initialize
renderTasks();
updateCounters();
// Event Listeners
taskForm.addEventListener('submit', addTask);
clearCompletedBtn.addEventListener('click', clearCompletedTasks);
filterAllBtn.addEventListener('click', () => setFilter('all'));
filterActiveBtn.addEventListener('click', () => setFilter('active'));
filterCompletedBtn.addEventListener('click', () => setFilter('completed'));
darkModeToggle.addEventListener('click', toggleDarkMode);
// Check for saved dark mode preference
if (localStorage.getItem('darkMode') === 'enabled') {
document.documentElement.classList.add('dark');
}
// Functions
function addTask(e) {
e.preventDefault();
const taskText = taskInput.value.trim();
if (!taskText) return;
const newTask = {
id: Date.now(),
text: taskText,
completed: false
};
tasks.unshift(newTask);
saveTasks();
renderTasks();
updateCounters();
taskInput.value = '';
taskInput.focus();
}
function renderTasks() {
// Clear the task list
taskList.innerHTML = '';
// Filter tasks based on current filter
let filteredTasks = [];
switch (currentFilter) {
case 'active':
filteredTasks = tasks.filter(task => !task.completed);
break;
case 'completed':
filteredTasks = tasks.filter(task => task.completed);
break;
default:
filteredTasks = [...tasks];
}
// Show empty state if no tasks
if (filteredTasks.length === 0) {
const emptyState = emptyStateTemplate.content.cloneNode(true);
taskList.appendChild(emptyState);
return;
}
// Render each task
filteredTasks.forEach(task => {
const taskItem = taskItemTemplate.content.cloneNode(true);
const checkbox = taskItem.querySelector('input[type="checkbox"]');
const taskText = taskItem.querySelector('.task-text');
const deleteBtn = taskItem.querySelector('.delete-btn');
checkbox.checked = task.completed;
taskText.textContent = task.text;
if (task.completed) {
taskText.classList.add('line-through', 'text-gray-400', 'dark:text-gray-500');
}
// Add event listeners to the new elements
checkbox.addEventListener('change', () => toggleTaskCompletion(task.id));
deleteBtn.addEventListener('click', () => deleteTask(task.id));
taskList.appendChild(taskItem);
});
}
function toggleTaskCompletion(taskId) {
tasks = tasks.map(task => {
if (task.id === taskId) {
return { ...task, completed: !task.completed };
}
return task;
});
saveTasks();
renderTasks();
updateCounters();
}
function deleteTask(taskId) {
tasks = tasks.filter(task => task.id !== taskId);
saveTasks();
renderTasks();
updateCounters();
}
function clearCompletedTasks() {
tasks = tasks.filter(task => !task.completed);
saveTasks();
renderTasks();
updateCounters();
}
function setFilter(filter) {
currentFilter = filter;
// Update active filter button styles
[filterAllBtn, filterActiveBtn, filterCompletedBtn].forEach(btn => {
btn.classList.remove('bg-indigo-600', 'text-white');
btn.classList.add('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300');
});
switch (filter) {
case 'all':
filterAllBtn.classList.add('bg-indigo-600', 'text-white');
filterAllBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300');
break;
case 'active':
filterActiveBtn.classList.add('bg-indigo-600', 'text-white');
filterActiveBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300');
break;
case 'completed':
filterCompletedBtn.classList.add('bg-indigo-600', 'text-white');
filterCompletedBtn.classList.remove('bg-gray-200', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300');
break;
}
renderTasks();
}
function updateCounters() {
const totalTasks = tasks.length;
const completedTasks = tasks.filter(task => task.completed).length;
const activeTasks = totalTasks - completedTasks;
taskCount.textContent = activeTasks;
completedCount.textContent = completedTasks;
// Show/hide clear completed button
if (completedTasks > 0) {
clearCompletedBtn.classList.remove('invisible');
} else {
clearCompletedBtn.classList.add('invisible');
}
}
function saveTasks() {
localStorage.setItem('tasks', JSON.stringify(tasks));
}
function toggleDarkMode() {
document.documentElement.classList.toggle('dark');
if (document.documentElement.classList.contains('dark')) {
localStorage.setItem('darkMode', 'enabled');
} else {
localStorage.setItem('darkMode', 'disabled');
}
}
});
</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=Bencolliss/testrun2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>