diff --git a/src/components/ToolManager.tsx b/src/components/ToolManager.tsx index 7bcc1a0..f7ccdfc 100644 --- a/src/components/ToolManager.tsx +++ b/src/components/ToolManager.tsx @@ -1,9 +1,11 @@ -import { type Tool } from '../constants/tools'; -import { useState, useEffect } from 'react'; +import { type Tool, type Category, CATEGORIES } from '../constants/tools'; +import { useState, useEffect, useMemo } from 'react'; import ToolCard from './tool/ToolCard'; +import CategoryFilter from '../ui/CategoryFilter'; export default function ToolManager({ tools }: { tools: Tool[] }) { const [favoriteTools, setFavoriteTools] = useState([]); + const [activeCategory, setActiveCategory] = useState("All"); function setFavorites(array: Tool[]){ localStorage.setItem('favorite_tools', JSON.stringify(array.map(m => m.href))); @@ -32,6 +34,59 @@ export default function ToolManager({ tools }: { tools: Tool[] }) { setFavorites(validatedFavorites); }, []); + useEffect(() => { + const syncCategoryFromUrl = () => { + const params = new URLSearchParams(window.location.search); + const categoryParam = params.get("category"); + if (categoryParam) { + const matchedCategory = CATEGORIES.find(c => c.toLowerCase() === categoryParam.toLowerCase()); + if (matchedCategory) { + setActiveCategory(matchedCategory); + } else { + setActiveCategory("All"); + } + } else { + setActiveCategory("All"); + } + }; + + syncCategoryFromUrl(); + window.addEventListener("popstate", syncCategoryFromUrl); + return () => window.removeEventListener("popstate", syncCategoryFromUrl); + }, []); + + const handleCategorySelect = (category: Category | "All") => { + setActiveCategory(category); + const url = new URL(window.location.href); + if (category === "All") { + url.searchParams.delete("category"); + } else { + url.searchParams.set("category", category.toLowerCase()); + } + window.history.pushState(null, "", url.toString()); + }; + + const categoriesWithCounts = useMemo(() => { + const counts: Record = { All: tools.length }; + CATEGORIES.forEach(c => counts[c] = 0); + tools.forEach(t => { + if (t.category && counts[t.category] !== undefined) { + counts[t.category]++; + } + }); + + const result = [{ name: "All" as const, count: counts["All"] }]; + CATEGORIES.forEach(c => { + result.push({ name: c, count: counts[c] }); + }); + return result; + }, [tools]); + + const displayTools = useMemo(() => { + if (activeCategory === "All") return tools; + return tools.filter(t => t.category === activeCategory); + }, [tools, activeCategory]); + return (
{(favoriteTools.length !== 0) && ( @@ -55,13 +110,18 @@ export default function ToolManager({ tools }: { tools: Tool[] }) {

Available Tools

-

+

Essential utilities to boost your productivity.

+
- {tools.map(tool => t.href === tool.href)} key={tool.href} tool={tool} onFavoriteToggle={onFavoriteToggle}>)} + {displayTools.map(tool => t.href === tool.href)} key={tool.href} tool={tool} onFavoriteToggle={onFavoriteToggle}>)}
) diff --git a/src/constants/tools.ts b/src/constants/tools.ts index 1958b0d..b7aeb59 100644 --- a/src/constants/tools.ts +++ b/src/constants/tools.ts @@ -1,3 +1,7 @@ +export type Category = "Format" | "Convert" | "CSS" | "Security" | "Generate" | "Dev"; + +export const CATEGORIES: Category[] = ["Format", "Convert", "CSS", "Security", "Generate", "Dev"]; + export interface Tool { name: string; description: string; @@ -12,18 +16,21 @@ export const tools: Tool[] = [ "Beautify and validate your JSON data with custom indentation.", href: "/tools/json-formatter", icon: ``, + category: "Format", }, { name: "Base64 Encoder & Decoder", description: "Encode and decode Base64 strings easily.", href: "/tools/base64-converter", icon: ``, + category: "Convert", }, { name: "URL Encoder & Decoder", description: "Encode and decode URL-safe text and query strings.", href: "/tools/url-converter", icon: ``, + category: "Convert", }, { name: "Diff Checker", @@ -31,30 +38,35 @@ export const tools: Tool[] = [ "Compare text side by side and highlight added, removed, and changed lines.", href: "/tools/diff-checker", icon: ``, + category: "Dev", }, { name: "UUID Generator", description: "Generate UUID v4 values instantly", href: "/tools/uuid-generator", icon: ``, + category: "Generate", }, { name: "JWT Decoder", description: "Decode and inspect JSON Web Tokens locally.", href: "/tools/jwt-decoder", icon: ``, + category: "Security", }, { name: "Unix Timestamp Converter", description: "Convert timestamps to readable dates and back.", href: "/tools/timestamp-converter", icon: ``, + category: "Convert", }, { name: "Hash Generator", description: "Generate SHA-1, SHA-256, and SHA-512 hashes securely.", href: "/tools/hash-generator", icon: ``, + category: "Security", }, { name: "Regex Sandbox", @@ -62,6 +74,7 @@ export const tools: Tool[] = [ "Test and debug regular expressions visually with real-time highlighting and capture groups.", href: "/tools/regex-sandbox", icon: ``, + category: "Dev", }, { name: "API Tester", @@ -69,12 +82,14 @@ export const tools: Tool[] = [ "A lightweight, no-fuss client to send REST API requests and instantly inspect JSON responses.", href: "/tools/api-tester", icon: ``, + category: "Dev", }, { name: "JSON Model Generator", description: "Convert JSON into TypeScript interfaces and Dart classes.", href: "/tools/json-model-generator", icon: ``, + category: "Convert", }, { name: "Cron Expression Generator", @@ -82,12 +97,14 @@ export const tools: Tool[] = [ "Build, validate, and understand cron expressions with a visual editor and plain English explanations.", href: "/tools/cron-generator", icon: ``, + category: "Generate", }, { name: "QR Code Generator", description: "Generate QR codes from text or URLs instantly.", href: "/tools/qr-code-generator", icon: ``, + category: "Generate", }, { name: "Text Case Modifier", @@ -95,6 +112,7 @@ export const tools: Tool[] = [ "Convert text between UPPERCASE, lowercase, Title Case, camelCase, PascalCase, snake_case, and kebab-case.", href: "/tools/text-case-modifier", icon: ``, + category: "Convert", }, { name: "Text ↔ Binary Converter", @@ -102,6 +120,7 @@ export const tools: Tool[] = [ "Convert plain text to binary (0s and 1s) and binary back to readable text instantly.", href: "/tools/text-to-binary", icon: ``, + category: "Convert", }, { name: "Number Base Converter", @@ -109,6 +128,7 @@ export const tools: Tool[] = [ "Convert numbers between Decimal, Binary, Hexadecimal, and Octal in real time.", href: "/tools/number-base-converter", icon: ``, + category: "Convert", }, { name: "Lorem Ipsum Generator", @@ -116,6 +136,7 @@ export const tools: Tool[] = [ "Generate customizable Lorem Ipsum placeholder text by words, sentences, or paragraphs.", href: "/tools/lorem-ipsum-generator", icon: ``, + category: "Generate", }, { name: "Color Converter", @@ -123,6 +144,7 @@ export const tools: Tool[] = [ "Convert colors between HEX, RGB, HSL, and CSS named formats with a live preview.", href: "/tools/color-converter", icon: ``, + category: "CSS", }, { name: "Gitignore Generator", @@ -130,6 +152,7 @@ export const tools: Tool[] = [ "Generate a customized, production-ready .gitignore file based on the technology you use.", href: "/tools/gitignore-generator", icon: ``, + category: "Generate", }, { name: "Markdown Preview", @@ -137,12 +160,14 @@ export const tools: Tool[] = [ "Live preview your Markdown as HTML with real-time rendering and sanitized output.", href: "/tools/markdown-preview", icon: ``, + category: "Format", }, { name: "Curl to Fetch", description: "Convert curl commands into JavaScript fetch requests.", href: "/tools/curl-to-fetch", icon: ``, + category: "Convert", }, { name: "JSON ↔ CSV Converter", @@ -150,6 +175,7 @@ export const tools: Tool[] = [ "Convert JSON arrays to CSV and CSV data back into JSON instantly.", href: "/tools/json-csv-converter", icon: ``, + category: "Convert", }, { name: "YAML ↔ JSON Converter", @@ -157,6 +183,7 @@ export const tools: Tool[] = [ "Convert YAML to JSON and JSON to YAML instantly in your browser.", href: "/tools/yaml-json-converter", icon: ``, + category: "Convert", }, { name: "Password Generator", @@ -164,6 +191,7 @@ export const tools: Tool[] = [ "Generate secure random passwords with customizable length and character options.", href: "/tools/password-generator", icon: ``, + category: "Security", }, { name: "Password Strength Checker", @@ -171,12 +199,14 @@ export const tools: Tool[] = [ "Evaluate password strength locally with instant feedback and clear improvement suggestions.", href: "/tools/password-strength-checker", icon: ``, + category: "Security", }, { name: "HTML Live Preview", description: "Preview HTML instantly with safe browser-side rendering.", href: "/tools/html-live-preview", icon: ``, + category: "Format", }, { name: "SQL Formatter", @@ -184,18 +214,21 @@ export const tools: Tool[] = [ "Beautify your raw SQL queries with clean spacing and line breaks automatically.", href: "/tools/sql-formatter", icon: ``, + category: "Format", }, { name: "XML Formatter", description: "Format and validate XML with clean readable output.", href: "/tools/xml-formatter", icon: ``, + category: "Format", }, { name: "CSS Unit Converter", description: "Convert between px, em, rem, %, vw and vh units.", href: "/tools/css-unit-converter", icon: ``, + category: "CSS", }, { name: "CSS Clamp Generator", @@ -207,6 +240,7 @@ export const tools: Tool[] = [ `, + category: "CSS", }, { name: "Color Palette Generator", @@ -214,6 +248,7 @@ export const tools: Tool[] = [ "Generate beautiful color schemes with different harmonies and export them, or create multi-stop CSS gradients.", href: "/tools/color-palette-generator", icon: ``, + category: "CSS", }, { name: "CSS Grid Generator", @@ -221,6 +256,7 @@ export const tools: Tool[] = [ "Visually configure CSS Grid layouts and generate copyable CSS with live preview.", href: "/tools/grid-generator", icon: ``, + category: "CSS", }, { name: "CSS Gradient Generator", @@ -228,6 +264,7 @@ export const tools: Tool[] = [ "Generate CSS gradients visually with live preview and exportable CSS code.", href: "/tools/css-gradient-generator", icon: ``, + category: "CSS", }, { name: "CSS Animation Generator", @@ -235,6 +272,7 @@ export const tools: Tool[] = [ "Visually design CSS animations with delay, duration, easing, and direction controls, and copy the generated CSS & keyframes.", href: "/tools/css-animation-generator", icon: ``, + category: "CSS", }, { name: "Tailwind Class Generator", @@ -242,6 +280,7 @@ export const tools: Tool[] = [ "Build Tailwind CSS utility classes visually with live preview and copyable output.", href: "/tools/tailwind-class-generator", icon: ``, + category: "CSS", }, { name: "CSS Box Shadow Generator", @@ -249,6 +288,7 @@ export const tools: Tool[] = [ "Build CSS box-shadow styles with live preview, sliders, and copyable output.", href: "/tools/box-shadow-generator", icon: ``, + category: "CSS", }, { name: "Flexbox Generator", @@ -256,6 +296,7 @@ export const tools: Tool[] = [ "Configure Flexbox layouts visually and generate CSS with a live preview.", href: "/tools/flexbox-generator", icon: ``, + category: "CSS", }, { name: "Border Radius Generator", @@ -263,6 +304,7 @@ export const tools: Tool[] = [ "Generate rounded-corner CSS with a live preview and copy-ready border-radius output.", href: "/tools/border-radius-generator", icon: ``, + category: "CSS", }, { name: "OpenAPI / Swagger Viewer", @@ -270,6 +312,7 @@ export const tools: Tool[] = [ "Parse and view OpenAPI/Swagger specifications visually in an interactive, clean API documentation viewer.", href: "/tools/openapi-swagger-viewer", icon: ``, + category: "Dev", }, { name: "JWT Generator & Validator", @@ -277,6 +320,7 @@ export const tools: Tool[] = [ "Generate, inspect, decode, and verify JSON Web Tokens directly in your browser.", href: "/tools/jwt-generator-validator", icon: ``, + category: "Security", }, { name: "Bcrypt Generator & Validator", @@ -284,6 +328,7 @@ export const tools: Tool[] = [ "Generate bcrypt hashes with configurable salt rounds and validate plaintext against existing hashes. Runs entirely in your browser.", href: "/tools/bcrypt-generator", icon: ``, + category: "Security", }, { name: "Word & Character Counter", @@ -291,6 +336,7 @@ export const tools: Tool[] = [ "Count characters, words, sentences, and paragraphs in real time, with reading and speaking time estimates.", href: "/tools/word-counter", icon: ``, + category: "Dev", }, { name: "HTTP Status Code Reference", @@ -298,5 +344,6 @@ export const tools: Tool[] = [ "Browse and search common HTTP status codes grouped by category, with names and short descriptions.", href: "/tools/http-status-codes", icon: ``, + category: "Dev", }, ]; diff --git a/src/ui/CategoryFilter.tsx b/src/ui/CategoryFilter.tsx new file mode 100644 index 0000000..f8f1ddc --- /dev/null +++ b/src/ui/CategoryFilter.tsx @@ -0,0 +1,28 @@ +import Button from "./Button"; +import { type Category } from "../constants/tools"; + +interface CategoryFilterProps { + categories: { name: Category | "All"; count: number }[]; + activeCategory: Category | "All"; + onSelect: (category: Category | "All") => void; +} + +export default function CategoryFilter({ + categories, + activeCategory, + onSelect, +}: CategoryFilterProps) { + return ( +
+ {categories.map((cat) => ( + + ))} +
+ ); +}