Skip to content

Commit 75b1f1b

Browse files
authored
Merge pull request #75 from Nitanshu12/make-to-do-list-56
Todo-list in Javascript
2 parents 7881f61 + 02b8fd9 commit 75b1f1b

3 files changed

Lines changed: 239 additions & 0 deletions

File tree

javascript/todo-list/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Todo List</title>
7+
<link rel="stylesheet" href="style.css" />
8+
</head>
9+
<body>
10+
<main class="app">
11+
<h1 class="title">Todo List</h1>
12+
13+
<form id="todo-form" class="todo-form" autocomplete="off">
14+
<input id="todo-input" class="todo-input" type="text" placeholder="Add a new task..." aria-label="Todo text" />
15+
<button type="submit" class="add-btn" aria-label="Add todo">Add</button>
16+
</form>
17+
18+
<ul id="todo-list" class="todo-list" aria-live="polite"></ul>
19+
20+
<div class="footer">
21+
<button id="clear-completed" class="clear-btn" type="button">Clear Completed</button>
22+
</div>
23+
</main>
24+
25+
<script src="script.js"></script>
26+
</body>
27+
</html>
28+
29+

javascript/todo-list/script.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
(() => {
2+
const STORAGE_KEY = 'todo.list.items.v1';
3+
4+
/** @type {{ id: string; text: string; completed: boolean }[]} */
5+
let items = [];
6+
7+
const form = document.getElementById('todo-form');
8+
const input = document.getElementById('todo-input');
9+
const list = document.getElementById('todo-list');
10+
const clearCompletedBtn = document.getElementById('clear-completed');
11+
12+
function load() {
13+
try {
14+
const raw = localStorage.getItem(STORAGE_KEY);
15+
items = raw ? JSON.parse(raw) : [];
16+
if (!Array.isArray(items)) items = [];
17+
} catch { items = []; }
18+
}
19+
20+
function save() {
21+
localStorage.setItem(STORAGE_KEY, JSON.stringify(items));
22+
}
23+
24+
function createItem(text) {
25+
return { id: String(Date.now()) + Math.random().toString(36).slice(2), text, completed: false };
26+
}
27+
28+
function render() {
29+
list.innerHTML = '';
30+
for (const item of items) {
31+
const li = document.createElement('li');
32+
li.className = 'todo-item';
33+
li.dataset.id = item.id;
34+
35+
const checkbox = document.createElement('input');
36+
checkbox.type = 'checkbox';
37+
checkbox.className = 'todo-check';
38+
checkbox.checked = item.completed;
39+
40+
const p = document.createElement('p');
41+
p.className = 'todo-text' + (item.completed ? ' completed' : '');
42+
p.textContent = item.text;
43+
44+
const del = document.createElement('button');
45+
del.className = 'delete-btn';
46+
del.type = 'button';
47+
del.textContent = 'Delete';
48+
49+
li.appendChild(checkbox);
50+
li.appendChild(p);
51+
li.appendChild(del);
52+
list.appendChild(li);
53+
}
54+
}
55+
56+
function addItem(text) {
57+
const trimmed = text.trim();
58+
if (!trimmed) return;
59+
items.unshift(createItem(trimmed));
60+
save();
61+
render();
62+
}
63+
64+
function deleteItem(id) {
65+
items = items.filter(i => i.id !== id);
66+
save();
67+
render();
68+
}
69+
70+
function toggleItem(id, completed) {
71+
const item = items.find(i => i.id === id);
72+
if (!item) return;
73+
item.completed = completed;
74+
save();
75+
render();
76+
}
77+
78+
function clearCompleted() {
79+
items = items.filter(i => !i.completed);
80+
save();
81+
render();
82+
}
83+
84+
form.addEventListener('submit', (e) => {
85+
e.preventDefault();
86+
addItem(input.value);
87+
input.value = '';
88+
input.focus();
89+
});
90+
91+
list.addEventListener('click', (e) => {
92+
const target = e.target;
93+
if (!(target instanceof HTMLElement)) return;
94+
const li = target.closest('.todo-item');
95+
if (!li) return;
96+
const id = li.dataset.id;
97+
if (!id) return;
98+
if (target.classList.contains('delete-btn')) {
99+
deleteItem(id);
100+
}
101+
});
102+
103+
list.addEventListener('change', (e) => {
104+
const target = e.target;
105+
if (!(target instanceof HTMLInputElement)) return;
106+
if (!target.classList.contains('todo-check')) return;
107+
const li = target.closest('.todo-item');
108+
if (!li) return;
109+
const id = li.dataset.id;
110+
if (!id) return;
111+
toggleItem(id, target.checked);
112+
});
113+
114+
clearCompletedBtn.addEventListener('click', () => {
115+
clearCompleted();
116+
});
117+
118+
load();
119+
render();
120+
})();
121+
122+

javascript/todo-list/style.css

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
:root {
2+
--bg: #0f172a;
3+
--panel: #111827;
4+
--text: #e5e7eb;
5+
--muted: #9ca3af;
6+
--accent: #22c55e;
7+
--danger: #ef4444;
8+
--border: #1f2937;
9+
}
10+
11+
* { box-sizing: border-box; }
12+
html, body { height: 100%; }
13+
body {
14+
margin: 0;
15+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica Neue, Arial, "Apple Color Emoji", "Segoe UI Emoji";
16+
background: linear-gradient(180deg, #0b1023, #121a36 60%, #0b1023);
17+
color: var(--text);
18+
display: grid;
19+
place-items: center;
20+
}
21+
22+
.app {
23+
width: 100%;
24+
max-width: 720px;
25+
padding: 24px;
26+
}
27+
28+
.title { margin: 0 0 16px; font-weight: 700; letter-spacing: 0.3px; }
29+
30+
.todo-form {
31+
display: grid;
32+
grid-template-columns: 1fr auto;
33+
gap: 12px;
34+
margin-bottom: 16px;
35+
}
36+
37+
.todo-input {
38+
padding: 12px 14px;
39+
background: var(--panel);
40+
border: 1px solid var(--border);
41+
border-radius: 10px;
42+
color: var(--text);
43+
outline: none;
44+
}
45+
.todo-input::placeholder { color: var(--muted); }
46+
47+
.add-btn, .clear-btn {
48+
padding: 12px 16px;
49+
border: 1px solid var(--border);
50+
border-radius: 10px;
51+
background: #0b1324;
52+
color: var(--text);
53+
cursor: pointer;
54+
}
55+
.add-btn:hover { background: #0e172e; }
56+
.clear-btn:hover { background: #0e172e; }
57+
58+
.todo-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
59+
60+
.todo-item {
61+
display: grid;
62+
grid-template-columns: auto 1fr auto;
63+
align-items: center;
64+
gap: 12px;
65+
background: var(--panel);
66+
border: 1px solid var(--border);
67+
border-radius: 12px;
68+
padding: 12px 14px;
69+
}
70+
71+
.todo-check { width: 18px; height: 18px; cursor: pointer; }
72+
73+
.todo-text { margin: 0; }
74+
.todo-text.completed { color: var(--muted); text-decoration: line-through; }
75+
76+
.delete-btn {
77+
background: transparent;
78+
color: var(--danger);
79+
border: 1px solid var(--border);
80+
padding: 8px 10px;
81+
border-radius: 8px;
82+
cursor: pointer;
83+
}
84+
.delete-btn:hover { background: rgba(239, 68, 68, 0.08); }
85+
86+
.footer { margin-top: 14px; display: flex; justify-content: flex-end; }
87+
88+

0 commit comments

Comments
 (0)