100% found this document useful (1 vote)
66 views5 pages

!doctype

The document is an HTML template for a web application called ToolNest, which offers over 100 free online tools categorized by functionality. It includes a header, a search bar for tool searching, a grid layout for displaying tool cards, and a footer. The application is built using React and Tailwind CSS, with initial tool data defined in a JavaScript array.

Uploaded by

jayade7307
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
66 views5 pages

!doctype

The document is an HTML template for a web application called ToolNest, which offers over 100 free online tools categorized by functionality. It includes a header, a search bar for tool searching, a grid layout for displaying tool cards, and a footer. The application is built using React and Tailwind CSS, with initial tool data defined in a JavaScript array.

Uploaded by

jayade7307
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 5

<!

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToolNest – 100+ Free Online Tools</title>
<script src="https://cdn.tailwindcss.com"></script>
<style type="text/tailwindcss">
/* You can add custom Tailwind directives or global styles here if needed
*/
body {
font-family: 'Inter', sans-serif; /* A common, clean sans-serif font */
}
/* For smoother sticky search bar */
.sticky-search {
position: -webkit-sticky; /* Safari */
position: sticky;
/* Adjust top value based on header height + desired gap */
/* Header py-5 (20px top/bottom) means ~40px height on small screens,
~48px on md for h1. Let's use a safe value. */
/* Header height: text-3xl (36px line-height) + py-5 (1.25rem*2 =
2.5rem = 40px) = ~76px */
/* Header height: md:text-4xl (40px line-height) + py-5 = ~80px */
/* We need to ensure the search bar sticks below the header. */
}
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?
family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body class="bg-slate-50 text-slate-800">
<div id="root"></div>

<script src="https://unpkg.com/react@18/umd/react.development.js"
crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<script type="text/babel">
const { useState, useEffect } = React;

// --- Data ---


const initialToolsData = [
{
id: 'word-counter',
name: 'Word Counter',
description: 'Count words, characters, sentences, and paragraphs.',
icon: '📝',
category: 'Text Tools',
},
{
id: 'image-converter',
name: 'Image Converter',
description: 'Convert images between JPG, PNG, WEBP, etc.',
icon: '',
category: 'Image Tools',
},
{
id: 'bmi-calculator',
name: 'BMI Calculator',
description: 'Calculate your Body Mass Index quickly.',
icon: '⚖️',
category: 'Health Tools',
},
{
id: 'qr-code-generator',
name: 'QR Code Generator',
description: 'Create custom QR codes for URLs, text, and more.',
icon: '🔗',
category: 'Utility Tools',
},
{
id: 'case-converter',
name: 'Case Converter',
description: 'Convert text to UPPERCASE, lowercase, Title Case, etc.',
icon: ' Aa ',
category: 'Text Tools',
},
{
id: 'json-formatter',
name: 'JSON Formatter',
description: 'Validate and format your JSON data beautifully.',
icon: '📄',
category: 'Developer Tools',
},
{
id: 'color-picker',
name: 'Color Picker',
description: 'Pick colors from a palette or an image.',
icon: '🎨',
category: 'Design Tools',
},
{
id: 'password-generator',
name: 'Password Generator',
description: 'Create strong, secure, and random passwords.',
icon: '🔑',
category: 'Security Tools',
},
];

// --- Components ---

function Header({ title }) {


return (
<header className="bg-gradient-to-r from-sky-500 to-indigo-600 text-
white shadow-md sticky top-0 z-50">
<div className="container mx-auto px-4 py-5">
<h1 className="text-3xl md:text-4xl font-bold text-center tracking-
tight">
{title}
</h1>
</div>
</header>
);
}
function SearchBar({ searchTerm, onSearchChange }) {
return (
<div className="mb-8 sticky-search top-[70px] md:top-[78px] z-40 bg-
slate-50 py-4 -mt-1 shadow-sm"> {/* Adjust top value based on header height */}
<input
type="text"
placeholder="🔍 Search for a tool (e.g., 'image', 'text', 'QR')..."
value={searchTerm}
onChange={(e) => onSearchChange(e.target.value)}
className="w-full p-4 text-lg border-2 border-sky-300 rounded-lg
shadow-sm focus:ring-2 focus:ring-sky-500 focus:border-sky-500 outline-none
transition-shadow duration-300"
/>
</div>
);
}

function ToolCard({ tool }) {


const handleOpenTool = () => {
console.log(`Opening tool: ${tool.name} (ID: ${tool.id})`);
alert(`Imagine opening ${tool.name}! This would navigate to its
dedicated page or display the tool inline.`);
// In a multi-page app, you might do: window.location.href = `/tools/$
{tool.id}`;
};

return (
<div className="bg-white rounded-xl shadow-lg overflow-hidden flex
flex-col h-full
transform transition-all duration-300 ease-in-out
hover:shadow-2xl hover:scale-105 group">
<div className="p-6 flex-grow">
<div className="flex items-center mb-4">
<span className="text-3xl mr-3" role="img" aria-
label={tool.name}>{tool.icon || ''}</span>
<h3 className="text-xl font-semibold text-slate-800 group-
hover:text-sky-600 transition-colors duration-300">
{tool.name}
</h3>
</div>
<p className="text-slate-600 text-sm mb-4 min-h-[3em]">
{tool.description}
</p>
</div>
<div className="p-4 bg-slate-50 border-t border-slate-200">
<button
onClick={handleOpenTool}
className="w-full bg-sky-500 text-white font-semibold py-2 px-4
rounded-lg
hover:bg-sky-600 focus:outline-none focus:ring-2
focus:ring-sky-500 focus:ring-opacity-50
transition-all duration-300 transform hover:translate-
y-[-2px] active:translate-y-[1px]"
>
Open Tool
</button>
</div>
</div>
);
}

function ToolGrid({ tools }) {


if (!tools || tools.length === 0) {
return <p className="text-center text-slate-500">No tools available at
the moment.</p>;
}

return (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-
cols-4 xl:grid-cols-5 gap-6">
{tools.map(tool => (
<ToolCard key={tool.id} tool={tool} />
))}
</div>
);
}

function Footer() {
return (
<footer className="bg-slate-800 text-slate-300 text-center p-6 mt-12">
<p>&copy; 2025 ToolNest. All rights reserved.</p>
<p className="text-sm text-slate-400 mt-1">
Crafted for all your utility needs.
</p>
</footer>
);
}

// --- Main App Component ---


function App() {
const [allTools, setAllTools] = useState([]);
const [filteredTools, setFilteredTools] = useState([]);
const [searchTerm, setSearchTerm] = useState('');

useEffect(() => {
// Simulate fetching data (in a real app, this could be from an API or
Firebase)
// For now, using the predefined initialToolsData
setAllTools(initialToolsData);
setFilteredTools(initialToolsData);
}, []);

useEffect(() => {
const lowercasedFilter = searchTerm.toLowerCase();
const filtered = allTools.filter(tool =>
tool.name.toLowerCase().includes(lowercasedFilter) ||
tool.description.toLowerCase().includes(lowercasedFilter) ||
tool.category.toLowerCase().includes(lowercasedFilter)
);
setFilteredTools(filtered);
}, [searchTerm, allTools]);

return (
<div className="flex flex-col min-h-screen">
<Header title="ToolNest – 100+ Free Online Tools" />
<main className="flex-grow container mx-auto px-4 py-8">
<SearchBar searchTerm={searchTerm}
onSearchChange={setSearchTerm} />
{filteredTools.length > 0 ? (
<ToolGrid tools={filteredTools} />
) : (
<p className="text-center text-slate-500 text-xl mt-10">
No tools found matching your search. Try a different keyword!
</p>
)}
</main>
<Footer />
</div>
);
}

// --- Render the App ---


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

</script>
</body>
</html>

You might also like