1- import { ReactNode , CSSProperties , ChangeEvent } from 'react' ;
1+ import { ReactNode , CSSProperties , ChangeEvent , ButtonHTMLAttributes } from 'react' ;
22
33// Container for the whole TodoList app
44interface ContainerProps {
55 children : ReactNode ;
66}
77
8- const Container = ( { children} : ContainerProps ) => (
9- < div style = { { maxWidth : '800px' , margin : '0 auto' , fontFamily : 'Arial, sans-serif' } } >
8+ const Container = ( { children } : ContainerProps ) => (
9+ < div className = "max-w-4xl mx- auto px-4 py-8 font-sans" >
1010 { children }
1111 </ div >
1212) ;
@@ -16,66 +16,72 @@ interface HeaderProps {
1616 children : ReactNode ;
1717}
1818
19- const Header = ( { children} : HeaderProps ) => (
20- < h1 style = { { textAlign : ' center' , color : '#333' , marginBottom : '20px' } } >
19+ const Header = ( { children } : HeaderProps ) => (
20+ < h1 className = "text-4xl font-bold text- center text-transparent bg-clip-text bg-gradient-to-r from-primary-dark via-primary to-primary-light drop-shadow-sm py-2 mb-6" >
2121 { children }
2222 </ h1 >
2323) ;
2424
2525// Styled button with hover effect
26- interface StyledButtonProps {
26+ interface StyledButtonProps extends ButtonHTMLAttributes < HTMLButtonElement > {
2727 children : ReactNode ;
28- onClick ?: ( ) => void ;
29- type ?: 'button' | 'submit' | 'reset' ;
30- style ?: CSSProperties ;
28+ variant ?: 'primary' | 'success' | 'danger' ;
3129}
3230
33- const StyledButton = ( { children, onClick, type = 'button' , style} : StyledButtonProps ) => (
34- < button
35- type = { type }
36- onClick = { onClick }
37- style = { {
38- padding : '10px 20px' ,
39- fontSize : '16px' ,
40- backgroundColor : '#28a745' ,
41- color : '#fff' ,
42- border : 'none' ,
43- borderRadius : '4px' ,
44- cursor : 'pointer' ,
45- transition : 'background-color 0.3s' ,
46- ...style ,
47- } }
48- onMouseEnter = { ( e ) => ( e . currentTarget . style . backgroundColor = '#218838' ) }
49- onMouseLeave = { ( e ) => ( e . currentTarget . style . backgroundColor = '#28a745' ) }
50- >
51- { children }
52- </ button >
53- ) ;
31+ const StyledButton = ( {
32+ children,
33+ onClick,
34+ type = 'button' ,
35+ variant = 'primary' ,
36+ className = '' ,
37+ ...rest
38+ } : StyledButtonProps ) => {
39+ const baseClass = 'btn' ;
40+ const variantClass = `btn-${ variant } ` ;
41+
42+ return (
43+ < button
44+ type = { type }
45+ onClick = { onClick }
46+ className = { `${ baseClass } ${ variantClass } ${ className } ` }
47+ { ...rest }
48+ >
49+ { children }
50+ </ button >
51+ ) ;
52+ } ;
5453
5554// Small icon button for action controls (toggle and delete)
5655interface IconButtonProps {
5756 icon : ReactNode ;
58- color : string ;
5957 onClick : ( ) => void ;
6058 title : string ;
59+ variant ?: 'primary' | 'success' | 'danger' ;
6160}
6261
63- const IconButton = ( { icon, color, onClick, title} : IconButtonProps ) => (
64- < button
65- onClick = { onClick }
66- title = { title }
67- style = { {
68- backgroundColor : 'transparent' ,
69- border : 'none' ,
70- cursor : 'pointer' ,
71- fontSize : '16px' ,
72- color,
73- margin : '0 5px' ,
74- } }
75- >
76- { icon }
77- </ button >
78- ) ;
62+ const IconButton = ( {
63+ icon,
64+ onClick,
65+ title,
66+ variant = 'primary'
67+ } : IconButtonProps ) => {
68+ const variantClasses = {
69+ primary : 'text-primary hover:text-primary-dark' ,
70+ success : 'text-success hover:text-success-dark' ,
71+ danger : 'text-danger hover:text-danger-dark' ,
72+ } ;
73+
74+ return (
75+ < button
76+ onClick = { onClick }
77+ title = { title }
78+ className = { `bg-transparent border-none cursor-pointer p-2 transition-colors ${ variantClasses [ variant ] } ` }
79+ aria-label = { title }
80+ >
81+ { icon }
82+ </ button >
83+ ) ;
84+ } ;
7985
8086// Input field for entering todo title
8187interface StyledInputProps {
@@ -84,21 +90,14 @@ interface StyledInputProps {
8490 placeholder ?: string ;
8591}
8692
87- const StyledInput = ( { value, onChange, placeholder} : StyledInputProps ) => (
93+ const StyledInput = ( { value, onChange, placeholder } : StyledInputProps ) => (
8894 < input
8995 type = "text"
9096 value = { value }
9197 onChange = { onChange }
9298 placeholder = { placeholder }
93- required = { true }
94- style = { {
95- padding : '10px' ,
96- width : '70%' ,
97- fontSize : '16px' ,
98- border : '1px solid #ddd' ,
99- borderRadius : '4px' ,
100- marginRight : '10px' ,
101- } }
99+ required
100+ className = "px-4 py-2 border border-gray-300 rounded-md w-full md:w-96 shadow-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
102101 />
103102) ;
104103
@@ -107,16 +106,12 @@ interface StyledTableProps {
107106 children : ReactNode ;
108107}
109108
110- const StyledTable = ( { children} : StyledTableProps ) => (
111- < table
112- style = { {
113- width : '100%' ,
114- borderCollapse : 'collapse' ,
115- boxShadow : '0 4px 8px rgba(0, 0, 0, 0.1)' ,
116- } }
117- >
118- { children }
119- </ table >
109+ const StyledTable = ( { children } : StyledTableProps ) => (
110+ < div className = "w-full overflow-x-auto rounded-lg shadow-md bg-white animate-fade-in" >
111+ < table className = "w-full border-collapse" >
112+ { children }
113+ </ table >
114+ </ div >
120115) ;
121116
122117// Table cell component with optional width
@@ -127,22 +122,32 @@ interface TableCellProps {
127122 width ?: string ;
128123}
129124
130- const TableCell = ( { children, header = false , center = false , width} : TableCellProps ) => {
131- const baseStyle : CSSProperties = {
132- padding : '10px' ,
133- textAlign : center ? 'center' : 'left' ,
134- backgroundColor : header ? '#f4f4f4' : 'inherit' ,
135- borderBottom : header ? '2px solid #ddd' : '1px solid #ddd' ,
136- width : width || 'auto' ,
137- whiteSpace : 'nowrap' ,
138- overflow : 'hidden' ,
139- textOverflow : 'ellipsis' ,
140- } ;
141-
125+ const TableCell = ( {
126+ children,
127+ header = false ,
128+ center = false ,
129+ width
130+ } : TableCellProps ) => {
131+ // Added truncate and fixed height classes to prevent line wrapping
132+ const baseClass = "p-3 text-sm border-b border-gray-200 whitespace-nowrap overflow-hidden text-ellipsis" ;
133+ const alignClass = center ? "text-center" : "text-left" ;
134+ const headerClass = header ? "bg-gray-100 font-semibold text-gray-700" : "" ;
135+
136+ const style : CSSProperties = { } ;
137+ if ( width ) {
138+ style . width = width ;
139+ // Add max-width to ensure proper truncation
140+ style . maxWidth = width ;
141+ }
142+
142143 return header ? (
143- < th style = { baseStyle } > { children } </ th >
144+ < th className = { `${ baseClass } ${ alignClass } ${ headerClass } ` } style = { style } >
145+ { children }
146+ </ th >
144147 ) : (
145- < td style = { baseStyle } > { children } </ td >
148+ < td className = { `${ baseClass } ${ alignClass } ` } style = { style } >
149+ { children }
150+ </ td >
146151 ) ;
147152} ;
148153
@@ -151,9 +156,9 @@ interface WelcomeMessageProps {
151156 username : string ;
152157}
153158
154- const WelcomeMessage = ( { username} : WelcomeMessageProps ) => (
155- < p style = { { textAlign : ' center' , fontSize : '18px' , color : '#555' } } >
156- Welcome, { username } !
159+ const WelcomeMessage = ( { username } : WelcomeMessageProps ) => (
160+ < p className = "text- center text-lg text-gray-600 mb-6" >
161+ Welcome, < span className = "font-semibold" > { username } </ span > !
157162 </ p >
158163) ;
159164
0 commit comments