@@ -13,30 +13,111 @@ export default function TodoList({ todos }) {
1313 }
1414
1515 return (
16- < >
17- < form onSubmit = { handleSubmit } >
18- < input
19- type = "text"
20- value = { data . title }
21- onChange = { ( e ) => setData ( 'title' , e . target . value ) }
22- placeholder = "Add a new todo"
23- disabled = { processing }
24- />
25- < button type = "submit" disabled = { processing } >
26- Add Todo
27- </ button >
28- </ form >
29- { todos . length === 0 ? (
30- < p > No todos available.</ p >
31- ) : (
32- < ul >
33- { todos . map ( ( todo ) => (
34- < li key = { todo . id } >
35- { todo . title } { todo . completed ? '(Completed)' : '' }
36- </ li >
37- ) ) }
38- </ ul >
39- ) }
40- </ >
16+ < div className = "min-h-screen bg-neutral-50 py-12 px-4 sm:px-6 lg:px-8" >
17+ < div className = "max-w-2xl mx-auto" >
18+ { /* Header */ }
19+ < header className = "mb-12" >
20+ < h1 className = "text-4xl font-bold tracking-tight text-neutral-900 mb-2" > Tasks</ h1 >
21+ < div className = "h-1 w-16 bg-neutral-900" aria-hidden = "true" > </ div >
22+ </ header >
23+
24+ { /* Add Todo Form */ }
25+ < section aria-labelledby = "add-todo-heading" className = "mb-16" >
26+ < h2 id = "add-todo-heading" className = "sr-only" >
27+ Add a new task
28+ </ h2 >
29+ < form onSubmit = { handleSubmit } className = "space-y-4" >
30+ < div >
31+ < label htmlFor = "todo-input" className = "block text-sm font-medium text-neutral-700 mb-2" >
32+ New Task
33+ </ label >
34+ < div className = "flex gap-3" >
35+ < input
36+ id = "todo-input"
37+ type = "text"
38+ value = { data . title }
39+ onChange = { ( e ) => setData ( 'title' , e . target . value ) }
40+ placeholder = "What needs to be done?"
41+ disabled = { processing }
42+ required
43+ className = "flex-1 px-4 py-3 border-2 border-neutral-300 bg-white text-neutral-900 placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:border-transparent disabled:bg-neutral-100 disabled:cursor-not-allowed transition-colors"
44+ aria-describedby = "todo-input-description"
45+ />
46+ < button
47+ type = "submit"
48+ disabled = { processing || ! data . title . trim ( ) }
49+ className = "px-6 py-3 bg-neutral-900 text-white font-medium hover:bg-neutral-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 disabled:bg-neutral-400 disabled:cursor-not-allowed transition-colors"
50+ aria-label = "Add task"
51+ >
52+ { processing ? 'Adding...' : 'Add' }
53+ </ button >
54+ </ div >
55+ < p id = "todo-input-description" className = "mt-2 text-sm text-neutral-500" >
56+ Press Enter or click Add to create a new task
57+ </ p >
58+ </ div >
59+ </ form >
60+ </ section >
61+
62+ { /* Todo List */ }
63+ < section aria-labelledby = "todo-list-heading" >
64+ < div className = "flex items-center justify-between mb-6" >
65+ < h2 id = "todo-list-heading" className = "text-2xl font-bold tracking-tight text-neutral-900" >
66+ All Tasks
67+ </ h2 >
68+ < span className = "text-sm font-medium text-neutral-500" aria-live = "polite" aria-atomic = "true" >
69+ { todos . length } { todos . length === 1 ? 'task' : 'tasks' }
70+ </ span >
71+ </ div >
72+
73+ { todos . length === 0 ? (
74+ < div className = "border-2 border-dashed border-neutral-300 bg-white p-12 text-center" role = "status" >
75+ < svg
76+ className = "mx-auto h-12 w-12 text-neutral-400"
77+ fill = "none"
78+ viewBox = "0 0 24 24"
79+ stroke = "currentColor"
80+ aria-hidden = "true"
81+ >
82+ < path
83+ strokeLinecap = "round"
84+ strokeLinejoin = "round"
85+ strokeWidth = { 2 }
86+ d = "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
87+ />
88+ </ svg >
89+ < p className = "mt-4 text-lg font-medium text-neutral-900" > No tasks yet</ p >
90+ < p className = "mt-2 text-sm text-neutral-500" > Get started by creating your first task above</ p >
91+ </ div >
92+ ) : (
93+ < ul className = "space-y-3" role = "list" >
94+ { todos . map ( ( todo ) => (
95+ < li
96+ key = { todo . id }
97+ className = "bg-white border-l-4 border-neutral-900 p-4 shadow-sm hover:shadow-md transition-shadow"
98+ >
99+ < div className = "flex items-start" >
100+ < div className = "flex-1 min-w-0" >
101+ < p
102+ className = { `text-base font-medium ${
103+ todo . completed ? 'text-neutral-500 line-through' : 'text-neutral-900'
104+ } `}
105+ >
106+ { todo . title }
107+ </ p >
108+ { todo . completed && (
109+ < span className = "inline-flex items-center mt-2 px-2 py-1 text-xs font-medium bg-neutral-100 text-neutral-600" >
110+ Completed
111+ </ span >
112+ ) }
113+ </ div >
114+ </ div >
115+ </ li >
116+ ) ) }
117+ </ ul >
118+ ) }
119+ </ section >
120+ </ div >
121+ </ div >
41122 )
42123}
0 commit comments