anycoder-96c696a4 / index.html
akhaliq's picture
akhaliq HF Staff
Upload folder using huggingface_hub
a612e72 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #6366f1;
--primary-hover: #4f46e5;
--bg-color: #f8fafc;
--card-bg: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
--border-color: #e2e8f0;
--success-color: #22c55e;
--danger-color: #ef4444;
--warning-color: #f59e0b;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
--radius: 12px;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.dark-mode {
--bg-color: #0f172a;
--card-bg: #1e293b;
--text-primary: #f1f5f9;
--text-secondary: #94a3b8;
--border-color: #334155;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg-color);
color: var(--text-primary);
min-height: 100vh;
transition: var(--transition);
line-height: 1.6;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 40px 20px;
}
/* Header */
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40px;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
}
.logo i {
font-size: 32px;
color: var(--primary-color);
}
.logo h1 {
font-size: 28px;
font-weight: 700;
background: linear-gradient(135deg, var(--primary-color), #8b5cf6);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.logo a {
text-decoration: none;
display: flex;
align-items: center;
gap: 12px;
}
.theme-toggle {
background: var(--card-bg);
border: 2px solid var(--border-color);
color: var(--text-primary);
width: 48px;
height: 48px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
transition: var(--transition);
box-shadow: var(--shadow);
}
.theme-toggle:hover {
border-color: var(--primary-color);
transform: rotate(15deg);
box-shadow: var(--shadow-lg);
}
/* Stats */
.stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 30px;
}
.stat-card {
background: var(--card-bg);
padding: 20px;
border-radius: var(--radius);
text-align: center;
box-shadow: var(--shadow);
border: 1px solid var(--border-color);
transition: var(--transition);
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
.stat-number {
font-size: 32px;
font-weight: 700;
color: var(--primary-color);
}
.stat-label {
font-size: 14px;
color: var(--text-secondary);
margin-top: 4px;
}
/* Add Todo Section */
.add-todo {
background: var(--card-bg);
border-radius: var(--radius);
padding: 24px;
margin-bottom: 24px;
box-shadow: var(--shadow);
border: 1px solid var(--border-color);
}
.input-group {
display: flex;
gap: 12px;
}
.todo-input {
flex: 1;
padding: 16px 20px;
border: 2px solid var(--border-color);
border-radius: var(--radius);
font-size: 16px;
background: var(--bg-color);
color: var(--text-primary);
transition: var(--transition);
}
.todo-input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
}
.todo-input::placeholder {
color: var(--text-secondary);
}
.add-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 16px 28px;
border-radius: var(--radius);
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 8px;
}
.add-btn:hover {
background: var(--primary-hover);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
}
.add-btn:active {
transform: translateY(0);
}
/* Filter Buttons */
.filters {
display: flex;
gap: 8px;
margin-bottom: 24px;
flex-wrap: wrap;
}
.filter-btn {
padding: 10px 20px;
border: 2px solid var(--border-color);
background: var(--card-bg);
color: var(--text-secondary);
border-radius: 25px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
}
.filter-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
}
.filter-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Todo List */
.todo-list {
list-style: none;
}
.todo-item {
background: var(--card-bg);
border-radius: var(--radius);
padding: 20px;
margin-bottom: 12px;
box-shadow: var(--shadow);
border: 1px solid var(--border-color);
display: flex;
align-items: center;
gap: 16px;
transition: var(--transition);
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.todo-item:hover {
box-shadow: var(--shadow-lg);
}
.todo-item.completed {
opacity: 0.7;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
color: var(--text-secondary);
}
.todo-item.dragging {
opacity: 0.5;
transform: scale(1.02);
}
.checkbox-wrapper {
position: relative;
width: 24px;
height: 24px;
}
.checkbox-wrapper input {
opacity: 0;
position: absolute;
width: 100%;
height: 100%;
cursor: pointer;
z-index: 2;
}
.custom-checkbox {
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border: 2px solid var(--border-color);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
transition: var(--transition);
cursor: pointer;
}
.checkbox-wrapper input:checked + .custom-checkbox {
background: var(--success-color);
border-color: var(--success-color);
}
.custom-checkbox i {
color: white;
font-size: 12px;
opacity: 0;
transform: scale(0);
transition: var(--transition);
}
.checkbox-wrapper input:checked + .custom-checkbox i {
opacity: 1;
transform: scale(1);
}
.todo-text {
flex: 1;
font-size: 16px;
font-weight: 500;
transition: var(--transition);
word-break: break-word;
}
.todo-actions {
display: flex;
gap: 8px;
opacity: 0;
transition: var(--transition);
}
.todo-item:hover .todo-actions {
opacity: 1;
}
.action-btn {
width: 36px;
height: 36px;
border: none;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: var(--transition);
}
.edit-btn {
background: rgba(99, 102, 241, 0.1);
color: var(--primary-color);
}
.edit-btn:hover {
background: var(--primary-color);
color: white;
}
.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--danger-color);
}
.delete-btn:hover {
background: var(--danger-color);
color: white;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state i {
font-size: 64px;
margin-bottom: 20px;
opacity: 0.3;
}
.empty-state h3 {
font-size: 20px;
margin-bottom: 8px;
color: var(--text-primary);
}
.empty-state p {
font-size: 14px;
}
/* Clear Completed */
.clear-completed {
text-align: center;
margin-top: 24px;
}
.clear-btn {
background: transparent;
border: 2px solid var(--danger-color);
color: var(--danger-color);
padding: 12px 24px;
border-radius: var(--radius);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
}
.clear-btn:hover {
background: var(--danger-color);
color: white;
}
/* Progress Bar */
.progress-container {
margin-bottom: 24px;
}
.progress-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.progress-label {
font-size: 14px;
color: var(--text-secondary);
}
.progress-percent {
font-size: 14px;
font-weight: 600;
color: var(--primary-color);
}
.progress-bar {
height: 8px;
background: var(--border-color);
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), #8b5cf6);
border-radius: 4px;
transition: width 0.5s ease;
width: 0%;
}
/* Responsive */
@media (max-width: 768px) {
.container {
padding: 20px 16px;
}
.header {
margin-bottom: 24px;
}
.logo h1 {
font-size: 24px;
}
.stats {
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.stat-card {
padding: 16px 12px;
}
.stat-number {
font-size: 24px;
}
.stat-label {
font-size: 12px;
}
.input-group {
flex-direction: column;
}
.add-btn {
width: 100%;
justify-content: center;
}
.todo-item {
padding: 16px;
gap: 12px;
}
.todo-actions {
opacity: 1;
}
.filters {
gap: 6px;
}
.filter-btn {
padding: 8px 16px;
font-size: 13px;
}
}
@media (max-width: 480px) {
.stats {
grid-template-columns: 1fr;
}
.header {
flex-direction: column;
gap: 16px;
}
.logo {
width: 100%;
justify-content: center;
}
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%) translateY(100px);
background: var(--card-bg);
color: var(--text-primary);
padding: 16px 24px;
border-radius: var(--radius);
box-shadow: var(--shadow-lg);
border: 1px solid var(--border-color);
z-index: 1000;
opacity: 0;
transition: var(--transition);
display: flex;
align-items: center;
gap: 12px;
}
.toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
.toast.success i {
color: var(--success-color);
}
.toast.warning i {
color: var(--warning-color);
}
/* Priority Badge */
.priority {
font-size: 10px;
padding: 4px 8px;
border-radius: 4px;
font-weight: 600;
text-transform: uppercase;
}
.priority.high {
background: rgba(239, 68, 68, 0.1);
color: var(--danger-color);
}
.priority.medium {
background: rgba(245, 158, 11, 0.1);
color: var(--warning-color);
}
.priority.low {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
/* Modal */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.modal-overlay.show {
opacity: 1;
visibility: visible;
}
.modal {
background: var(--card-bg);
padding: 32px;
border-radius: var(--radius);
width: 90%;
max-width: 450px;
transform: scale(0.9);
transition: var(--transition);
}
.modal-overlay.show .modal {
transform: scale(1);
}
.modal h2 {
margin-bottom: 24px;
font-size: 24px;
}
.modal-input {
width: 100%;
padding: 14px 18px;
border: 2px solid var(--border-color);
border-radius: var(--radius);
font-size: 16px;
background: var(--bg-color);
color: var(--text-primary);
margin-bottom: 16px;
transition: var(--transition);
}
.modal-input:focus {
outline: none;
border-color: var(--primary-color);
}
.modal-buttons {
display: flex;
gap: 12px;
justify-content: flex-end;
}
.modal-btn {
padding: 12px 24px;
border-radius: var(--radius);
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
}
.modal-btn.cancel {
background: transparent;
border: 2px solid var(--border-color);
color: var(--text-primary);
}
.modal-btn.cancel:hover {
border-color: var(--text-secondary);
}
.modal-btn.save {
background: var(--primary-color);
border: none;
color: white;
}
.modal-btn.save:hover {
background: var(--primary-hover);
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="logo">
<i class="fas fa-check-double"></i>
<h1>Todo App</h1>
</a>
<button class="theme-toggle" id="themeToggle" title="Toggle Theme">
<i class="fas fa-moon"></i>
</button>
</header>
<!-- Stats -->
<div class="stats">
<div class="stat-card">
<div class="stat-number" id="totalTodos">0</div>
<div class="stat-label">Total Tasks</div>
</div>
<div class="stat-card">
<div class="stat-number" id="completedTodos">0</div>
<div class="stat-label">Completed</div>
</div>
<div class="stat-card">
<div class="stat-number" id="pendingTodos">0</div>
<div class="stat-label">Pending</div>
</div>
</div>
<!-- Progress Bar -->
<div class="progress-container">
<div class="progress-header">
<span class="progress-label">Progress</span>
<span class="progress-percent" id="progressPercent">0%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
</div>
<!-- Add Todo -->
<div class="add-todo">
<div class="input-group">
<input type="text" class="todo-input" id="todoInput" placeholder="What needs to be done?">
<button class="add-btn" id="addBtn">
<i class="fas fa-plus"></i>
Add Task
</button>
</div>
</div>
<!-- Filters -->
<div class="filters">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="active">Active</button>
<button class="filter-btn" data-filter="completed">Completed</button>
</div>
<!-- Todo List -->
<ul class="todo-list" id="todoList">
<!-- Todo items will be rendered here -->
</ul>
<!-- Clear Completed -->
<div class="clear-completed" id="clearCompletedSection" style="display: none;">
<button class="clear-btn" id="clearCompleted">
<i class="fas fa-trash-alt"></i>
Clear Completed
</button>
</div>
</div>
<!-- Edit Modal -->
<div class="modal-overlay" id="editModal">
<div class="modal">
<h2>Edit Task</h2>
<input type="text" class="modal-input" id="editInput" placeholder="Edit your task...">
<div class="modal-buttons">
<button class="modal-btn cancel" id="cancelEdit">Cancel</button>
<button class="modal-btn save" id="saveEdit">Save Changes</button>
</div>
</div>
</div>
<!-- Toast -->
<div class="toast" id="toast">
<i class="fas fa-check-circle"></i>
<span id="toastMessage">Task added successfully!</span>
</div>
<script>
// DOM Elements
const todoInput = document.getElementById('todoInput');
const addBtn = document.getElementById('addBtn');
const todoList = document.getElementById('todoList');
const todoListItems = document.querySelectorAll('.todo-item');
const filterBtns = document.querySelectorAll('.filter-btn');
const clearCompletedBtn = document.getElementById('clearCompleted');
const themeToggle = document.getElementById('themeToggle');
const editModal = document.getElementById('editModal');
const editInput = document.getElementById('editInput');
const cancelEditBtn = document.getElementById('cancelEdit');
const saveEditBtn = document.getElementById('saveEdit');
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
const clearCompletedSection = document.getElementById('clearCompletedSection');
// State
let todos = JSON.parse(localStorage.getItem('todos')) || [];
let currentFilter = 'all';
let editingId = null;
let draggedItem = null;
// Initialize
document.addEventListener('DOMContentLoaded', () => {
renderTodos();
updateStats();
checkTheme();
});
// Theme Toggle
function checkTheme() {
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
themeToggle.innerHTML = '<i class="fas fa-sun"></i>';
}
}
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
const isDark = document.body.classList.contains('dark-mode');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
themeToggle.innerHTML = isDark ? '<i class="fas fa-sun"></i>' : '<i class="fas fa-moon"></i>';
});
// Add Todo
addBtn.addEventListener('click', addTodo);
todoInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') addTodo();
});
function addTodo() {
const text = todoInput.value.trim();
if (text === '') {
showToast('Please enter a task!', 'warning');
return;
}
const todo = {
id: Date.now(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
todos.unshift(todo);
saveTodos();
renderTodos();
updateStats();
todoInput.value = '';
showToast('Task added successfully!', 'success');
}
// Render Todos
function renderTodos() {
const filteredTodos = todos.filter(todo => {
if (currentFilter === 'active') return !todo.completed;
if (currentFilter === 'completed') return todo.completed;
return true;
});
if (filteredTodos.length === 0) {
todoList.innerHTML = `
<li class="empty-state">
<i class="fas fa-clipboard-list"></i>
<h3>${currentFilter === 'all' ? 'No tasks yet' : 'No ' + currentFilter + ' tasks'}</h3>
<p>${currentFilter === 'all' ? 'Add a task above to get started!' : 'Try changing your filter'}</p>
</li>
`;
} else {
todoList.innerHTML = filteredTodos.map(todo => `
<li class="todo-item ${todo.completed ? 'completed' : ''}" draggable="true" data-id="${todo.id}">
<div class="checkbox-wrapper">
<input type="checkbox" ${todo.completed ? 'checked' : ''} onchange="toggleTodo(${todo.id})">
<span class="custom-checkbox">
<i class="fas fa-check"></i>
</span>
</div>
<span class="todo-text">${escapeHtml(todo.text)}</span>
<div class="todo-actions">
<button class="action-btn edit-btn" onclick="openEditModal(${todo.id})" title="Edit">
<i class="fas fa-edit"></i>
</button>
<button class="action-btn delete-btn" onclick="deleteTodo(${todo.id})" title="Delete">
<i class="fas fa-trash"></i>
</button>
</div>
</li>
`).join('');
}
// Show/hide clear completed button
const completedCount = todos.filter(t => t.completed).length;
clearCompletedSection.style.display = completedCount > 0 ? 'block' : 'none';
// Add drag and drop listeners
addDragAndDropListeners();
}
// Toggle Todo
window.toggleTodo = function(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
saveTodos();
renderTodos();
updateStats();
showToast(todo.completed ? 'Task completed!' : 'Task marked as active', 'success');
}
};
// Delete Todo
window.deleteTodo = function(id) {
todos = todos.filter(t => t.id !== id);
saveTodos();
renderTodos();
updateStats();
showToast('Task deleted', 'warning');
};
// Edit Modal
window.openEditModal = function(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
editingId = id;
editInput.value = todo.text;
editModal.classList.add('show');
editInput.focus();
}
};
editModal.addEventListener('click', (e) => {
if (e.target === editModal) {
closeEditModal();
}
});
function closeEditModal() {
editModal.classList.remove('show');
editingId = null;
}
cancelEditBtn.addEventListener('click', closeEditModal);
saveEditBtn.addEventListener('click', () => {
const newText = editInput.value.trim();
if (newText === '') {
showToast('Task cannot be empty!', 'warning');
return;
}
const todo = todos.find(t => t.id === editingId);
if (todo) {
todo.text = newText;
saveTodos();
renderTodos();
updateStats();
showToast('Task updated!', 'success');
}
closeEditModal();
});
editInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') saveEditBtn.click();
});
// Filter Todos
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
filterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilter = btn.dataset.filter;
renderTodos();
});
});
// Clear Completed
clearCompletedBtn.addEventListener('click', () => {
const completedCount = todos.filter(t => t.completed).length;
todos = todos.filter(t => !t.completed);
saveTodos();
renderTodos();
updateStats();
showToast(`${completedCount} completed tasks cleared`, 'warning');
});
// Drag and Drop
function addDragAndDropListeners() {
const items = document.querySelectorAll('.todo-item');
items.forEach(item => {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('drop', handleDrop);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
});
}
function handleDragStart(e) {
draggedItem = this;
this.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
}
function handleDragEnd(e) {
this.classList.remove('dragging');
draggedItem = null;
}
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
}
function handleDragEnter(e) {
this.style.transform = 'scale(1.02)';
this.style.boxShadow = 'var(--shadow-lg)';
}
function handleDragLeave(e) {
this.style.transform = '';
this.style.boxShadow = '';
}
function handleDrop(e) {
e.preventDefault();
this.style.transform = '';
this.style.boxShadow = '';
if (draggedItem !== this) {
const draggedId = parseInt(draggedItem.dataset.id);
const droppedId = parseInt(this.dataset.id);
const draggedIndex = todos.findIndex(t => t.id === draggedId);
const droppedIndex = todos.findIndex(t => t.id === droppedId);
// Swap items
const [removed] = todos.splice(draggedIndex, 1);
todos.splice(droppedIndex, 0, removed);
saveTodos();
renderTodos();
}
}
// Update Stats
function updateStats() {
const total = todos.length;
const completed = todos.filter(t => t.completed).length;
const pending = total - completed;
const progress = total > 0 ? Math.round((completed / total) * 100) : 0;
document.getElementById('totalTodos').textContent = total;
document.getElementById('completedTodos').textContent = completed;
document.getElementById('pendingTodos').textContent = pending;
document.getElementById('progressPercent').textContent = progress + '%';
document.getElementById('progressFill').style.width = progress + '%';
}
// Toast Notification
function showToast(message, type = 'success') {
toast.className = 'toast ' + type;
toastMessage.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// Local Storage
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}
// Escape HTML
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Keyboard Shortcuts
document.addEventListener('keydown', (e) => {
// Ctrl/Cmd + N to focus input
if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
e.preventDefault();
todoInput.focus();
}
});
</script>
</body>
</html>