mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add Lucide icons to all 47 tools with BentoPDF-style card layout
This commit is contained in:
@@ -1,6 +1,53 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Search } from "lucide-react";
|
import type { LucideIcon } from "lucide-react";
|
||||||
|
import {
|
||||||
|
AppWindow,
|
||||||
|
AudioLines,
|
||||||
|
Code,
|
||||||
|
Columns,
|
||||||
|
Columns2,
|
||||||
|
Copy,
|
||||||
|
Crop,
|
||||||
|
Eraser,
|
||||||
|
Eye,
|
||||||
|
EyeOff,
|
||||||
|
FileEdit,
|
||||||
|
FileImage,
|
||||||
|
FileOutput,
|
||||||
|
FileText,
|
||||||
|
Film,
|
||||||
|
Focus,
|
||||||
|
Frame,
|
||||||
|
Globe,
|
||||||
|
Grid3x3,
|
||||||
|
ImagePlus,
|
||||||
|
Info,
|
||||||
|
Layers,
|
||||||
|
LayoutGrid,
|
||||||
|
Maximize2,
|
||||||
|
Minimize2,
|
||||||
|
Palette,
|
||||||
|
PenLine,
|
||||||
|
PenTool,
|
||||||
|
Pipette,
|
||||||
|
QrCode,
|
||||||
|
RotateCw,
|
||||||
|
Scan,
|
||||||
|
ScanFace,
|
||||||
|
ScanLine,
|
||||||
|
ScanText,
|
||||||
|
Search,
|
||||||
|
ShieldOff,
|
||||||
|
SlidersHorizontal,
|
||||||
|
Sparkles,
|
||||||
|
TextCursorInput,
|
||||||
|
Type,
|
||||||
|
Undo2,
|
||||||
|
UserCheck,
|
||||||
|
Wand2,
|
||||||
|
ZoomIn,
|
||||||
|
} from "lucide-react";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { FadeIn } from "./fade-in";
|
import { FadeIn } from "./fade-in";
|
||||||
|
|
||||||
@@ -15,28 +62,37 @@ const categories = [
|
|||||||
{ id: "ai", name: "AI Tools", color: "#F59E0B" },
|
{ id: "ai", name: "AI Tools", color: "#F59E0B" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const tools = [
|
const tools: { name: string; description: string; category: string; icon: LucideIcon }[] = [
|
||||||
// Essentials
|
// Essentials
|
||||||
{
|
{
|
||||||
name: "Resize",
|
name: "Resize",
|
||||||
description: "Resize by pixels, percentage, or social media presets",
|
description: "Resize by pixels, percentage, or social media presets",
|
||||||
category: "essentials",
|
category: "essentials",
|
||||||
|
icon: Maximize2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Crop",
|
name: "Crop",
|
||||||
description: "Freeform crop, aspect ratio presets, shape crop",
|
description: "Freeform crop, aspect ratio presets, shape crop",
|
||||||
category: "essentials",
|
category: "essentials",
|
||||||
|
icon: Crop,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Rotate & Flip",
|
name: "Rotate & Flip",
|
||||||
description: "Rotate, flip, and straighten images",
|
description: "Rotate, flip, and straighten images",
|
||||||
category: "essentials",
|
category: "essentials",
|
||||||
|
icon: RotateCw,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Convert",
|
||||||
|
description: "Convert between image formats",
|
||||||
|
category: "essentials",
|
||||||
|
icon: FileOutput,
|
||||||
},
|
},
|
||||||
{ name: "Convert", description: "Convert between image formats", category: "essentials" },
|
|
||||||
{
|
{
|
||||||
name: "Compress",
|
name: "Compress",
|
||||||
description: "Reduce file size by quality or target size",
|
description: "Reduce file size by quality or target size",
|
||||||
category: "essentials",
|
category: "essentials",
|
||||||
|
icon: Minimize2,
|
||||||
},
|
},
|
||||||
// Optimization
|
// Optimization
|
||||||
{
|
{
|
||||||
@@ -44,170 +100,255 @@ const tools = [
|
|||||||
description:
|
description:
|
||||||
"Optimize images for web with format conversion, quality control, and live preview",
|
"Optimize images for web with format conversion, quality control, and live preview",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: Globe,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Remove Metadata",
|
name: "Remove Metadata",
|
||||||
description: "Remove EXIF, GPS, and camera info",
|
description: "Remove EXIF, GPS, and camera info",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: ShieldOff,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Edit Metadata",
|
name: "Edit Metadata",
|
||||||
description: "Edit EXIF, GPS, and camera info",
|
description: "Edit EXIF, GPS, and camera info",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: PenLine,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Bulk Rename",
|
name: "Bulk Rename",
|
||||||
description: "Rename multiple files with patterns",
|
description: "Rename multiple files with patterns",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: FileEdit,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Image to PDF",
|
name: "Image to PDF",
|
||||||
description: "Combine images into a PDF document",
|
description: "Combine images into a PDF document",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: FileText,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Favicon Generator",
|
name: "Favicon Generator",
|
||||||
description: "Generate all favicon and app icon sizes",
|
description: "Generate all favicon and app icon sizes",
|
||||||
category: "optimization",
|
category: "optimization",
|
||||||
|
icon: AppWindow,
|
||||||
},
|
},
|
||||||
// Adjustments
|
// Adjustments
|
||||||
{
|
{
|
||||||
name: "Adjust Colors",
|
name: "Adjust Colors",
|
||||||
description: "Brightness, contrast, exposure, saturation, temperature, sharpness, and effects",
|
description: "Brightness, contrast, exposure, saturation, temperature, sharpness, and effects",
|
||||||
category: "adjustments",
|
category: "adjustments",
|
||||||
|
icon: SlidersHorizontal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sharpening",
|
name: "Sharpening",
|
||||||
description: "Adaptive, unsharp mask, and high-pass sharpening with presets",
|
description: "Adaptive, unsharp mask, and high-pass sharpening with presets",
|
||||||
category: "adjustments",
|
category: "adjustments",
|
||||||
|
icon: Focus,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Replace & Invert Color",
|
name: "Replace & Invert Color",
|
||||||
description: "Replace specific colors or invert",
|
description: "Replace specific colors or invert",
|
||||||
category: "adjustments",
|
category: "adjustments",
|
||||||
|
icon: Pipette,
|
||||||
},
|
},
|
||||||
// AI Tools
|
// AI Tools
|
||||||
{ name: "Remove Background", description: "AI-powered background removal", category: "ai" },
|
{
|
||||||
{ name: "Image Upscaling", description: "AI super-resolution enhancement", category: "ai" },
|
name: "Remove Background",
|
||||||
{ name: "Object Eraser", description: "Remove unwanted objects with AI", category: "ai" },
|
description: "AI-powered background removal",
|
||||||
{ name: "OCR / Text Extraction", description: "Extract text from images", category: "ai" },
|
category: "ai",
|
||||||
|
icon: Eraser,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Image Upscaling",
|
||||||
|
description: "AI super-resolution enhancement",
|
||||||
|
category: "ai",
|
||||||
|
icon: ZoomIn,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Object Eraser",
|
||||||
|
description: "Remove unwanted objects with AI",
|
||||||
|
category: "ai",
|
||||||
|
icon: Wand2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OCR / Text Extraction",
|
||||||
|
description: "Extract text from images",
|
||||||
|
category: "ai",
|
||||||
|
icon: ScanText,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Face / PII Blur",
|
name: "Face / PII Blur",
|
||||||
description: "Auto-detect and blur faces and sensitive info",
|
description: "Auto-detect and blur faces and sensitive info",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: EyeOff,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Smart Crop",
|
name: "Smart Crop",
|
||||||
description: "Smart subject, face, or trim-based cropping",
|
description: "Smart subject, face, or trim-based cropping",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: Scan,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Image Enhancement",
|
name: "Image Enhancement",
|
||||||
description: "One-click auto-improve with smart analysis",
|
description: "One-click auto-improve with smart analysis",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: Sparkles,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Face Enhancement",
|
||||||
|
description: "Restore and enhance faces with AI",
|
||||||
|
category: "ai",
|
||||||
|
icon: ScanFace,
|
||||||
},
|
},
|
||||||
{ name: "Face Enhancement", description: "Restore and enhance faces with AI", category: "ai" },
|
|
||||||
{
|
{
|
||||||
name: "AI Colorization",
|
name: "AI Colorization",
|
||||||
description: "Convert B&W photos to full color with AI",
|
description: "Convert B&W photos to full color with AI",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: Palette,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Noise Removal",
|
||||||
|
description: "AI-powered noise and grain removal",
|
||||||
|
category: "ai",
|
||||||
|
icon: AudioLines,
|
||||||
},
|
},
|
||||||
{ name: "Noise Removal", description: "AI-powered noise and grain removal", category: "ai" },
|
|
||||||
{
|
{
|
||||||
name: "Red Eye Removal",
|
name: "Red Eye Removal",
|
||||||
description: "AI-detect and fix red eye in flash photos",
|
description: "AI-detect and fix red eye in flash photos",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: Eye,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Photo Restoration",
|
name: "Photo Restoration",
|
||||||
description: "Fix scratches, tears, and damage on old photos with AI",
|
description: "Fix scratches, tears, and damage on old photos with AI",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: Undo2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Passport Photo",
|
name: "Passport Photo",
|
||||||
description: "AI-powered passport and ID photo generator",
|
description: "AI-powered passport and ID photo generator",
|
||||||
category: "ai",
|
category: "ai",
|
||||||
|
icon: UserCheck,
|
||||||
},
|
},
|
||||||
// Watermark & Overlay
|
// Watermark & Overlay
|
||||||
{ name: "Text Watermark", description: "Add text watermark overlay", category: "watermark" },
|
{
|
||||||
{ name: "Image Watermark", description: "Overlay a logo as watermark", category: "watermark" },
|
name: "Text Watermark",
|
||||||
{ name: "Text Overlay", description: "Add styled text to images", category: "watermark" },
|
description: "Add text watermark overlay",
|
||||||
|
category: "watermark",
|
||||||
|
icon: Type,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Image Watermark",
|
||||||
|
description: "Overlay a logo as watermark",
|
||||||
|
category: "watermark",
|
||||||
|
icon: ImagePlus,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Text Overlay",
|
||||||
|
description: "Add styled text to images",
|
||||||
|
category: "watermark",
|
||||||
|
icon: TextCursorInput,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Image Composition",
|
name: "Image Composition",
|
||||||
description: "Layer images with position and opacity",
|
description: "Layer images with position and opacity",
|
||||||
category: "watermark",
|
category: "watermark",
|
||||||
|
icon: Layers,
|
||||||
},
|
},
|
||||||
// Utilities
|
// Utilities
|
||||||
{
|
{
|
||||||
name: "Image Info",
|
name: "Image Info",
|
||||||
description: "View all metadata and image properties",
|
description: "View all metadata and image properties",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: Info,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Image Compare",
|
name: "Image Compare",
|
||||||
description: "Side-by-side comparison of two images",
|
description: "Side-by-side comparison of two images",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: Columns2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Find Duplicates",
|
name: "Find Duplicates",
|
||||||
description: "Detect duplicate and near-duplicate images",
|
description: "Detect duplicate and near-duplicate images",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: Copy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Color Palette",
|
name: "Color Palette",
|
||||||
description: "Extract dominant colors from image",
|
description: "Extract dominant colors from image",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: Palette,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "QR Code Generator",
|
name: "QR Code Generator",
|
||||||
description: "Generate styled QR codes with custom colors, patterns, and logos",
|
description: "Generate styled QR codes with custom colors, patterns, and logos",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: QrCode,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Barcode Reader",
|
name: "Barcode Reader",
|
||||||
description: "Scan images for QR codes, barcodes, and 2D codes",
|
description: "Scan images for QR codes, barcodes, and 2D codes",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: ScanLine,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Image to Base64",
|
name: "Image to Base64",
|
||||||
description: "Convert images to base64 strings for embedding in HTML, CSS, and more",
|
description: "Convert images to base64 strings for embedding in HTML, CSS, and more",
|
||||||
category: "utilities",
|
category: "utilities",
|
||||||
|
icon: Code,
|
||||||
},
|
},
|
||||||
// Layout & Composition
|
// Layout & Composition
|
||||||
{
|
{
|
||||||
name: "Collage / Grid",
|
name: "Collage / Grid",
|
||||||
description: "Combine images into beautiful grid collages with 25+ templates",
|
description: "Combine images into beautiful grid collages with 25+ templates",
|
||||||
category: "layout",
|
category: "layout",
|
||||||
|
icon: LayoutGrid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Stitch / Combine",
|
name: "Stitch / Combine",
|
||||||
description: "Join images side by side, stacked, or in a grid",
|
description: "Join images side by side, stacked, or in a grid",
|
||||||
category: "layout",
|
category: "layout",
|
||||||
|
icon: Columns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Image Splitting",
|
name: "Image Splitting",
|
||||||
description: "Split images into grid tiles or by pixel size with live preview",
|
description: "Split images into grid tiles or by pixel size with live preview",
|
||||||
category: "layout",
|
category: "layout",
|
||||||
|
icon: Grid3x3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Border & Frame",
|
name: "Border & Frame",
|
||||||
description: "Add borders, rounded corners, shadows",
|
description: "Add borders, rounded corners, shadows",
|
||||||
category: "layout",
|
category: "layout",
|
||||||
|
icon: Frame,
|
||||||
},
|
},
|
||||||
// Format & Conversion
|
// Format & Conversion
|
||||||
{
|
{
|
||||||
name: "SVG to Raster",
|
name: "SVG to Raster",
|
||||||
description: "Convert SVG to PNG, JPEG, WebP, AVIF, TIFF, GIF, or HEIF at custom scale and DPI",
|
description: "Convert SVG to PNG, JPEG, WebP, AVIF, TIFF, GIF, or HEIF at custom scale and DPI",
|
||||||
category: "format",
|
category: "format",
|
||||||
|
icon: FileImage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Image to SVG",
|
||||||
|
description: "Vectorize images using tracing",
|
||||||
|
category: "format",
|
||||||
|
icon: PenTool,
|
||||||
},
|
},
|
||||||
{ name: "Image to SVG", description: "Vectorize images using tracing", category: "format" },
|
|
||||||
{
|
{
|
||||||
name: "GIF Tools",
|
name: "GIF Tools",
|
||||||
description:
|
description:
|
||||||
"Resize, optimize, change speed, reverse, extract frames, and rotate animated GIFs",
|
"Resize, optimize, change speed, reverse, extract frames, and rotate animated GIFs",
|
||||||
category: "format",
|
category: "format",
|
||||||
|
icon: Film,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PDF to Image",
|
||||||
|
description: "Convert PDF pages to images",
|
||||||
|
category: "format",
|
||||||
|
icon: FileOutput,
|
||||||
},
|
},
|
||||||
{ name: "PDF to Image", description: "Convert PDF pages to images", category: "format" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const categoryMap = new Map(categories.map((c) => [c.id, c]));
|
const categoryMap = new Map(categories.map((c) => [c.id, c]));
|
||||||
@@ -298,27 +439,30 @@ export function BentoGrid() {
|
|||||||
|
|
||||||
{/* Tool grid */}
|
{/* Tool grid */}
|
||||||
{filtered.length > 0 ? (
|
{filtered.length > 0 ? (
|
||||||
<div className="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="mt-8 grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5">
|
||||||
{filtered.map((tool) => {
|
{filtered.map((tool) => {
|
||||||
const cat = categoryMap.get(tool.category);
|
const cat = categoryMap.get(tool.category);
|
||||||
|
const Icon = tool.icon;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={tool.name}
|
key={tool.name}
|
||||||
className="rounded-xl border border-border bg-background p-5 transition-shadow hover:shadow-md"
|
className="tool-card flex flex-col items-center rounded-xl border border-border bg-background-alt px-4 py-6 text-center transition-all hover:shadow-md"
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"--cat-color": cat?.color,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<Icon size={30} style={{ color: cat?.color }} className="mb-3 shrink-0" />
|
||||||
<span
|
<div className="flex items-center justify-center gap-1.5">
|
||||||
className="inline-block h-2.5 w-2.5 shrink-0 rounded-full"
|
<span className="font-bold text-sm">{tool.name}</span>
|
||||||
style={{ backgroundColor: cat?.color }}
|
|
||||||
/>
|
|
||||||
<span className="font-semibold">{tool.name}</span>
|
|
||||||
{tool.category === "ai" && (
|
{tool.category === "ai" && (
|
||||||
<span className="rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-bold leading-none text-amber-700">
|
<span className="rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-bold leading-none text-amber-700">
|
||||||
AI
|
AI
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-sm leading-relaxed text-muted">{tool.description}</p>
|
<p className="mt-1.5 text-xs leading-relaxed text-muted">{tool.description}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -13,3 +13,8 @@
|
|||||||
--color-dark-fg: #fafaf9;
|
--color-dark-fg: #fafaf9;
|
||||||
--color-dark-muted: #a8a29e;
|
--color-dark-muted: #a8a29e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tool card hover border uses --cat-color set inline */
|
||||||
|
.tool-card:hover {
|
||||||
|
border-color: var(--cat-color);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user