Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Reminders - Apple Style Todo</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #007AFF; | |
| --primary-dark: #0051D5; | |
| --primary-light: #5AC8FA; | |
| --secondary: #FF3B30; | |
| --success: #34C759; | |
| --warning: #FF9500; | |
| --info: #5AC8FA; | |
| --dark: #1C1C1E; | |
| --light: #F2F2F7; | |
| --gray: #8E8E93; | |
| --gray-light: #E5E5EA; | |
| --white: #FFFFFF; | |
| --system-gray: #C7C7CC; | |
| --system-gray2: #AEAEB2; | |
| --system-gray3: #8E8E93; | |
| --system-gray4: #636366; | |
| --system-gray5: #48484A; | |
| --system-gray6: #363638; | |
| --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12); | |
| --shadow: 0 4px 6px rgba(0, 0, 0, 0.07); | |
| --shadow-lg: 0 10px 40px rgba(0, 0, 0, 0.12); | |
| --transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); | |
| --radius: 20px; | |
| --radius-sm: 12px; | |
| --radius-xs: 8px; | |
| } | |
| [data-theme="dark"] { | |
| --light: #000000; | |
| --gray-light: #1C1C1E; | |
| --white: #1C1C1E; | |
| --dark: #FFFFFF; | |
| --gray: #AEAEB2; | |
| --system-gray: #48484A; | |
| --system-gray2: #636366; | |
| --system-gray3: #8E8E93; | |
| --system-gray4: #AEAEB2; | |
| --system-gray5: #C7C7CC; | |
| --system-gray6: #D1D1D6; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 20px; | |
| transition: var(--transition); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| [data-theme="dark"] body { | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| } | |
| .background-gradient { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), | |
| radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%), | |
| radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.2) 0%, transparent 50%); | |
| z-index: -1; | |
| } | |
| .container { | |
| width: 100%; | |
| max-width: 920px; | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border-radius: var(--radius); | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); | |
| overflow: hidden; | |
| animation: slideUp 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| [data-theme="dark"] .container { | |
| background: rgba(28, 28, 30, 0.95); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| @keyframes slideUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(40px) scale(0.95); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| } | |
| } | |
| header { | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); | |
| color: var(--white); | |
| padding: 32px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| header::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 100%); | |
| pointer-events: none; | |
| } | |
| .header-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 24px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| h1 { | |
| font-size: 2.2em; | |
| font-weight: 700; | |
| letter-spacing: -0.5px; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .logo { | |
| width: 48px; | |
| height: 48px; | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: var(--radius-sm); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.4em; | |
| backdrop-filter: blur(10px); | |
| } | |
| .header-actions { | |
| display: flex; | |
| gap: 12px; | |
| } | |
| .theme-toggle { | |
| background: rgba(255, 255, 255, 0.2); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| color: var(--white); | |
| width: 44px; | |
| height: 44px; | |
| border-radius: var(--radius-xs); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: var(--transition); | |
| font-size: 1.1em; | |
| } | |
| .theme-toggle:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: scale(1.05); | |
| } | |
| .theme-toggle:active { | |
| transform: scale(0.95); | |
| } | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); | |
| gap: 16px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .stat-card { | |
| background: rgba(255, 255, 255, 0.15); | |
| backdrop-filter: blur(10px); | |
| padding: 18px; | |
| border-radius: var(--radius-sm); | |
| text-align: center; | |
| transition: var(--transition); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .stat-card:hover { | |
| background: rgba(255, 255, 255, 0.25); | |
| transform: translateY(-2px); | |
| } | |
| .stat-value { | |
| font-size: 2em; | |
| font-weight: 600; | |
| margin-bottom: 4px; | |
| letter-spacing: -0.5px; | |
| } | |
| .stat-label { | |
| font-size: 0.85em; | |
| opacity: 0.9; | |
| font-weight: 500; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| .progress-bar { | |
| height: 4px; | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| margin-top: 24px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--success) 0%, #30D158 100%); | |
| transition: width 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94); | |
| border-radius: 2px; | |
| box-shadow: 0 0 10px rgba(52, 199, 89, 0.5); | |
| } | |
| .add-todo-section { | |
| padding: 32px; | |
| background: var(--white); | |
| border-bottom: 1px solid var(--gray-light); | |
| } | |
| [data-theme="dark"] .add-todo-section { | |
| background: var(--white); | |
| } | |
| .add-todo-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| } | |
| .input-group { | |
| display: flex; | |
| gap: 12px; | |
| flex-wrap: wrap; | |
| } | |
| .todo-input { | |
| flex: 1; | |
| min-width: 240px; | |
| padding: 14px 18px; | |
| border: 1px solid var(--gray-light); | |
| border-radius: var(--radius-sm); | |
| font-size: 1em; | |
| transition: var(--transition); | |
| background: var(--light); | |
| color: var(--dark); | |
| font-weight: 500; | |
| } | |
| .todo-input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| background: var(--white); | |
| box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1); | |
| } | |
| .select-input { | |
| padding: 14px 18px; | |
| border: 1px solid var(--gray-light); | |
| border-radius: var(--radius-sm); | |
| font-size: 1em; | |
| background: var(--light); | |
| color: var(--dark); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 500; | |
| min-width: 140px; | |
| } | |
| .select-input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| background: var(--white); | |
| } | |
| .date-input { | |
| padding: 14px 18px; | |
| border: 1px solid var(--gray-light); | |
| border-radius: var(--radius-sm); | |
| font-size: 1em; | |
| background: var(--light); | |
| color: var(--dark); | |
| transition: var(--transition); | |
| font-weight: 500; | |
| } | |
| .add-btn { | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); | |
| color: var(--white); | |
| border: none; | |
| padding: 14px 28px; | |
| border-radius: var(--radius-sm); | |
| font-size: 1em; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| box-shadow: var(--shadow); | |
| } | |
| .add-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 20px rgba(0, 122, 255, 0.3); | |
| } | |
| .add-btn:active { | |
| transform: translateY(0); | |
| } | |
| .controls-section { | |
| padding: 24px 32px; | |
| background: var(--white); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 16px; | |
| border-bottom: 1px solid var(--gray-light); | |
| } | |
| [data-theme="dark"] .controls-section { | |
| background: var(--white); | |
| } | |
| .search-box { | |
| position: relative; | |
| flex: 1; | |
| max-width: 320px; | |
| } | |
| .search-input { | |
| width: 100%; | |
| padding: 12px 16px 12px 44px; | |
| border: 1px solid var(--gray-light); | |
| border-radius: var(--radius-sm); | |
| font-size: 0.95em; | |
| background: var(--light); | |
| color: var(--dark); | |
| transition: var(--transition); | |
| font-weight: 500; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| border-color: var(--primary); | |
| background: var(--white); | |
| } | |
| .search-icon { | |
| position: absolute; | |
| left: 16px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| color: var(--gray); | |
| } | |
| .filter-tabs { | |
| display: flex; | |
| gap: 4px; | |
| background: var(--light); | |
| padding: 4px; | |
| border-radius: var(--radius-sm); | |
| } | |
| .filter-tab { | |
| padding: 10px 20px; | |
| border: none; | |
| background: transparent; | |
| color: var(--gray); | |
| font-size: 0.95em; | |
| font-weight: 500; | |
| cursor: pointer; | |
| border-radius: var(--radius-xs); | |
| transition: var(--transition); | |
| } | |
| .filter-tab.active { | |
| background: var(--white); | |
| color: var(--primary); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .clear-btn { | |
| background: var(--secondary); | |
| color: var(--white); | |
| border: none; | |
| padding: 12px 20px; | |
| border-radius: var(--radius-sm); | |
| font-size: 0.95em; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .clear-btn:hover { | |
| background: #D70015; | |
| transform: translateY(-1px); | |
| } | |
| .todos-section { | |
| padding: 32px; | |
| min-height: 300px; | |
| background: var(--white); | |
| } | |
| [data-theme="dark"] .todos-section { | |
| background: var(--white); | |
| } | |
| .todos-list { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .todo-item { | |
| background: var(--light); | |
| border: 1px solid var(--gray-light); | |
| border-radius: var(--radius-sm); | |
| padding: 16px; | |
| display: flex; | |
| align-items: center; | |
| gap: 14px; | |
| transition: var(--transition); | |
| cursor: move; | |
| animation: fadeIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .todo-item:hover { | |
| border-color: var(--primary); | |
| box-shadow: var(--shadow); | |
| transform: translateX(4px); | |
| } | |
| .todo-item.dragging { | |
| opacity: 0.5; | |
| transform: scale(1.02); | |
| } | |
| .todo-item.completed { | |
| opacity: 0.6; | |
| background: var(--gray-light); | |
| } | |
| .todo-item.completed .todo-text { | |
| text-decoration: line-through; | |
| color: var(--gray); | |
| } | |
| .todo-checkbox { | |
| width: 24px; | |
| height: 24px; | |
| border: 2px solid var(--system-gray3); | |
| border-radius: 50%; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: var(--transition); | |
| flex-shrink: 0; | |
| background: var(--white); | |
| } | |
| .todo-checkbox:hover { | |
| border-color: var(--primary); | |
| background: rgba(0, 122, 255, 0.05); | |
| } | |
| .todo-checkbox.checked { | |
| background: var(--success); | |
| border-color: var(--success); | |
| } | |
| .todo-checkbox.checked::after { | |
| content: '✓'; | |
| color: var(--white); | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| .todo-content { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .todo-text { | |
| font-size: 1em; | |
| color: var(--dark); | |
| word-break: break-word; | |
| font-weight: 500; | |
| line-height: 1.4; | |
| } | |
| .todo-meta { | |
| display: flex; | |
| gap: 10px; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| } | |
| .todo-category, | |
| .todo-priority, | |
| .todo-date { | |
| font-size: 0.82em; | |
| padding: 5px 12px; | |
| border-radius: 20px; | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| font-weight: 600; | |
| } | |
| .category-work { | |
| background: rgba(0, 122, 255, 0.1); | |
| color: var(--primary); | |
| } | |
| .category-personal { | |
| background: rgba(255, 59, 48, 0.1); | |
| color: var(--secondary); | |
| } | |
| .category-shopping { | |
| background: rgba(255, 149, 0, 0.1); | |
| color: var(--warning); | |
| } | |
| .category-health { | |
| background: rgba(52, 199, 89, 0.1); | |
| color: var(--success); | |
| } | |
| .priority-high { | |
| background: rgba(255, 59, 48, 0.1); | |
| color: var(--secondary); | |
| } | |
| .priority-medium { | |
| background: rgba(255, 149, 0, 0.1); | |
| color: var(--warning); | |
| } | |
| .priority-low { | |
| background: rgba(142, 142, 147, 0.1); | |
| color: var(--gray); | |
| } | |
| .todo-date { | |
| background: rgba(90, 200, 250, 0.1); | |
| color: var(--info); | |
| } | |
| .todo-actions { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .action-btn { | |
| width: 36px; | |
| height: 36px; | |
| border: 1px solid var(--gray-light); | |
| background: var(--white); | |
| color: var(--gray); | |
| border-radius: var(--radius-xs); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: var(--transition); | |
| font-size: 0.9em; | |
| } | |
| .action-btn:hover { | |
| background: var(--primary); | |
| color: var(--white); | |
| border-color: var(--primary); | |
| transform: scale(1.05); | |
| } | |
| .action-btn.delete:hover { | |
| background: var(--secondary); | |
| border-color: var(--secondary); | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 80px 20px; | |
| color: var(--gray); | |
| } | |
| .empty-icon { | |
| font-size: 4.5em; | |
| margin-bottom: 24px; | |
| opacity: 0.3; | |
| color: var(--system-gray3); | |
| } | |
| .empty-text { | |
| font-size: 1.3em; | |
| margin-bottom: 8px; | |
| font-weight: 600; | |
| color: var(--dark); | |
| } | |
| [data-theme="dark"] .empty-text { | |
| color: var(--white); | |
| } | |
| .empty-subtext { | |
| font-size: 0.95em; | |
| opacity: 0.7; | |
| } | |
| .edit-modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.4); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| z-index: 1000; | |
| align-items: center; | |
| justify-content: center; | |
| animation: fadeIn 0.3s ease-out; | |
| } | |
| .edit-modal.active { | |
| display: flex; | |
| } | |
| .modal-content { | |
| background: var(--white); | |
| border-radius: var(--radius); | |
| padding: 32px; | |
| width: 90%; | |
| max-width: 520px; | |
| animation: modalSlide 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); | |
| } | |
| @keyframes modalSlide { | |
| from { | |
| opacity: 0; | |
| transform: translateY(30px) scale(0.95); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| } | |
| } | |
| .modal-header { | |
| margin-bottom: 24px; | |
| } | |
| .modal-title { | |
| font-size: 1.6em; | |
| color: var(--dark); | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| font-weight: 600; | |
| } | |
| .modal-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| } | |
| .modal-actions { | |
| display: flex; | |
| gap: 12px; | |
| justify-content: flex-end; | |
| margin-top: 24px; | |
| } | |
| .modal-btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: var(--radius-sm); | |
| font-size: 1em; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .modal-btn.cancel { | |
| background: var(--light); | |
| color: var(--dark); | |
| } | |
| .modal-btn.save { | |
| background: var(--primary); | |
| color: var(--white); | |
| } | |
| .modal-btn:hover { | |
| transform: translateY(-1px); | |
| } | |
| footer { | |
| padding: 24px; | |
| text-align: center; | |
| background: var(--light); | |
| border-top: 1px solid var(--gray-light); | |
| } | |
| .footer-link { | |
| color: var(--primary); | |
| text-decoration: none; | |
| font-weight: 600; | |
| transition: var(--transition); | |
| } | |
| .footer-link:hover { | |
| color: var(--primary-dark); | |
| text-decoration: underline; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| border-radius: var(--radius-sm); | |
| } | |
| header { | |
| padding: 24px; | |
| } | |
| h1 { | |
| font-size: 1.8em; | |
| } | |
| .stats { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| .add-todo-section { | |
| padding: 24px; | |
| } | |
| .input-group { | |
| flex-direction: column; | |
| } | |
| .controls-section { | |
| padding: 20px 24px; | |
| } | |
| .filter-tabs { | |
| order: 3; | |
| width: 100%; | |
| } | |
| .filter-tab { | |
| flex: 1; | |
| text-align: center; | |
| } | |
| .todos-section { | |
| padding: 24px; | |
| } | |
| .todo-item { | |
| padding: 14px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| body { | |
| padding: 12px; | |
| } | |
| .header-content { | |
| flex-direction: column; | |
| gap: 16px; | |
| align-items: flex-start; | |
| } | |
| .stats { | |
| grid-template-columns: 1fr; | |
| } | |
| .controls-section { | |
| flex-direction: column; | |
| align-items: stretch; | |
| } | |
| .search-box { | |
| max-width: 100%; | |
| } | |
| } | |
| .notification { | |
| position: fixed; | |
| bottom: 24px; | |
| right: 24px; | |
| background: var(--success); | |
| color: var(--white); | |
| padding: 16px 24px; | |
| border-radius: var(--radius-sm); | |
| box-shadow: var(--shadow-lg); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| transform: translateX(400px); | |
| transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| z-index: 2000; | |
| font-weight: 600; | |
| } | |
| .notification.show { | |
| transform: translateX(0); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="background-gradient"></div> | |
| <div class="container"> | |
| <header> | |
| <div class="header-content"> | |
| <h1> | |
| <div class="logo"> | |
| <i class="fas fa-check-circle"></i> | |
| </div> | |
| Reminders | |
| </h1> | |
| <div class="header-actions"> | |
| <button class="theme-toggle" onclick="toggleTheme()"> | |
| <i class="fas fa-moon" id="theme-icon"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="stats"> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="total-tasks">0</div> | |
| <div class="stat-label">Total</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="completed-tasks">0</div> | |
| <div class="stat-label">Done</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="pending-tasks">0</div> | |
| <div class="stat-label">Pending</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-value" id="completion-rate">0%</div> | |
| <div class="stat-label">Progress</div> | |
| </div> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progress-fill"></div> | |
| </div> | |
| </header> | |
| <section class="add-todo-section"> | |
| <form class="add-todo-form" onsubmit="addTodo(event)"> | |
| <div class="input-group"> | |
| <input type="text" class="todo-input" id="todo-input" placeholder="New Reminder..." required> | |
| <select class="select-input" id="category-select"> | |
| <option value="work">Work</option> | |
| <option value="personal">Personal</option> | |
| <option value="shopping">Shopping</option> | |
| <option value="health">Health</option> | |
| </select> | |
| <select class="select-input" id="priority-select"> | |
| <option value="low">Low</option> | |
| <option value="medium">Medium</option> | |
| <option value="high">High</option> | |
| </select> | |
| <input type="date" class="date-input" id="due-date"> | |
| <button type="submit" class="add-btn"> | |
| <i class="fas fa-plus"></i> | |
| Add | |
| </button> | |
| </div> | |
| </form> | |
| </section> | |
| <section class="controls-section"> | |
| <div class="search-box"> | |
| <i class="fas fa-search search-icon"></i> | |
| <input type="text" class="search-input" id="search-input" placeholder="Search reminders..." oninput="searchTodos()"> | |
| </div> | |
| <div class="filter-tabs"> | |
| <button class="filter-tab active" onclick="filterTodos('all')">All</button> | |
| <button class="filter-tab" onclick="filterTodos('active')">Active</button> | |
| <button class="filter-tab" onclick="filterTodos('completed')">Done</button> | |
| </div> | |
| <button class="clear-btn" onclick="clearCompleted()"> | |
| <i class="fas fa-trash"></i> | |
| Clear Done | |
| </button> | |
| </section> | |
| <main class="todos-section"> | |
| <div class="todos-list" id="todos-list"> | |
| <div class="empty-state"> | |
| <div class="empty-icon"> | |
| <i class="fas fa-clipboard-list"></i> | |
| </div> | |
| <div class="empty-text">No reminders</div> | |
| <div class="empty-subtext">Create your first reminder to get started!</div> | |
| </div> | |
| </div> | |
| </main> | |
| <footer> | |
| <p>Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" | |
| class="footer-link">anycoder</a></p> | |
| </footer> | |
| </div> | |
| <div class="edit-modal" id="edit-modal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h2 class="modal-title"> | |
| <i class="fas fa-edit"></i> | |
| Edit Reminder | |
| </h2> | |
| </div> | |
| <form class="modal-form" onsubmit="saveEdit(event)"> | |
| <input type="text" class="todo-input" id="edit-input" required> | |
| <select class="select-input" id="edit-category"> | |
| <option value="work">Work</option> | |
| <option value="personal">Personal</option> | |
| <option value="shopping">Shopping</option> | |
| <option value="health">Health</option> | |
| </select> | |
| <select class="select-input" id="edit-priority"> | |
| <option value="low">Low</option> | |
| <option value="medium">Medium</option> | |
| <option value="high">High</option> | |
| </select> | |
| <input type="date" class="date-input" id="edit-date"> | |
| <div class="modal-actions"> | |
| <button type="button" class="modal-btn cancel" onclick="closeEditModal()">Cancel</button> | |
| <button type="submit" class="modal-btn save">Save</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="notification" id="notification"> | |
| <i class="fas fa-check-circle"></i> | |
| <span id="notification-text">Reminder added!</span> | |
| </div> | |
| <script> | |
| let todos = JSON.parse(localStorage.getItem('todos')) || []; | |
| let currentFilter = 'all'; | |
| let editingId = null; | |
| let draggedItem = null; | |
| // Initialize app | |
| document.addEventListener('DOMContentLoaded', () => { | |
| loadTheme(); | |
| renderTodos(); | |
| updateStats(); | |
| setMinDate(); | |
| }); | |
| // Theme management | |
| function toggleTheme() { | |
| const html = document.documentElement; | |
| const themeIcon = document.getElementById('theme-icon'); | |
| if (html.getAttribute('data-theme') === 'dark') { | |
| html.removeAttribute('data-theme'); | |
| themeIcon.className = 'fas fa-moon'; | |
| localStorage.setItem('theme', 'light'); | |
| } else { | |
| html.setAttribute('data-theme', 'dark'); | |
| themeIcon.className = 'fas fa-sun'; | |
| localStorage.setItem('theme', 'dark'); | |
| } | |
| } | |
| function loadTheme() { | |
| const theme = localStorage.getItem('theme'); | |
| const themeIcon = document.getElementById('theme-icon'); | |
| if (theme === 'dark') { | |
| document.documentElement.setAttribute('data-theme', 'dark'); | |
| themeIcon.className = 'fas fa-sun'; | |
| } | |
| } | |
| // Set minimum date to today | |
| function setMinDate() { | |
| const today = new Date().toISOString().split('T')[0]; | |
| document.getElementById('due-date').setAttribute('min', today); | |
| document.getElementById('edit-date').setAttribute('min', today); | |
| } | |
| // Add todo | |
| function addTodo(event) { | |
| event.preventDefault(); | |
| const input = document.getElementById('todo-input'); | |
| const category = document.getElementById('category-select').value; | |
| const priority = document.getElementById('priority-select').value; | |
| const dueDate = document.getElementById('due-date').value; | |
| const todo = { | |
| id: Date.now(), | |
| text: input.value.trim(), | |
| completed: false, | |
| category, | |
| priority, | |
| dueDate, | |
| createdAt: new Date().toISOString() | |
| }; | |
| todos.unshift(todo); | |
| saveTodos(); | |
| renderTodos(); | |
| updateStats(); | |
| // Reset form | |
| input.value = ''; | |
| document.getElementById('due-date').value = ''; | |
| showNotification('Reminder added!'); | |
| } | |
| // Toggle todo completion | |
| function toggleTodo(id) { | |
| const todo = todos.find(t => t.id === id); | |
| if (todo) { | |
| todo.completed = !todo.completed; | |
| saveTodos(); | |
| renderTodos(); | |
| updateStats(); | |
| if (todo.completed) { | |
| showNotification('Great job! Task completed!'); | |
| } | |
| } | |
| } | |
| // Delete todo | |
| function deleteTodo(id) { | |
| todos = todos.filter(t => t.id !== id); | |
| saveTodos(); | |
| renderTodos(); | |
| updateStats(); | |
| showNotification('Reminder deleted'); | |
| } | |
| // Edit todo | |
| function editTodo(id) { | |
| const todo = todos.find(t => t.id === id); | |
| if (todo) { | |
| editingId = id; | |
| document.getElementById('edit-input').value = todo.text; | |
| document.getElementById('edit-category').value = todo.category; | |
| document.getElementById('edit-priority').value = todo.priority; | |
| document.getElementById('edit-date').value = todo.dueDate; | |
| document.getElementById('edit-modal').classList.add('active'); | |
| } | |
| } | |
| // Save edit | |
| function saveEdit(event) { | |
| event.preventDefault(); | |
| const todo = todos.find(t => t.id === editingId); | |
| if (todo) { | |
| todo.text = document.getElementById('edit-input').value.trim(); | |
| todo.category = document.getElementById('edit-category').value; | |
| todo.priority = document.getElementById('edit-priority').value; | |
| todo.dueDate = document.getElementById('edit-date').value; | |
| saveTodos(); | |
| renderTodos(); | |
| updateStats(); | |
| closeEditModal(); | |
| showNotification('Reminder updated!'); | |
| } | |
| } | |
| // Close edit modal | |
| function closeEditModal() { | |
| document.getElementById('edit-modal').classList.remove('active'); | |
| editingId = null; | |
| } | |
| // Filter todos | |
| function filterTodos(filter) { | |
| currentFilter = filter; | |
| // Update active tab | |
| document.querySelectorAll('.filter-tab').forEach(tab => { | |
| tab.classList.remove('active'); | |
| }); | |
| event.target.classList.add('active'); | |
| renderTodos(); | |
| } | |
| // Search todos | |
| function searchTodos() { | |
| renderTodos(); | |
| } | |
| // Clear completed todos | |
| function clearCompleted() { | |
| const completedCount = todos.filter(t => t.completed).length; | |
| if (completedCount > 0) { | |
| if (confirm(`Delete ${completedCount} completed reminder(s)?`)) { | |
| todos = todos.filter(t => !t.completed); | |
| saveTodos(); | |
| renderTodos(); | |
| updateStats(); | |
| showNotification('Completed reminders cleared'); | |
| } | |
| } else { | |
| showNotification('No completed reminders to clear'); | |
| } | |
| } | |
| // Render todos | |
| function renderTodos() { | |
| const list = document.getElementById('todos-list'); | |
| const searchTerm = document.getElementById('search-input').value.toLowerCase(); | |
| let filteredTodos = todos; | |
| // Apply filter | |
| if (currentFilter === 'active') { | |
| filteredTodos = filteredTodos.filter(t => !t.completed); | |
| } else if (currentFilter === 'completed') { | |
| filteredTodos = filteredTodos.filter(t => t.completed); | |
| } | |
| // Apply search | |
| if (searchTerm) { | |
| filteredTodos = filteredTodos.filter(t => | |
| t.text.toLowerCase().includes(searchTerm) | |
| ); | |
| } | |
| if (filteredTodos.length === 0) { | |
| list.innerHTML = ` | |
| <div class="empty-state"> | |
| <div class="empty-icon"> | |
| <i class="fas fa-clipboard-list"></i> | |
| </div> | |
| <div class="empty-text">No reminders found</div> | |
| <div class="empty-subtext"> | |
| ${searchTerm ? 'Try a different search term' : 'Create a new reminder to get started!'} | |
| </div> | |
| </div> | |
| `; | |
| return; | |
| } | |
| list.innerHTML = filteredTodos.map(todo => ` | |
| <div class="todo-item ${todo.completed ? 'completed' : ''}" | |
| draggable="true" | |
| ondragstart="handleDragStart(event, ${todo.id})" | |
| ondragover="handleDragOver(event)" | |
| ondrop="handleDrop(event, ${todo.id})" | |
| ondragend="handleDragEnd(event)"> | |
| <div class="todo-checkbox ${todo.completed ? 'checked' : ''}" | |
| onclick="toggleTodo(${todo.id})"></div> | |
| <div class="todo-content"> | |
| <div class="todo-text">${escapeHtml(todo.text)}</div> | |
| <div class="todo-meta"> | |
| <span class="todo-category category-${todo.category}"> | |
| <i class="fas fa-tag"></i> | |
| ${todo.category} | |
| </span> | |
| <span class="todo-priority priority-${todo.priority}"> | |
| <i class="fas fa-flag"></i> | |
| ${todo.priority} | |
| </span> | |
| ${todo.dueDate ? ` | |
| <span class="todo-date"> | |
| <i class="fas fa-calendar"></i> | |
| ${formatDate(todo.dueDate)} | |
| </span> | |
| ` : ''} | |
| </div> | |
| </div> | |
| <div class="todo-actions"> | |
| <button class="action-btn" onclick="editTodo(${todo.id})"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="action-btn delete" onclick="deleteTodo(${todo.id})"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| // Drag and drop | |
| function handleDragStart(event, id) { | |
| draggedItem = id; | |
| event.target.classList.add('dragging'); | |
| } | |
| function handleDragOver(event) { | |
| event.preventDefault(); | |
| } | |
| function handleDrop(event, targetId) { | |
| event.preventDefault(); | |
| if (draggedItem !== targetId) { | |
| const draggedIndex = todos.findIndex(t => t.id === draggedItem); | |
| const targetIndex = todos.findIndex(t => t.id === targetId); | |
| if (draggedIndex !== -1 && targetIndex !== -1) { | |
| const [removed] = todos.splice(draggedIndex, 1); | |
| todos.splice(targetIndex, 0, removed); | |
| saveTodos(); | |
| renderTodos(); | |
| } | |
| } | |
| } | |
| function handleDragEnd(event) { | |
| event.target.classList.remove('dragging'); | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| const total = todos.length; | |
| const completed = todos.filter(t => t.completed).length; | |
| const pending = total - completed; | |
| const rate = total > 0 ? Math.round((completed / total) * 100) : 0; | |
| document.getElementById('total-tasks').textContent = total; | |
| document.getElementById('completed-tasks').textContent = completed; | |
| document.getElementById('pending-tasks').textContent = pending; | |
| document.getElementById('completion-rate').textContent = rate + '%'; | |
| document.getElementById('progress-fill').style.width = rate + '%'; | |
| } | |
| // Save to localStorage | |
| function saveTodos() { | |
| localStorage.setItem('todos', JSON.stringify(todos)); | |
| } | |
| // Show notification | |
| function showNotification(message) { | |
| const notification = document.getElementById('notification'); | |
| const text = document.getElementById('notification-text'); | |
| text.textContent = message; | |
| notification.classList.add('show'); | |
| setTimeout(() => { | |
| notification.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // Utility functions | |
| function escapeHtml(text) { | |
| const div = document.createElement('div'); | |
| div.textContent = text; | |
| return div.innerHTML; | |
| } | |
| function formatDate(dateString) { | |
| const date = new Date(dateString); | |
| const today = new Date(); | |
| const tomorrow = new Date(today); | |
| tomorrow.setDate(tomorrow.getDate() + 1); | |
| if (date.toDateString() === today.toDateString()) { | |
| return 'Today'; | |
| } else if (date.toDateString() === tomorrow.toDateString()) { | |
| return 'Tomorrow'; | |
| } else { | |
| return date.toLocaleDateString('en-US', { | |
| month: 'short', | |
| day: 'numeric', | |
| year: date.getFullYear() !== today.getFullYear() ? 'numeric' : undefined | |
| }); | |
| } | |
| } | |
| // Close modal on escape key | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'Escape') { | |
| closeEditModal(); | |
| } | |
| }); | |
| // Close modal on outside click | |
| document.getElementById('edit-modal').addEventListener('click', (e) => { | |
| if (e.target.id === 'edit-modal') { | |
| closeEditModal(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |