Skip to content

Commit 857b23f

Browse files
Add create, toggle and delete task
1 parent 193702a commit 857b23f

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

src/App.css

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
* {
2+
padding: 0;
3+
margin: 0;
4+
box-sizing: border-box;
5+
font-family: 'Courier New', Courier, monospace;
6+
}
7+
8+
body {
9+
display: flex;
10+
justify-content: center;
11+
align-items: center;
12+
min-height: 100vh;
13+
background: linear-gradient(135deg, #f8f9fa 0%, #e0e0e0 100%);
14+
}
15+
16+
.container {
17+
border: 1px solid #d1d5db;
18+
border-radius: 1rem;
19+
box-shadow: 0 4px 24px #b0b0b0;
20+
padding: 1rem;
21+
min-width: 500px;
22+
background: #fff;
23+
}
24+
25+
h1 {
26+
margin-bottom: 1rem;
27+
color: #222;
28+
text-shadow: 0 1px 2px #e0e0e0;
29+
position: relative;
30+
width: max-content;
31+
}
32+
33+
h1::after {
34+
content: "";
35+
display: block;
36+
position: absolute;
37+
left: 0;
38+
bottom: -4px;
39+
width: 100%;
40+
height: 4px;
41+
background: linear-gradient(90deg, #000, #fff);
42+
border-radius: 2px;
43+
}
44+
45+
.input-group {
46+
display: flex;
47+
}
48+
.input-group input {
49+
width: 100%;
50+
line-height: 1.5rem;
51+
border-radius: 1rem 0 0 1rem;
52+
border: 1px solid #bdbdbd;
53+
padding-left: .8rem;
54+
box-shadow: 0 0 8px #e0e0e0;
55+
background: #f5f5f5;
56+
color: #222;
57+
}
58+
.input-group input:focus {
59+
outline: none;
60+
border-color: #888;
61+
background: #fff;
62+
}
63+
64+
.input-group button {
65+
border-radius: 0 1rem 1rem 0;
66+
border: none;
67+
background: #222;
68+
color: #fff;
69+
padding: 5px 16px;
70+
letter-spacing: -1px;
71+
font-size: .9rem;
72+
font-weight: bold;
73+
box-shadow: 0 0 8px #e0e0e0;
74+
transition: background 0.2s, color 0.2s;
75+
}
76+
77+
.input-group button:hover {
78+
background: #444;
79+
cursor: pointer;
80+
}
81+
82+
hr {
83+
margin: 0.5rem 0;
84+
box-shadow: 0 0 8px #e0e0e0;
85+
border: none;
86+
border-top: 1px solid #d1d5db;
87+
}
88+
89+
li {
90+
list-style-type: none;
91+
background: #f8f9fa;
92+
margin-bottom: 0.5rem;
93+
padding: 0.5rem 1rem;
94+
border-radius: 0.5rem;
95+
color: #222;
96+
box-shadow: 0 1px 4px #e0e0e0;
97+
display: flex;
98+
justify-content: space-between;
99+
cursor: pointer;
100+
}
101+
102+
.line-through {
103+
text-decoration: line-through;
104+
}
105+
106+
li button {
107+
border: none;
108+
color: red;
109+
padding: 4px;
110+
cursor: pointer;
111+
}
112+
li button:hover {
113+
border-radius: 4px;
114+
background: rgba(192, 192, 192, 0.548);
115+
}

src/App.tsx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { useReducer, useState } from 'react'
2+
import './App.css'
3+
interface Task {
4+
id?: number;
5+
text: string;
6+
done: boolean;
7+
}
8+
9+
const initialState: Task[] = []
10+
11+
const App = () => {
12+
const [text, setText] = useState('');
13+
const [todos, dispatch] = useReducer(reducer, initialState)
14+
15+
const handleAddTask = () => {
16+
if (!text) return
17+
dispatch({ type: 'ADD_TASK', value: text })
18+
setText('');
19+
}
20+
21+
return (
22+
<div className='container'>
23+
<h1>MyTodo</h1>
24+
25+
<div className="input-group">
26+
<input
27+
type="text"
28+
placeholder='Type your task here...'
29+
value={text}
30+
onChange={e => setText(e.target.value)}
31+
/>
32+
<button onClick={handleAddTask}>Add</button>
33+
</div>
34+
35+
<hr />
36+
37+
<ul>
38+
{todos.map(task => (
39+
<li key={task.id} >
40+
<span
41+
className={ task.done ? 'line-through' : '' }
42+
onClick={() => {
43+
if (task.id)
44+
dispatch({ type: 'TOGGLE_TASK', id: task.id })
45+
}}
46+
>{task.text}</span>
47+
<button
48+
onClick={e => {
49+
e.stopPropagation();
50+
if (task.id)
51+
dispatch({ type: 'DELETE_TASK', id: task.id })
52+
}}
53+
>&times;</button>
54+
</li>
55+
))}
56+
</ul>
57+
58+
</div>
59+
)
60+
}
61+
62+
export default App
63+
64+
type Action =
65+
| { type: 'ADD_TASK', value: string }
66+
| { type: 'DELETE_TASK', id: number }
67+
| { type: 'TOGGLE_TASK', id: number }
68+
69+
const reducer = (state: Task[], action: Action) => {
70+
switch (action.type) {
71+
72+
case 'ADD_TASK':
73+
return [...state, { id: Date.now(), text: action.value, done: false }]
74+
75+
case 'DELETE_TASK':
76+
return state.filter(task => task.id !== action.id)
77+
78+
case 'TOGGLE_TASK':
79+
return state.map(task => (task.id === action.id) ? { ...task, done: !task.done } : task)
80+
81+
default:
82+
return state
83+
}
84+
}

src/main.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { StrictMode } from 'react'
22
import { createRoot } from 'react-dom/client'
33
import './index.css'
4+
import App from './App'
45

56
createRoot(document.getElementById('root')!).render(
67
<StrictMode>
8+
<App />
79
</StrictMode>,
810
)

0 commit comments

Comments
 (0)