;
@@ -26,32 +64,23 @@ interface PipelineStepSettingsProps {
}
export function PipelineStepSettings({ toolId, settings, onChange }: PipelineStepSettingsProps) {
- if (toolId === "resize") return ;
- if (toolId === "crop") return ;
- if (toolId === "rotate") return ;
- if (toolId === "convert") return ;
- if (toolId === "compress") return ;
- if (toolId === "strip-metadata")
- return ;
- if (toolId === "border") return ;
- if (toolId === "watermark-text")
- return ;
- if (toolId === "text-overlay")
- return ;
- if (toolId === "replace-color")
- return ;
- if (toolId === "smart-crop") return ;
- if (toolId === "gif-tools") return ;
- if (toolId === "upscale") return ;
- if (toolId === "blur-faces") return ;
- if (toolId === "enhance-faces")
- return ;
- if (toolId === "remove-background")
- return ;
- if (toolId === "noise-removal")
- return ;
- if (COLOR_TOOL_IDS.has(toolId))
- return ;
+ const Control = CONTROLS[toolId];
+
+ if (Control) {
+ return (
+
+
+
+ );
+ }
+
+ if (COLOR_TOOL_IDS.has(toolId)) {
+ return (
+
+
+
+ );
+ }
return (
diff --git a/apps/web/src/components/tools/remove-bg-settings.tsx b/apps/web/src/components/tools/remove-bg-settings.tsx
index b01ddb59..6e3a90b8 100644
--- a/apps/web/src/components/tools/remove-bg-settings.tsx
+++ b/apps/web/src/components/tools/remove-bg-settings.tsx
@@ -10,6 +10,7 @@ import {
import { useEffect, useRef, useState } from "react";
import { ProgressCard } from "@/components/common/progress-card";
import { useToolProcessor } from "@/hooks/use-tool-processor";
+import { formatHeaders } from "@/lib/api";
import { useFileStore } from "@/stores/file-store";
type SubjectType = "people" | "products" | "general";
@@ -565,22 +566,20 @@ export function RemoveBgSettings({ onBgPreview }: RemoveBgSettingsProps = {}) {
// Decode HEIC via server preview endpoint
const formData = new FormData();
formData.append("file", file);
- import("@/lib/api").then(({ formatHeaders }) => {
- fetch("/api/v1/preview", {
- method: "POST",
- headers: formatHeaders(),
- body: formData,
+ fetch("/api/v1/preview", {
+ method: "POST",
+ headers: formatHeaders(),
+ body: formData,
+ })
+ .then((res) => (res.ok ? res.blob() : null))
+ .then((blob) => {
+ if (blob && bgImageFileRef.current === file) {
+ const url = URL.createObjectURL(blob);
+ revoke = () => URL.revokeObjectURL(url);
+ setBgImageBlobUrl(url);
+ }
})
- .then((res) => (res.ok ? res.blob() : null))
- .then((blob) => {
- if (blob && bgImageFileRef.current === file) {
- const url = URL.createObjectURL(blob);
- revoke = () => URL.revokeObjectURL(url);
- setBgImageBlobUrl(url);
- }
- })
- .catch(() => {});
- });
+ .catch(() => {});
} else {
const url = URL.createObjectURL(file);
revoke = () => URL.revokeObjectURL(url);
@@ -744,7 +743,7 @@ export function RemoveBgSettings({ onBgPreview }: RemoveBgSettingsProps = {}) {
formData.append("backgroundImage", bgImageFile);
}
- const headers = (await import("@/lib/api")).formatHeaders();
+ const headers = formatHeaders();
const response = await fetch("/api/v1/tools/remove-background/effects", {
method: "POST",
headers,
diff --git a/apps/web/src/lib/icon-map.ts b/apps/web/src/lib/icon-map.ts
new file mode 100644
index 00000000..9e049918
--- /dev/null
+++ b/apps/web/src/lib/icon-map.ts
@@ -0,0 +1,106 @@
+import type { LucideIcon } from "lucide-react";
+import {
+ CheckCircle2,
+ Code,
+ Columns,
+ Columns2,
+ Copy,
+ Crop,
+ Eraser,
+ Eye,
+ EyeOff,
+ FileEdit,
+ FileImage,
+ FileOutput,
+ FileText,
+ FileType,
+ Film,
+ Focus,
+ FolderInput,
+ Frame,
+ Globe,
+ Grid3x3,
+ Image,
+ Info,
+ Layers,
+ LayoutGrid,
+ Maximize2,
+ Minimize2,
+ Palette,
+ PenLine,
+ PenTool,
+ Pipette,
+ QrCode,
+ RotateCw,
+ ScanFace,
+ ScanLine,
+ ScanText,
+ ShieldOff,
+ SlidersHorizontal,
+ Sparkles,
+ Stamp,
+ Star,
+ TextCursorInput,
+ Type,
+ Undo2,
+ UserCheck,
+ Wand2,
+ Workflow,
+ Wrench,
+ Zap,
+ ZoomIn,
+} from "lucide-react";
+
+// Only the icons actually used by tool definitions in @ashim/shared constants.
+// Avoids `import * as icons from "lucide-react"` which pulls the entire 1000+ icon library.
+export const ICON_MAP: Record = {
+ CheckCircle2,
+ Code,
+ Columns,
+ Columns2,
+ Copy,
+ Crop,
+ Eraser,
+ Eye,
+ EyeOff,
+ FileEdit,
+ FileImage,
+ FileOutput,
+ FileText,
+ FileType,
+ Film,
+ Focus,
+ FolderInput,
+ Frame,
+ Globe,
+ Grid3x3,
+ Image,
+ Info,
+ LayoutGrid,
+ Layers,
+ Maximize2,
+ Minimize2,
+ Palette,
+ PenLine,
+ PenTool,
+ Pipette,
+ QrCode,
+ RotateCw,
+ ScanFace,
+ ScanLine,
+ ScanText,
+ ShieldOff,
+ SlidersHorizontal,
+ Sparkles,
+ Stamp,
+ Star,
+ TextCursorInput,
+ Type,
+ Undo2,
+ UserCheck,
+ Wand2,
+ Workflow,
+ Wrench,
+ Zap,
+ ZoomIn,
+};
diff --git a/apps/web/src/pages/fullscreen-grid-page.tsx b/apps/web/src/pages/fullscreen-grid-page.tsx
index 54c9f47b..dcca7ff7 100644
--- a/apps/web/src/pages/fullscreen-grid-page.tsx
+++ b/apps/web/src/pages/fullscreen-grid-page.tsx
@@ -1,11 +1,11 @@
import type { CategoryInfo, Tool } from "@ashim/shared";
import { CATEGORIES, TOOLS } from "@ashim/shared";
-import * as icons from "lucide-react";
import { Eye, EyeOff, FileImage, LayoutGrid, List, Search } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { GemLogo } from "@/components/common/gem-logo";
import { apiGet } from "@/lib/api";
+import { ICON_MAP } from "@/lib/icon-map";
import { cn } from "@/lib/utils";
export function FullscreenGridPage() {
@@ -57,8 +57,6 @@ export function FullscreenGridPage() {
const activeCategories = CATEGORIES.filter((cat) => groupedTools.has(cat.id));
- const iconsMap = icons as unknown as Record>;
-
return (
{/* Top bar */}
@@ -130,7 +128,6 @@ export function FullscreenGridPage() {
category={category}
tools={groupedTools.get(category.id) || []}
showDetails={showDetails}
- iconsMap={iconsMap}
/>
))}
@@ -144,14 +141,13 @@ function CategoryCard({
category,
tools,
showDetails,
- iconsMap,
}: {
category: CategoryInfo;
tools: Tool[];
showDetails: boolean;
- iconsMap: Record>;
}) {
- const CategoryIcon = iconsMap[category.icon] || LayoutGrid;
+ const CategoryIcon =
+ (ICON_MAP[category.icon] as React.ComponentType<{ className?: string }>) ?? LayoutGrid;
return (
@@ -183,7 +179,8 @@ function CategoryCard({
{/* Tool list */}
{tools.map((tool) => {
- const ToolIcon = iconsMap[tool.icon] || FileImage;
+ const ToolIcon =
+ (ICON_MAP[tool.icon] as React.ComponentType<{ className?: string }>) ?? FileImage;
return (
-
+
{selectedFileName ?? files[0].name}
@@ -81,9 +81,8 @@ export function HomePage() {
const tool = TOOLS.find((t) => t.id === id);
if (!tool) return null;
const Icon =
- (icons as unknown as Record>)[
- tool.icon
- ] || icons.FileImage;
+ (ICON_MAP[tool.icon] as React.ComponentType<{ className?: string }>) ??
+ ICON_MAP.FileImage;
return (