Skip to content

Commit aa1f0df

Browse files
Fix critical nesting error and stabilization of Tools Page
1 parent a9817a0 commit aa1f0df

1 file changed

Lines changed: 60 additions & 57 deletions

File tree

app/tools/page.tsx

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
'use client'
22

3-
import React, { useState, useEffect, useMemo } from 'react'
3+
import React, { useState, useMemo, useEffect } from 'react'
44
import Link from 'next/link'
5-
import {
5+
import {
66
FileJson, Key, FileText, Link as LinkIcon, AlignLeft, Palette,
77
Hash, Type, Clock, Binary, Shield, Code, Ruler, Shuffle, FileCode, Globe,
8-
Search, Filter, Laptop, Zap, Settings, Layout, Layers, Code2, Star
8+
Search, Filter, Laptop, Zap, Settings, Layout, Layers, Code2
99
} from 'lucide-react'
1010

1111
const tools = [
1212
// Formatters
1313
{ name: 'Professional JSON Formatter', description: 'Enterprise-grade JSON formatting, validation, and beautification', icon: FileJson, href: '/tools/json-formatter', color: 'from-blue-500 to-blue-700', category: 'Formatters' },
1414
{ name: 'JS Code Minifier', description: 'High-performance JavaScript compression for production deployment', icon: Code2, href: '/tools/js-minifier', color: 'from-yellow-500 to-yellow-700', category: 'Formatters' },
15-
15+
1616
// Generators
1717
{ name: 'Secure Password Generator', description: 'US-standard cryptographically secure password generation tool', icon: Key, href: '/tools/password-generator', color: 'from-indigo-500 to-indigo-700', category: 'Generators' },
1818
{ name: 'UUID/GUID Generator', description: 'Instant RFC-compliant unique identifier generation', icon: Shuffle, href: '/tools/uuid-generator', color: 'from-lime-600 to-lime-800', category: 'Generators' },
@@ -24,7 +24,7 @@ const tools = [
2424
{ name: 'JSON-LD Schema Generator', description: 'Build structured data schema for Google Rich Results', icon: Code, href: '/tools/schema-generator', color: 'from-emerald-600 to-emerald-800', category: 'SEO', releaseDate: '2026-05-07' },
2525
{ name: 'WCAG Color Contrast Checker', description: 'Verify ADA and WCAG 2.1 accessibility compliance', icon: Palette, href: '/tools/color-contrast', color: 'from-pink-500 to-pink-700', category: 'Design', releaseDate: '2026-05-08' },
2626
{ name: 'Markdown to HTML Converter', description: 'Convert documentation to clean, semantic HTML code', icon: FileCode, href: '/tools/markdown-converter', color: 'from-violet-500 to-violet-700', category: 'Formatters', releaseDate: '2026-05-09' },
27-
27+
2828
// Converters
2929
{ name: 'Base64 Data Converter', description: 'Secure encoding and decoding of Base64 data strings', icon: FileText, href: '/tools/base64-encoder', color: 'from-purple-500 to-purple-700', category: 'Converters' },
3030
{ name: 'URL Percent Encoder', description: 'Safe URL encoding for special characters and parameters', icon: LinkIcon, href: '/tools/url-encoder', color: 'from-emerald-500 to-emerald-700', category: 'Converters' },
@@ -33,7 +33,7 @@ const tools = [
3333
{ name: 'CSS Unit Converter Pro', description: 'Calculate px, rem, em, and vh units for responsive design', icon: Ruler, href: '/tools/css-unit-converter', color: 'from-fuchsia-500 to-fuchsia-700', category: 'Converters' },
3434
{ name: 'Text Case Converter', description: 'Transform text into Uppercase, Lowercase, and Title Case', icon: Type, href: '/tools/case-converter', color: 'from-cyan-500 to-cyan-700', category: 'Converters' },
3535
{ name: 'HTML Entity Encoder', description: 'Convert special characters into secure HTML entities', icon: Code, href: '/tools/html-encoder', color: 'from-violet-500 to-violet-700', category: 'Converters' },
36-
36+
3737
// Utilities
3838
{ name: 'Design Color Picker', description: 'Visual color selection with HEX and RGB export', icon: Palette, href: '/tools/color-picker', color: 'from-pink-500 to-pink-700', category: 'Utilities' },
3939
{ name: 'Technical Word Counter', description: 'Accurate word, character, and sentence analysis', icon: Hash, href: '/tools/word-counter', color: 'from-teal-500 to-teal-700', category: 'Utilities' },
@@ -48,7 +48,7 @@ export default function ToolsPage() {
4848
const [favorites, setFavorites] = useState<string[]>([])
4949

5050
const today = useMemo(() => new Date().toISOString().split('T')[0], [])
51-
51+
5252
useEffect(() => {
5353
const saved = localStorage.getItem('wtk_favorites')
5454
if (saved) setFavorites(JSON.parse(saved))
@@ -57,10 +57,10 @@ export default function ToolsPage() {
5757
const toggleFavorite = (e: React.MouseEvent, href: string) => {
5858
e.preventDefault()
5959
e.stopPropagation()
60-
const newFavorites = favorites.includes(href)
60+
const newFavorites = favorites.includes(href)
6161
? favorites.filter(id => id !== href)
6262
: [...favorites, href]
63-
63+
6464
setFavorites(newFavorites)
6565
localStorage.setItem('wtk_favorites', JSON.stringify(newFavorites))
6666
}
@@ -78,8 +78,8 @@ export default function ToolsPage() {
7878

7979
const filteredTools = useMemo(() => {
8080
return visibleTools.filter(tool => {
81-
const matchesSearch = tool.name.toLowerCase().includes(search.toLowerCase()) ||
82-
tool.description.toLowerCase().includes(search.toLowerCase())
81+
const matchesSearch = tool.name.toLowerCase().includes(search.toLowerCase()) ||
82+
tool.description.toLowerCase().includes(search.toLowerCase())
8383
const matchesCategory = activeCategory === 'All' || tool.category === activeCategory
8484
return matchesSearch && matchesCategory
8585
})
@@ -117,11 +117,10 @@ export default function ToolsPage() {
117117
<button
118118
key={cat}
119119
onClick={() => setActiveCategory(cat)}
120-
className={`px-6 py-4 rounded-2xl font-bold whitespace-nowrap transition-all duration-300 ${
121-
activeCategory === cat
122-
? 'bg-blue-600 text-white shadow-lg shadow-blue-200 dark:shadow-none'
123-
: 'bg-white dark:bg-slate-900 text-gray-600 dark:text-slate-400 hover:bg-gray-100 dark:hover:bg-slate-800 border border-gray-100 dark:border-slate-800'
124-
}`}
120+
className={`px-6 py-4 rounded-2xl font-bold whitespace-nowrap transition-all duration-300 ${activeCategory === cat
121+
? 'bg-blue-600 text-white shadow-lg shadow-blue-200 dark:shadow-none'
122+
: 'bg-white dark:bg-slate-900 text-gray-600 dark:text-slate-400 hover:bg-gray-100 dark:hover:bg-slate-800 border border-gray-100 dark:border-slate-800'
123+
}`}
125124
>
126125
{cat}
127126
</button>
@@ -132,7 +131,7 @@ export default function ToolsPage() {
132131

133132
{/* AdSense Slot */}
134133
<div className="max-w-3xl mx-auto mb-12 min-h-[90px] flex items-center justify-center">
135-
{/* AdSense Leaderboard */}
134+
{/* AdSense Leaderboard */}
136135
</div>
137136

138137
{/* Favorites Section */}
@@ -144,69 +143,73 @@ export default function ToolsPage() {
144143
</div>
145144
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
146145
{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-
>
146+
<div key={`fav-${tool.href}`} className="relative group">
152147
<button
153148
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"
149+
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-20"
150+
title="Remove from favorites"
155151
>
156152
<Star className="w-5 h-5 fill-current" />
157153
</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>
154+
<Link
155+
href={tool.href}
156+
className="flex flex-col h-full 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"
157+
>
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+
</div>
169170
))}
170171
</div>
171172
<div className="mt-12 border-b border-gray-100 dark:border-slate-800"></div>
172173
</div>
173174
)}
174-
175+
175176
{/* Tools Grid */}
176177
{filteredTools.length > 0 ? (
177178
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
178179
{filteredTools.map((tool) => (
179-
<Link
180-
key={tool.href}
181-
href={tool.href}
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"
183-
>
180+
<div key={tool.href} className="relative group">
184181
<button
185182
onClick={(e) => toggleFavorite(e, tool.href)}
186-
className={`absolute top-6 right-6 p-2 rounded-full transition-all z-10 ${
183+
className={`absolute top-6 right-6 p-2 rounded-full transition-all z-20 ${
187184
favorites.includes(tool.href)
188185
? 'bg-yellow-50 dark:bg-yellow-900/20 text-yellow-500'
189186
: 'bg-gray-50 dark:bg-slate-800 text-gray-300 dark:text-slate-600 hover:text-yellow-500'
190187
}`}
188+
title={favorites.includes(tool.href) ? "Remove from favorites" : "Add to favorites"}
191189
>
192190
<Star className={`w-5 h-5 ${favorites.includes(tool.href) ? 'fill-current' : ''}`} />
193191
</button>
194-
<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`}>
195-
<tool.icon className="w-7 h-7 text-white" />
196-
</div>
197-
<div className="mb-4">
198-
<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">
199-
{tool.category}
200-
</span>
201-
<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>
202-
</div>
203-
<p className="text-sm text-gray-500 dark:text-slate-400 mb-6 leading-relaxed flex-grow">{tool.description}</p>
204-
<div className="flex items-center justify-between pt-4 border-t border-gray-50 dark:border-slate-800">
205-
<span className="text-sm font-bold text-blue-600 dark:text-blue-400 flex items-center gap-1 group-hover:gap-2 transition-all">
206-
Launch Tool <Zap className="w-4 h-4 fill-current" />
207-
</span>
208-
</div>
209-
</Link>
192+
<Link
193+
href={tool.href}
194+
className="flex flex-col h-full 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"
195+
>
196+
<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`}>
197+
<tool.icon className="w-7 h-7 text-white" />
198+
</div>
199+
<div className="mb-4">
200+
<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">
201+
{tool.category}
202+
</span>
203+
<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>
204+
</div>
205+
<p className="text-sm text-gray-500 dark:text-slate-400 mb-6 leading-relaxed flex-grow">{tool.description}</p>
206+
<div className="flex items-center justify-between pt-4 border-t border-gray-50 dark:border-slate-800">
207+
<span className="text-sm font-bold text-blue-600 dark:text-blue-400 flex items-center gap-1 group-hover:gap-2 transition-all">
208+
Launch Tool <Zap className="w-4 h-4 fill-current" />
209+
</span>
210+
</div>
211+
</Link>
212+
</div>
210213
))}
211214
</div>
212215
) : (

0 commit comments

Comments
 (0)