@@ -45,16 +45,37 @@ const categories = ['All', 'Formatters', 'Generators', 'Converters', 'Utilities'
4545export default function ToolsPage ( ) {
4646 const [ search , setSearch ] = useState ( '' )
4747 const [ activeCategory , setActiveCategory ] = useState ( 'All' )
48+ const [ favorites , setFavorites ] = useState < string [ ] > ( [ ] )
4849
4950 const today = useMemo ( ( ) => new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] , [ ] )
5051
52+ useEffect ( ( ) => {
53+ const saved = localStorage . getItem ( 'wtk_favorites' )
54+ if ( saved ) setFavorites ( JSON . parse ( saved ) )
55+ } , [ ] )
56+
57+ const toggleFavorite = ( e : React . MouseEvent , href : string ) => {
58+ e . preventDefault ( )
59+ e . stopPropagation ( )
60+ const newFavorites = favorites . includes ( href )
61+ ? favorites . filter ( id => id !== href )
62+ : [ ...favorites , href ]
63+
64+ setFavorites ( newFavorites )
65+ localStorage . setItem ( 'wtk_favorites' , JSON . stringify ( newFavorites ) )
66+ }
67+
5168 const visibleTools = useMemo ( ( ) => {
5269 return ( tools as any [ ] ) . filter ( tool => {
5370 if ( ! tool . releaseDate ) return true
5471 return tool . releaseDate <= today
5572 } )
5673 } , [ today ] )
5774
75+ const favoriteTools = useMemo ( ( ) => {
76+ return visibleTools . filter ( tool => favorites . includes ( tool . href ) )
77+ } , [ visibleTools , favorites ] )
78+
5879 const filteredTools = useMemo ( ( ) => {
5980 return visibleTools . filter ( tool => {
6081 const matchesSearch = tool . name . toLowerCase ( ) . includes ( search . toLowerCase ( ) ) ||
@@ -113,6 +134,43 @@ export default function ToolsPage() {
113134 < div className = "max-w-3xl mx-auto mb-12 min-h-[90px] flex items-center justify-center" >
114135 { /* AdSense Leaderboard */ }
115136 </ div >
137+
138+ { /* Favorites Section */ }
139+ { favoriteTools . length > 0 && search === '' && activeCategory === 'All' && (
140+ < div className = "mb-16" >
141+ < div className = "flex items-center gap-2 mb-8" >
142+ < Star className = "w-6 h-6 text-yellow-500 fill-current" />
143+ < h2 className = "text-2xl font-bold text-gray-900 dark:text-white" > Your Favorites</ h2 >
144+ </ div >
145+ < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6" >
146+ { favoriteTools . map ( ( tool ) => (
147+ < Link
148+ key = { `fav-${ tool . href } ` }
149+ href = { tool . href }
150+ className = "group bg-white dark:bg-slate-900 rounded-3xl border border-gray-100 dark:border-slate-800 p-8 hover:shadow-2xl dark:hover:shadow-blue-900/10 hover:-translate-y-1.5 transition-all duration-300 flex flex-col h-full relative"
151+ >
152+ < button
153+ onClick = { ( e ) => toggleFavorite ( e , tool . href ) }
154+ className = "absolute top-6 right-6 p-2 rounded-full bg-yellow-50 dark:bg-yellow-900/20 text-yellow-500 hover:scale-110 transition-transform z-10"
155+ >
156+ < Star className = "w-5 h-5 fill-current" />
157+ </ button >
158+ < div className = { `w-14 h-14 bg-gradient-to-br ${ tool . color } rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform duration-300` } >
159+ < tool . icon className = "w-7 h-7 text-white" />
160+ </ div >
161+ < div className = "mb-4" >
162+ < span className = "text-[10px] font-bold uppercase tracking-widest text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 px-2 py-1 rounded mb-2 inline-block" >
163+ { tool . category }
164+ </ span >
165+ < h3 className = "text-xl font-bold text-gray-900 dark:text-white group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" > { tool . name } </ h3 >
166+ </ div >
167+ < p className = "text-sm text-gray-500 dark:text-slate-400 mb-6 leading-relaxed flex-grow" > { tool . description } </ p >
168+ </ Link >
169+ ) ) }
170+ </ div >
171+ < div className = "mt-12 border-b border-gray-100 dark:border-slate-800" > </ div >
172+ </ div >
173+ ) }
116174
117175 { /* Tools Grid */ }
118176 { filteredTools . length > 0 ? (
@@ -121,8 +179,18 @@ export default function ToolsPage() {
121179 < Link
122180 key = { tool . href }
123181 href = { tool . href }
124- className = "group bg-white dark:bg-slate-900 rounded-3xl border border-gray-100 dark:border-slate-800 p-8 hover:shadow-2xl dark:hover:shadow-blue-900/10 hover:-translate-y-1.5 transition-all duration-300 flex flex-col h-full"
182+ className = "group bg-white dark:bg-slate-900 rounded-3xl border border-gray-100 dark:border-slate-800 p-8 hover:shadow-2xl dark:hover:shadow-blue-900/10 hover:-translate-y-1.5 transition-all duration-300 flex flex-col h-full relative "
125183 >
184+ < button
185+ onClick = { ( e ) => toggleFavorite ( e , tool . href ) }
186+ className = { `absolute top-6 right-6 p-2 rounded-full transition-all z-10 ${
187+ favorites . includes ( tool . href )
188+ ? 'bg-yellow-50 dark:bg-yellow-900/20 text-yellow-500'
189+ : 'bg-gray-50 dark:bg-slate-800 text-gray-300 dark:text-slate-600 hover:text-yellow-500'
190+ } `}
191+ >
192+ < Star className = { `w-5 h-5 ${ favorites . includes ( tool . href ) ? 'fill-current' : '' } ` } />
193+ </ button >
126194 < div className = { `w-14 h-14 bg-gradient-to-br ${ tool . color } rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform duration-300` } >
127195 < tool . icon className = "w-7 h-7 text-white" />
128196 </ div >
@@ -142,15 +210,15 @@ export default function ToolsPage() {
142210 ) ) }
143211 </ div >
144212 ) : (
145- < div className = "text-center py-20 bg-white rounded-3xl border border-dashed border-gray-200" >
146- < div className = "inline-flex items-center justify-center w-20 h-20 bg-gray-50 rounded-full mb-6" >
147- < Search className = "w-10 h-10 text-gray-300" />
213+ < div className = "text-center py-20 bg-white dark:bg-slate-900 rounded-3xl border border-dashed border-gray-200 dark:border-slate-800 " >
214+ < div className = "inline-flex items-center justify-center w-20 h-20 bg-gray-50 dark:bg-slate-800 rounded-full mb-6" >
215+ < Search className = "w-10 h-10 text-gray-300 dark:text-slate-600 " />
148216 </ div >
149- < h3 className = "text-2xl font-bold text-gray-900 mb-2" > No tools found</ h3 >
150- < p className = "text-gray-500" > We couldn't find any tools matching your search or filter.</ p >
217+ < h3 className = "text-2xl font-bold text-gray-900 dark:text-white mb-2" > No tools found</ h3 >
218+ < p className = "text-gray-500 dark:text-slate-400 " > We couldn't find any tools matching your search or filter.</ p >
151219 < button
152220 onClick = { ( ) => { setSearch ( '' ) ; setActiveCategory ( 'All' ) } }
153- className = "mt-6 text-blue-600 font-bold hover:underline"
221+ className = "mt-6 text-blue-600 dark:text-blue-400 font-bold hover:underline"
154222 >
155223 Clear all filters
156224 </ button >
0 commit comments