anycoder-36d69f42 / index.html
akhaliq's picture
akhaliq HF Staff
Upload folder using huggingface_hub
3650441 verified
<!DOCTYPE html>
<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>