import { CATEGORIES, PYTHON_SIDECAR_TOOLS, TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared"; import { Clock, Download, Loader2 } from "lucide-react"; import { useCallback, useEffect, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { ImageViewer } from "@/components/common/image-viewer"; import { MultiImageViewer } from "@/components/common/multi-image-viewer"; import { AppLayout } from "@/components/layout/app-layout"; import { ICON_MAP } from "@/lib/icon-map"; import { useFeaturesStore } from "@/stores/features-store"; import { useFileStore } from "@/stores/file-store"; import { useSettingsStore } from "@/stores/settings-store"; // Tools shown prominently as "quick actions" at the top const QUICK_ACTION_IDS = ["resize", "compress", "convert", "remove-background"]; let hasAppliedDefaultRedirect = false; export function HomePage() { const { setFiles, files, reset, originalBlobUrl, selectedFileName, selectedFileSize, currentEntry, } = useFileStore(); const navigate = useNavigate(); const { fetch: fetchSettings, defaultToolView, loaded: settingsLoaded } = useSettingsStore(); const { fetch: fetchFeatures, bundles, installing, queued } = useFeaturesStore(); useEffect(() => { reset(); }, [reset]); useEffect(() => { fetchSettings(); fetchFeatures(); }, [fetchSettings, fetchFeatures]); useEffect(() => { if ( !hasAppliedDefaultRedirect && settingsLoaded && defaultToolView === "fullscreen" && files.length === 0 ) { hasAppliedDefaultRedirect = true; navigate("/fullscreen", { replace: true }); } }, [settingsLoaded, defaultToolView, files.length, navigate]); const getToolStatus = useMemo(() => { return (toolId: string) => { const isAi = (PYTHON_SIDECAR_TOOLS as readonly string[]).includes(toolId); if (!isAi) return "installed"; const bundleId = TOOL_BUNDLE_MAP[toolId]; if (!bundleId) return "installed"; if (queued.includes(bundleId)) return "queued"; if (installing[bundleId]) return "installing"; const bundle = bundles.find((b) => b.id === bundleId); return bundle?.status === "installed" ? "installed" : "not_installed"; }; }, [bundles, installing, queued]); const handleFiles = useCallback( (newFiles: File[]) => { reset(); setFiles(newFiles); }, [setFiles, reset], ); const hasFile = files.length > 0; // If no file uploaded, show default layout (tool panel + dropzone) if (!hasFile) { return ; } // File uploaded — show tool selector on left, image preview on right return (
{/* Left panel: Tool selector */}
{/* File info */}
{selectedFileName ?? files[0].name}

{selectedFileSize ? `${(selectedFileSize / 1024).toFixed(1)} KB` : ""} {files.length > 1 && ` — ${files.length} files`}

{/* Quick actions */}

Quick Actions

{QUICK_ACTION_IDS.map((id) => { const tool = TOOLS.find((t) => t.id === id); if (!tool) return null; const Icon = (ICON_MAP[tool.icon] as React.ComponentType<{ className?: string }>) ?? ICON_MAP.FileImage; const status = getToolStatus(id); return ( ); })}
{/* All tools by category */}

All Tools

{CATEGORIES.map((category) => { const categoryTools = TOOLS.filter((t) => t.category === category.id); if (categoryTools.length === 0) return null; return (

{category.name}

{categoryTools.map((tool) => { const Icon = (ICON_MAP[tool.icon] as React.ComponentType<{ className?: string }>) ?? ICON_MAP.FileImage; const status = getToolStatus(tool.id); return ( ); })}
); })}
{/* Right panel: Image preview */}
{files.length > 1 ? ( ) : currentEntry?.previewLoading ? (

Generating preview...

{selectedFileName}

) : originalBlobUrl ? ( ) : (

Loading preview...

)}
); }