| | <!DOCTYPE html> |
| | <html lang="ar" dir="rtl"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>ู
ูุธู
ุงูู
ูุงู
ุงูููู
ู | To-Do List</title> |
| | |
| | |
| | <link rel="preconnect" href="https://fonts.googleapis.com"> |
| | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| | <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&display=swap" rel="stylesheet"> |
| |
|
| | <style> |
| | |
| | |
| | |
| | |
| | |
| | :root { |
| | --primary-color: #4facfe; |
| | --primary-dark: #00f2fe; |
| | --bg-color: #f0f4f8; |
| | --card-bg: #ffffff; |
| | --text-main: #2d3748; |
| | --text-light: #718096; |
| | --danger-color: #ff6b6b; |
| | --success-color: #48bb78; |
| | --border-radius: 16px; |
| | --shadow: 0 10px 30px rgba(0, 0, 0, 0.08); |
| | --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); |
| | } |
| | |
| | * { |
| | box-sizing: border-box; |
| | margin: 0; |
| | padding: 0; |
| | outline: none; |
| | } |
| | |
| | body { |
| | font-family: 'Cairo', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; |
| | background: var(--bg-color); |
| | background-image: linear-gradient(120deg, #fdfbfb 0%, #ebedee 100%); |
| | min-height: 100vh; |
| | display: flex; |
| | flex-direction: column; |
| | align-items: center; |
| | justify-content: center; |
| | color: var(--text-main); |
| | padding: 20px; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | header { |
| | text-align: center; |
| | margin-bottom: 2rem; |
| | width: 100%; |
| | } |
| | |
| | h1 { |
| | font-weight: 700; |
| | font-size: 2.5rem; |
| | color: var(--text-main); |
| | margin-bottom: 0.5rem; |
| | letter-spacing: -1px; |
| | } |
| | |
| | .anycoder-link { |
| | display: inline-block; |
| | text-decoration: none; |
| | background: rgba(79, 172, 254, 0.1); |
| | color: var(--primary-color); |
| | padding: 6px 12px; |
| | border-radius: 20px; |
| | font-size: 0.9rem; |
| | font-weight: 600; |
| | transition: var(--transition); |
| | } |
| | |
| | .anycoder-link:hover { |
| | background: var(--primary-color); |
| | color: white; |
| | transform: translateY(-2px); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .app-container { |
| | background: var(--card-bg); |
| | width: 100%; |
| | max-width: 500px; |
| | border-radius: var(--border-radius); |
| | box-shadow: var(--shadow); |
| | padding: 2rem; |
| | position: relative; |
| | overflow: hidden; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .input-group { |
| | display: flex; |
| | gap: 10px; |
| | margin-bottom: 2rem; |
| | position: relative; |
| | } |
| | |
| | input[type="text"] { |
| | flex-grow: 1; |
| | padding: 15px 20px; |
| | border: 2px solid #edf2f7; |
| | border-radius: 12px; |
| | font-family: inherit; |
| | font-size: 1rem; |
| | transition: var(--transition); |
| | background: #f8fafc; |
| | } |
| | |
| | input[type="text"]:focus { |
| | border-color: var(--primary-color); |
| | background: #fff; |
| | box-shadow: 0 0 0 4px rgba(79, 172, 254, 0.1); |
| | } |
| | |
| | .add-btn { |
| | background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); |
| | color: white; |
| | border: none; |
| | padding: 0 25px; |
| | border-radius: 12px; |
| | font-size: 1.5rem; |
| | cursor: pointer; |
| | transition: var(--transition); |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | min-width: 55px; |
| | } |
| | |
| | .add-btn:hover { |
| | transform: scale(1.05); |
| | box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4); |
| | } |
| | |
| | .add-btn:active { |
| | transform: scale(0.95); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .tasks-header { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | margin-bottom: 1rem; |
| | padding-bottom: 1rem; |
| | border-bottom: 1px solid #edf2f7; |
| | } |
| | |
| | .tasks-count { |
| | font-size: 0.9rem; |
| | color: var(--text-light); |
| | font-weight: 600; |
| | } |
| | |
| | .clear-all-btn { |
| | background: transparent; |
| | border: none; |
| | color: var(--danger-color); |
| | font-size: 0.85rem; |
| | cursor: pointer; |
| | font-weight: 600; |
| | transition: var(--transition); |
| | opacity: 0; |
| | pointer-events: none; |
| | } |
| | |
| | .clear-all-btn.visible { |
| | opacity: 1; |
| | pointer-events: all; |
| | } |
| | |
| | .clear-all-btn:hover { |
| | text-decoration: underline; |
| | } |
| | |
| | ul { |
| | list-style: none; |
| | max-height: 400px; |
| | overflow-y: auto; |
| | padding-right: 5px; |
| | } |
| | |
| | |
| | ul::-webkit-scrollbar { |
| | width: 6px; |
| | } |
| | ul::-webkit-scrollbar-track { |
| | background: #f1f1f1; |
| | border-radius: 10px; |
| | } |
| | ul::-webkit-scrollbar-thumb { |
| | background: #cbd5e0; |
| | border-radius: 10px; |
| | } |
| | ul::-webkit-scrollbar-thumb:hover { |
| | background: #a0aec0; |
| | } |
| | |
| | .task-item { |
| | display: flex; |
| | align-items: center; |
| | justify-content: space-between; |
| | background: #fff; |
| | padding: 1rem; |
| | margin-bottom: 10px; |
| | border-radius: 12px; |
| | border: 1px solid #edf2f7; |
| | transition: var(--transition); |
| | animation: slideIn 0.3s ease-out forwards; |
| | } |
| | |
| | @keyframes slideIn { |
| | from { opacity: 0; transform: translateY(20px); } |
| | to { opacity: 1; transform: translateY(0); } |
| | } |
| | |
| | .task-item:hover { |
| | transform: translateX(-5px); |
| | border-color: var(--primary-color); |
| | box-shadow: 0 4px 12px rgba(0,0,0,0.05); |
| | } |
| | |
| | .task-content { |
| | display: flex; |
| | align-items: center; |
| | gap: 12px; |
| | flex-grow: 1; |
| | cursor: pointer; |
| | } |
| | |
| | .custom-checkbox { |
| | width: 22px; |
| | height: 22px; |
| | border: 2px solid var(--primary-color); |
| | border-radius: 6px; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | transition: var(--transition); |
| | flex-shrink: 0; |
| | } |
| | |
| | .task-item.completed .custom-checkbox { |
| | background: var(--success-color); |
| | border-color: var(--success-color); |
| | } |
| | |
| | .task-item.completed .custom-checkbox::after { |
| | content: 'โ'; |
| | color: white; |
| | font-size: 14px; |
| | } |
| | |
| | .task-text { |
| | font-size: 1rem; |
| | transition: var(--transition); |
| | word-break: break-all; |
| | } |
| | |
| | .task-item.completed .task-text { |
| | text-decoration: line-through; |
| | color: #cbd5e0; |
| | } |
| | |
| | .delete-btn { |
| | background: #fff5f5; |
| | color: var(--danger-color); |
| | border: none; |
| | width: 32px; |
| | height: 32px; |
| | border-radius: 8px; |
| | cursor: pointer; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | transition: var(--transition); |
| | opacity: 0.6; |
| | } |
| | |
| | .delete-btn:hover { |
| | background: var(--danger-color); |
| | color: white; |
| | opacity: 1; |
| | transform: rotate(90deg); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .empty-state { |
| | text-align: center; |
| | padding: 2rem 0; |
| | color: var(--text-light); |
| | display: none; |
| | } |
| | |
| | .empty-state svg { |
| | width: 80px; |
| | height: 80px; |
| | margin-bottom: 1rem; |
| | fill: #e2e8f0; |
| | } |
| | |
| | .empty-state.visible { |
| | display: block; |
| | animation: fadeIn 0.5s ease; |
| | } |
| | |
| | @keyframes fadeIn { |
| | from { opacity: 0; } |
| | to { opacity: 1; } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | @media (max-width: 480px) { |
| | h1 { font-size: 2rem; } |
| | .app-container { padding: 1.5rem; } |
| | .input-group { flex-direction: column; } |
| | .add-btn { width: 100%; padding: 12px; } |
| | } |
| | </style> |
| | </head> |
| | <body> |
| |
|
| | |
| | <header> |
| | <h1>ู
ูุงู
ู ุงูููู
ูุฉ</h1> |
| | |
| | <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with anycoder</a> |
| | </header> |
| |
|
| | |
| | <main class="app-container"> |
| | |
| | |
| | <div class="input-group"> |
| | <input type="text" id="taskInput" placeholder="ุฃุถู ู
ูู
ุฉ ุฌุฏูุฏุฉ..." autocomplete="off"> |
| | <button class="add-btn" id="addBtn" title="ุฅุถุงูุฉ ู
ูู
ุฉ"> |
| | <span>+</span> |
| | </button> |
| | </div> |
| |
|
| | |
| | <div class="tasks-header"> |
| | <span class="tasks-count" id="tasksCount">0 ู
ูุงู
ู
ุชุจููุฉ</span> |
| | <button class="clear-all-btn" id="clearAllBtn">ู
ุณุญ ุงููู</button> |
| | </div> |
| |
|
| | |
| | <ul id="taskList"> |
| | |
| | </ul> |
| |
|
| | |
| | <div class="empty-state" id="emptyState"> |
| | <svg viewBox="0 0 24 24"> |
| | <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/> |
| | </svg> |
| | <p>ูุง ุชูุฌุฏ ู
ูุงู
ุญุงููุงูุ ุงุจุฏุฃ ููู
ู ุจุฅุถุงูุฉ ู
ูู
ุฉ!</p> |
| | </div> |
| |
|
| | </main> |
| |
|
| | <script> |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const taskInput = document.getElementById('taskInput'); |
| | const addBtn = document.getElementById('addBtn'); |
| | const taskList = document.getElementById('taskList'); |
| | const tasksCount = document.getElementById('tasksCount'); |
| | const clearAllBtn = document.getElementById('clearAllBtn'); |
| | const emptyState = document.getElementById('emptyState'); |
| | |
| | |
| | let tasks = []; |
| | |
| | |
| | document.addEventListener('DOMContentLoaded', () => { |
| | loadTasks(); |
| | renderTasks(); |
| | }); |
| | |
| | |
| | addBtn.addEventListener('click', addTask); |
| | |
| | taskInput.addEventListener('keypress', (e) => { |
| | if (e.key === 'Enter') addTask(); |
| | }); |
| | |
| | clearAllBtn.addEventListener('click', () => { |
| | if(confirm('ูู ุฃูุช ู
ุชุฃูุฏ ู
ู ุญุฐู ุฌู
ูุน ุงูู
ูุงู
ุ')) { |
| | tasks = []; |
| | saveTasks(); |
| | renderTasks(); |
| | } |
| | }); |
| | |
| | |
| | |
| | |
| | |
| | |
| | function addTask() { |
| | const text = taskInput.value.trim(); |
| | |
| | if (text === '') { |
| | |
| | taskInput.style.borderColor = '#ff6b6b'; |
| | setTimeout(() => taskInput.style.borderColor = '#edf2f7', 500); |
| | return; |
| | } |
| | |
| | const newTask = { |
| | id: Date.now(), |
| | text: text, |
| | completed: false |
| | }; |
| | |
| | tasks.unshift(newTask); |
| | saveTasks(); |
| | renderTasks(); |
| | |
| | taskInput.value = ''; |
| | taskInput.focus(); |
| | } |
| | |
| | |
| | |
| | |
| | function toggleTask(id) { |
| | tasks = tasks.map(task => { |
| | if (task.id === id) { |
| | return { ...task, completed: !task.completed }; |
| | } |
| | return task; |
| | }); |
| | saveTasks(); |
| | renderTasks(); |
| | } |
| | |
| | |
| | |
| | |
| | function deleteTask(id) { |
| | tasks = tasks.filter(task => task.id !== id); |
| | saveTasks(); |
| | renderTasks(); |
| | } |
| | |
| | |
| | |
| | |
| | function saveTasks() { |
| | localStorage.setItem('myTodoTasks', JSON.stringify(tasks)); |
| | } |
| | |
| | |
| | |
| | |
| | function loadTasks() { |
| | const storedTasks = localStorage.getItem('myTodoTasks'); |
| | if (storedTasks) { |
| | tasks = JSON.parse(storedTasks); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | function renderTasks() { |
| | taskList.innerHTML = ''; |
| | |
| | |
| | if (tasks.length === 0) { |
| | emptyState.classList.add('visible'); |
| | clearAllBtn.classList.remove('visible'); |
| | } else { |
| | emptyState.classList.remove('visible'); |
| | clearAllBtn.classList.add('visible'); |
| | } |
| | |
| | |
| | const remainingCount = tasks.filter(t => !t.completed).length; |
| | tasksCount.textContent = `${remainingCount} ู
ูุงู
ู
ุชุจููุฉ`; |
| | |
| | |
| | tasks.forEach(task => { |
| | const li = document.createElement('li'); |
| | li.className = `task-item ${task.completed ? 'completed' : ''}`; |
| | |
| | |
| | li.innerHTML = ` |
| | <div class="task-content" onclick="toggleTask(${task.id})"> |
| | <div class="custom-checkbox"></div> |
| | <span class="task-text">${escapeHtml(task.text)}</span> |
| | </div> |
| | <button class="delete-btn" onclick="deleteTask(${task.id})" title="ุญุฐู"> |
| | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
| | <polyline points="3 6 5 6 21 6"></polyline> |
| | <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> |
| | </svg> |
| | </button> |
| | `; |
| | |
| | taskList.appendChild(li); |
| | }); |
| | } |
| | |
| | |
| | |
| | |
| | function escapeHtml(text) { |
| | const map = { |
| | '&': '&', |
| | '<': '<', |
| | '>': '>', |
| | '"': '"', |
| | "'": ''' |
| | }; |
| | return text.replace(/[&<>"']/g, function(m) { return map[m]; }); |
| | } |
| | |
| | </script> |
| | </body> |
| | </html> |