Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Todo App</title> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', sans-serif; } | |
| body { min-height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; justify-content: center; align-items: center; padding: 20px; } | |
| .container { background: white; border-radius: 20px; padding: 30px; width: 100%; max-width: 500px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); } | |
| header { text-align: center; margin-bottom: 25px; } | |
| header a { color: #667eea; text-decoration: none; font-size: 12px; opacity: 0.7; } | |
| header a:hover { opacity: 1; } | |
| h1 { color: #333; font-size: 2rem; margin: 10px 0; } | |
| .input-group { display: flex; gap: 10px; margin-bottom: 20px; } | |
| input[type="text"] { flex: 1; padding: 15px; border: 2px solid #e0e0e0; border-radius: 10px; font-size: 16px; transition: border-color 0.3s; } | |
| input[type="text"]:focus { outline: none; border-color: #667eea; } | |
| button { padding: 15px 25px; background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; border-radius: 10px; cursor: pointer; font-size: 16px; transition: transform 0.2s, box-shadow 0.2s; } | |
| button:hover { transform: translateY(-2px); box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4); } | |
| .todo-list { list-style: none; max-height: 400px; overflow-y: auto; } | |
| .todo-item { display: flex; align-items: center; gap: 15px; padding: 15px; background: #f8f9fa; border-radius: 10px; margin-bottom: 10px; transition: all 0.3s; animation: slideIn 0.3s ease; } | |
| @keyframes slideIn { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } } | |
| .todo-item:hover { background: #e9ecef; transform: translateX(5px); } | |
| .todo-item.completed span { text-decoration: line-through; color: #aaa; } | |
| .todo-item input[type="checkbox"] { width: 22px; height: 22px; accent-color: #667eea; cursor: pointer; } | |
| .todo-item span { flex: 1; font-size: 16px; word-break: break-word; } | |
| .delete-btn { background: #ff6b6b; padding: 8px 12px; border-radius: 8px; } | |
| .delete-btn:hover { background: #ee5a5a; } | |
| .empty-state { text-align: center; padding: 40px; color: #aaa; } | |
| .empty-state i { font-size: 50px; margin-bottom: 15px; } | |
| .stats { display: flex; justify-content: space-between; padding: 15px; background: linear-gradient(135deg, #667eea20, #764ba220); border-radius: 10px; margin-top: 15px; font-size: 14px; color: #666; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a> | |
| <h1><i class="fas fa-check-circle"></i> Todo App</h1> | |
| </header> | |
| <div class="input-group"> | |
| <input type="text" id="todoInput" placeholder="What needs to be done?" onkeypress="if(event.key==='Enter')addTodo()"> | |
| <button onclick="addTodo()"><i class="fas fa-plus"></i></button> | |
| </div> | |
| <ul class="todo-list" id="todoList"></ul> | |
| <div class="stats" id="stats"></div> | |
| </div> | |
| <script> | |
| let todos = JSON.parse(localStorage.getItem('todos')) || []; | |
| const render = () => { | |
| const list = document.getElementById('todoList'); | |
| const stats = document.getElementById('stats'); | |
| if (todos.length === 0) { | |
| list.innerHTML = '<div class="empty-state"><i class="fas fa-clipboard-list"></i><p>No tasks yet. Add one above!</p></div>'; | |
| stats.style.display = 'none'; | |
| } else { | |
| list.innerHTML = todos.map((t, i) => ` | |
| <li class="todo-item ${t.done ? 'completed' : ''}"> | |
| <input type="checkbox" ${t.done ? 'checked' : ''} onchange="toggle(${i})"> | |
| <span>${t.text}</span> | |
| <button class="delete-btn" onclick="remove(${i})"><i class="fas fa-trash"></i></button> | |
| </li> | |
| `).join(''); | |
| const done = todos.filter(t => t.done).length; | |
| stats.innerHTML = `<span><i class="fas fa-tasks"></i> Total: ${todos.length}</span><span><i class="fas fa-check"></i> Done: ${done}</span><span><i class="fas fa-hourglass-half"></i> Pending: ${todos.length - done}</span>`; | |
| stats.style.display = 'flex'; | |
| } | |
| localStorage.setItem('todos', JSON.stringify(todos)); | |
| }; | |
| const addTodo = () => { const input = document.getElementById('todoInput'); if (input.value.trim()) { todos.unshift({ text: input.value.trim(), done: false }); input.value = ''; render(); } }; | |
| const toggle = i => { todos[i].done = !todos[i].done; render(); }; | |
| const remove = i => { todos.splice(i, 1); render(); }; | |
| render(); | |
| </script> | |
| </body> | |
| </html> |