| | <!DOCTYPE html> |
| | <html lang="ar" dir="rtl"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>مهامي - منظم المهام اليومية</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: #3b82f6; |
| | --primary-hover: #2563eb; |
| | --bg-color: #f0f7ff; |
| | --card-bg: #ffffff; |
| | --text-main: #1e293b; |
| | --text-light: #94a3b8; |
| | --danger-color: #ef4444; |
| | --success-color: #10b981; |
| | --shadow-soft: 0 10px 25px -5px rgba(59, 130, 246, 0.15); |
| | --shadow-hover: 0 20px 25px -5px rgba(59, 130, 246, 0.2); |
| | --radius: 16px; |
| | --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| | } |
| | |
| | * { |
| | margin: 0; |
| | padding: 0; |
| | box-sizing: border-box; |
| | font-family: 'Cairo', sans-serif; |
| | } |
| | |
| | body { |
| | background-color: var(--bg-color); |
| | color: var(--text-main); |
| | min-height: 100vh; |
| | display: flex; |
| | flex-direction: column; |
| | align-items: center; |
| | justify-content: center; |
| | padding: 20px; |
| | background-image: radial-gradient(#e0eafc 1px, transparent 1px); |
| | background-size: 20px 20px; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .app-container { |
| | background: var(--card-bg); |
| | width: 100%; |
| | max-width: 480px; |
| | border-radius: var(--radius); |
| | box-shadow: var(--shadow-soft); |
| | padding: 2rem; |
| | position: relative; |
| | transition: var(--transition); |
| | } |
| | |
| | .app-container:hover { |
| | box-shadow: var(--shadow-hover); |
| | transform: translateY(-2px); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | header { |
| | text-align: center; |
| | margin-bottom: 2rem; |
| | } |
| | |
| | h1 { |
| | font-size: 1.8rem; |
| | font-weight: 700; |
| | color: var(--primary-color); |
| | margin-bottom: 0.5rem; |
| | } |
| | |
| | .subtitle { |
| | color: var(--text-light); |
| | font-size: 0.9rem; |
| | } |
| | |
| | |
| | .anycoder-link { |
| | display: inline-block; |
| | margin-top: 10px; |
| | font-size: 0.75rem; |
| | color: var(--text-light); |
| | text-decoration: none; |
| | padding: 4px 12px; |
| | background: #f1f5f9; |
| | border-radius: 20px; |
| | transition: var(--transition); |
| | } |
| | |
| | .anycoder-link:hover { |
| | background: var(--primary-color); |
| | color: white; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .input-group { |
| | display: flex; |
| | gap: 10px; |
| | margin-bottom: 1.5rem; |
| | position: relative; |
| | } |
| | |
| | input[type="text"] { |
| | flex-grow: 1; |
| | padding: 14px 20px; |
| | border: 2px solid #e2e8f0; |
| | border-radius: 12px; |
| | font-size: 1rem; |
| | outline: none; |
| | transition: var(--transition); |
| | background: #f8fafc; |
| | } |
| | |
| | input[type="text"]:focus { |
| | border-color: var(--primary-color); |
| | background: #fff; |
| | box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); |
| | } |
| | |
| | |
| | input[type="text"].error { |
| | border-color: var(--danger-color); |
| | animation: shake 0.4s ease-in-out; |
| | } |
| | |
| | .add-btn { |
| | background: var(--primary-color); |
| | color: white; |
| | border: none; |
| | width: 54px; |
| | border-radius: 12px; |
| | cursor: pointer; |
| | font-size: 1.5rem; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | transition: var(--transition); |
| | } |
| | |
| | .add-btn:hover { |
| | background: var(--primary-hover); |
| | transform: scale(1.05); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .tasks-header { |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | margin-bottom: 1rem; |
| | padding-bottom: 0.5rem; |
| | border-bottom: 1px solid #f1f5f9; |
| | } |
| | |
| | .tasks-count { |
| | font-size: 0.9rem; |
| | font-weight: 600; |
| | color: var(--text-main); |
| | } |
| | |
| | .clear-btn { |
| | background: none; |
| | border: none; |
| | color: var(--text-light); |
| | font-size: 0.8rem; |
| | cursor: pointer; |
| | transition: var(--transition); |
| | padding: 5px 10px; |
| | border-radius: 6px; |
| | } |
| | |
| | .clear-btn:hover { |
| | color: var(--danger-color); |
| | background: #fee2e2; |
| | } |
| | |
| | ul { |
| | list-style: none; |
| | max-height: 400px; |
| | overflow-y: auto; |
| | padding-right: 5px; |
| | } |
| | |
| | |
| | ul::-webkit-scrollbar { |
| | width: 6px; |
| | } |
| | ul::-webkit-scrollbar-track { |
| | background: transparent; |
| | } |
| | ul::-webkit-scrollbar-thumb { |
| | background: #cbd5e1; |
| | border-radius: 10px; |
| | } |
| | |
| | |
| | .task-item { |
| | background: #fff; |
| | border: 1px solid #f1f5f9; |
| | border-radius: 12px; |
| | padding: 12px 16px; |
| | margin-bottom: 10px; |
| | display: flex; |
| | align-items: center; |
| | justify-content: space-between; |
| | transition: var(--transition); |
| | animation: slideIn 0.3s ease-out forwards; |
| | } |
| | |
| | .task-item:hover { |
| | border-color: #bfdbfe; |
| | transform: translateX(-3px); |
| | } |
| | |
| | .task-content { |
| | display: flex; |
| | align-items: center; |
| | gap: 12px; |
| | flex-grow: 1; |
| | cursor: pointer; |
| | } |
| | |
| | |
| | .custom-checkbox { |
| | width: 22px; |
| | height: 22px; |
| | border: 2px solid #cbd5e1; |
| | border-radius: 50%; |
| | 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; |
| | font-weight: bold; |
| | } |
| | |
| | .task-text { |
| | font-size: 1rem; |
| | transition: var(--transition); |
| | word-break: break-all; |
| | } |
| | |
| | .task-item.completed .task-text { |
| | text-decoration: line-through; |
| | color: var(--text-light); |
| | } |
| | |
| | |
| | .delete-btn { |
| | background: none; |
| | border: none; |
| | color: #cbd5e1; |
| | cursor: pointer; |
| | padding: 5px; |
| | border-radius: 8px; |
| | transition: var(--transition); |
| | opacity: 0; |
| | } |
| | |
| | .task-item:hover .delete-btn { |
| | opacity: 1; |
| | } |
| | |
| | .delete-btn:hover { |
| | color: var(--danger-color); |
| | background: #fee2e2; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | .empty-state { |
| | text-align: center; |
| | padding: 2rem 0; |
| | color: var(--text-light); |
| | display: none; |
| | } |
| | |
| | .empty-state svg { |
| | width: 80px; |
| | height: 80px; |
| | margin-bottom: 1rem; |
| | opacity: 0.5; |
| | fill: #e2e8f0; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | @keyframes slideIn { |
| | from { opacity: 0; transform: translateY(10px); } |
| | to { opacity: 1; transform: translateY(0); } |
| | } |
| | |
| | @keyframes shake { |
| | 0%, 100% { transform: translateX(0); } |
| | 25% { transform: translateX(-5px); } |
| | 75% { transform: translateX(5px); } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | @media (max-width: 480px) { |
| | .app-container { |
| | padding: 1.5rem; |
| | height: 100vh; |
| | max-height: 100vh; |
| | border-radius: 0; |
| | box-shadow: none; |
| | display: flex; |
| | flex-direction: column; |
| | } |
| | |
| | ul { |
| | flex-grow: 1; |
| | } |
| | |
| | .delete-btn { |
| | opacity: 1; |
| | } |
| | } |
| | </style> |
| | </head> |
| | <body> |
| |
|
| | <div class="app-container"> |
| | <header> |
| | <h1>مهامي اليومية</h1> |
| | <p class="subtitle">نظم وقتك، حقق أهدافك</p> |
| | |
| | |
| | <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> |
| | Built with anycoder |
| | </a> |
| | </header> |
| |
|
| | <section class="input-group"> |
| | <input type="text" id="taskInput" placeholder="أضف مهمة جديدة..." autocomplete="off"> |
| | <button class="add-btn" id="addBtn">+</button> |
| | </section> |
| |
|
| | <div class="tasks-header"> |
| | <span class="tasks-count" id="tasksCount">0 مهام متبقية</span> |
| | <button class="clear-btn" id="clearBtn">مسح الكل</button> |
| | </div> |
| |
|
| | <ul id="taskList"> |
| | |
| | </ul> |
| |
|
| | <div class="empty-state" id="emptyState"> |
| | <svg viewBox="0 0 24 24"> |
| | <path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/> |
| | </svg> |
| | <p>لا توجد مهام حالياً. استمتع بوقتك!</p> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const taskInput = document.getElementById('taskInput'); |
| | const addBtn = document.getElementById('addBtn'); |
| | const taskList = document.getElementById('taskList'); |
| | const tasksCount = document.getElementById('tasksCount'); |
| | const emptyState = document.getElementById('emptyState'); |
| | const clearBtn = document.getElementById('clearBtn'); |
| | |
| | |
| | let tasks = JSON.parse(localStorage.getItem('myTasks')) || []; |
| | |
| | |
| | function saveTasks() { |
| | localStorage.setItem('myTasks', JSON.stringify(tasks)); |
| | renderTasks(); |
| | } |
| | |
| | |
| | function addTask() { |
| | const text = taskInput.value.trim(); |
| | |
| | if (text === '') { |
| | |
| | taskInput.classList.add('error'); |
| | setTimeout(() => taskInput.classList.remove('error'), 500); |
| | return; |
| | } |
| | |
| | const newTask = { |
| | id: Date.now(), |
| | text: text, |
| | completed: false |
| | }; |
| | |
| | tasks.unshift(newTask); |
| | taskInput.value = ''; |
| | saveTasks(); |
| | } |
| | |
| | |
| | function deleteTask(id) { |
| | tasks = tasks.filter(task => task.id !== id); |
| | saveTasks(); |
| | } |
| | |
| | |
| | function toggleTask(id) { |
| | tasks = tasks.map(task => { |
| | if (task.id === id) { |
| | return { ...task, completed: !task.completed }; |
| | } |
| | return task; |
| | }); |
| | saveTasks(); |
| | } |
| | |
| | |
| | function clearAllTasks() { |
| | if(confirm('هل أنت متأكد من حذف جميع المهام؟')) { |
| | tasks = []; |
| | saveTasks(); |
| | } |
| | } |
| | |
| | |
| | function renderTasks() { |
| | taskList.innerHTML = ''; |
| | |
| | |
| | const remainingTasks = tasks.filter(t => !t.completed).length; |
| | tasksCount.textContent = `${remainingTasks} مهام متبقية`; |
| | |
| | |
| | if (tasks.length === 0) { |
| | emptyState.style.display = 'block'; |
| | taskList.style.display = 'none'; |
| | } else { |
| | emptyState.style.display = 'none'; |
| | taskList.style.display = 'block'; |
| | } |
| | |
| | |
| | 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="20" height="20" 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 div = document.createElement('div'); |
| | div.textContent = text; |
| | return div.innerHTML; |
| | } |
| | |
| | |
| | |
| | |
| | addBtn.addEventListener('click', addTask); |
| | |
| | |
| | taskInput.addEventListener('keypress', (e) => { |
| | if (e.key === 'Enter') { |
| | addTask(); |
| | } |
| | }); |
| | |
| | |
| | clearBtn.addEventListener('click', clearAllTasks); |
| | |
| | |
| | renderTasks(); |
| | |
| | </script> |
| | </body> |
| | </html> |