Skip to content

Commit a2db060

Browse files
committed
Added Tailwind CSS to the mix
1 parent 4bff9c0 commit a2db060

File tree

3 files changed

+111
-10
lines changed

3 files changed

+111
-10
lines changed

todo/public/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
-->
2727
<title>React App</title>
2828
</head>
29-
<body>
29+
<body class="bg-blue-50">
3030
<noscript>You need to enable JavaScript to run this app.</noscript>
3131
<div id="root"></div>
3232
<!--

todo/src/App.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import TodoList from "./TodoList"
55

66
function App() {
77
return (
8-
<div className="App">
9-
<h1 className="text-red-400">Hi from Kenny & Proful</h1>
8+
<div className="flex justify-center mt-20">
109
<TodoList />
1110
</div>
1211
)

todo/src/TodoList.tsx

+109-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ function TodoList() {
1616
return initialValue
1717
})
1818

19+
useEffect(
20+
() => window.localStorage.setItem("todos", JSON.stringify(todos)),
21+
[todos]
22+
)
23+
1924
const handleCreateTodo = (todo: string) => {
2025
const oldTodos = [...todos]
2126
oldTodos.push({
@@ -24,15 +29,47 @@ function TodoList() {
2429
isCompleted: false,
2530
})
2631
setTodos(oldTodos)
27-
window.localStorage.setItem("todos", JSON.stringify(oldTodos))
2832
}
2933

34+
const handleDeleteTodo = (todoId: number) => {
35+
let updatedTodos = [...todos]
36+
let selectedTodoIdx = todos.findIndex((todo) => todo.id === todoId)
37+
updatedTodos.splice(selectedTodoIdx, 1)
38+
setTodos(updatedTodos)
39+
}
40+
const handleComplete = (todoId: number) => {
41+
// clone the original array to avoid mutate by reference
42+
let updatedTodos = [...todos]
43+
// find the todo based on todo id
44+
let selectedTodo = todos.find((todo) => todo.id === todoId)
45+
// find the todo index based on todo id
46+
let selectedTodoIdx = todos.findIndex((todo) => todo.id === todoId)
47+
48+
if (selectedTodo) {
49+
updatedTodos[selectedTodoIdx] = {
50+
...selectedTodo,
51+
isCompleted: !selectedTodo.isCompleted,
52+
}
53+
setTodos(updatedTodos)
54+
}
55+
}
3056
return (
31-
<div>
57+
<div className="bg-white shadow-md w-2/5 p-8 rounded-xl">
58+
<h1 className="text-2xl font-bold">Todo List</h1>
59+
<hr className="mt-2" />
3260
<TodoNew createTodo={handleCreateTodo} />
33-
<div>
61+
<div className="mt-4">
62+
You have {todos.filter((it) => it.isCompleted === false).length} pending
63+
task(s)
64+
</div>
65+
<div className="mt-4">
3466
{todos.map((it) => (
35-
<TodoItem key={it.id} item={it} />
67+
<TodoItem
68+
key={it.id}
69+
item={it}
70+
deleteTodo={handleDeleteTodo}
71+
complete={handleComplete}
72+
/>
3673
))}
3774
</div>
3875
</div>
@@ -49,19 +86,84 @@ function TodoNew({ createTodo }: TodoNewProps) {
4986
setTodo("")
5087
}
5188
return (
52-
<form onSubmit={onSubmit}>
89+
<form onSubmit={onSubmit} className="relative">
90+
<span className="absolute top-5 right-3">
91+
<PlusCircle />
92+
</span>
5393
<input
5494
type="text"
5595
placeholder="Add new task"
5696
value={todo}
97+
className="bg-blue-50 p-3 rounded-full mt-2 w-full"
5798
onChange={(e) => setTodo(e.target.value)}
5899
/>
59100
</form>
60101
)
61102
}
103+
interface TodoItemProps {
104+
item: Todo
105+
deleteTodo: (id: number) => void
106+
complete: (id: number) => void
107+
}
108+
function TodoItem({ item, deleteTodo, complete }: TodoItemProps) {
109+
return (
110+
<div className="bg-blue-50 px-4 py-2 rounded-full shadow mb-4 relative">
111+
<button
112+
type="button"
113+
onClick={() => deleteTodo(item.id)}
114+
className="absolute top-3 right-3"
115+
>
116+
<Delete />
117+
</button>
118+
<input
119+
type="checkbox"
120+
className="h-4 w-4 mr-2 -mt-2"
121+
checked={item.isCompleted}
122+
onChange={() => complete(item.id)}
123+
/>
124+
<span className={item.isCompleted ? "line-through" : ""}>
125+
{item.text}
126+
</span>
127+
</div>
128+
)
129+
}
62130

63-
function TodoItem({ item }: { item: Todo }) {
64-
return <div>{item.text}</div>
131+
function PlusCircle() {
132+
return (
133+
<svg
134+
xmlns="http://www.w3.org/2000/svg"
135+
className="h-6 w-6"
136+
fill="none"
137+
viewBox="0 0 24 24"
138+
stroke="#4B5563"
139+
>
140+
<path
141+
strokeLinecap="round"
142+
strokeLinejoin="round"
143+
strokeWidth={2}
144+
d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"
145+
/>
146+
</svg>
147+
)
148+
}
149+
150+
function Delete() {
151+
return (
152+
<svg
153+
xmlns="http://www.w3.org/2000/svg"
154+
className="h-4 w-4"
155+
fill="none"
156+
viewBox="0 0 24 24"
157+
stroke="#4B5563"
158+
>
159+
<path
160+
strokeLinecap="round"
161+
strokeLinejoin="round"
162+
strokeWidth={2}
163+
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
164+
/>
165+
</svg>
166+
)
65167
}
66168

67169
export default TodoList

0 commit comments

Comments
 (0)