import { Check, ClipboardCopy, Download, FileJson, FileText, Loader2 } from "lucide-react"; import { useCallback, useState } from "react"; import type { Base64Result } from "@/stores/base64-store"; import { useBase64Store } from "@/stores/base64-store"; import { useFileStore } from "@/stores/file-store"; // -- Snippet generators ----------------------------------------------------- type TabId = "datauri" | "raw" | "html" | "css" | "json" | "markdown"; interface Tab { id: TabId; label: string; generate: (r: Base64Result) => string; } const TABS: Tab[] = [ { id: "datauri", label: "Data URI", generate: (r) => r.dataUri }, { id: "raw", label: "Raw Base64", generate: (r) => r.base64 }, { id: "html", label: "HTML", generate: (r) => { const alt = r.filename.replace(/\.[^.]+$/, ""); return `${alt}`; }, }, { id: "css", label: "CSS", generate: (r) => `background-image: url(${r.dataUri});`, }, { id: "json", label: "JSON", generate: (r) => JSON.stringify({ image: r.dataUri }, null, 2), }, { id: "markdown", label: "Markdown", generate: (r) => { const alt = r.filename.replace(/\.[^.]+$/, ""); return `![${alt}](${r.dataUri})`; }, }, ]; // -- Helpers ---------------------------------------------------------------- function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } function downloadFile(content: string, filename: string, type: string) { const blob = new Blob([content], { type }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } // -- CopyButton ------------------------------------------------------------- function CopyButton({ text, label }: { text: string; label?: string }) { const [copied, setCopied] = useState(false); const handleCopy = useCallback(async () => { await navigator.clipboard.writeText(text); setCopied(true); setTimeout(() => setCopied(false), 2000); }, [text]); return ( ); } // -- Single file result view ------------------------------------------------ function FileResult({ result }: { result: Base64Result }) { const [activeTab, setActiveTab] = useState("datauri"); const tab = TABS.find((t) => t.id === activeTab) ?? TABS[0]; const output = tab.generate(result); const handleDownload = useCallback(() => { const blob = new Blob([output], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${result.filename}.base64.txt`; a.click(); URL.revokeObjectURL(url); }, [output, result.filename]); return (
{/* Metadata */}
{result.filename}

{result.filename}

{result.width}x{result.height} · {formatBytes(result.originalSize)} →{" "} {formatBytes(result.encodedSize)}{" "} 50 ? "text-amber-500" : ""}> (+{result.overheadPercent}%)

{/* Tabs */}
{TABS.map((t) => ( ))}
{/* Code output */}
          {output}
        
{/* Actions */}
); } // -- Main ResultsPanel ------------------------------------------------------ export function ImageToBase64Results() { const { results, errors, processing, progress } = useBase64Store(); const { entries, selectedIndex, originalBlobUrl, selectedFileName } = useFileStore(); // -- Processing state: progress bar -- if (processing) { const pct = progress && progress.total > 0 ? Math.round((progress.completed / progress.total) * 100) : 0; return (
{progress ? ( <>

Converting{" "} {progress.currentFile}

{progress.completed} of {progress.total} files

) : (

Starting conversion...

)}
); } // -- No results yet: show preview of selected image -- if (results.length === 0 && errors.length === 0) { if (originalBlobUrl) { return (
{selectedFileName

{entries.length > 1 ? `${entries.length} files ready. Click "Convert to Base64" to start.` : `Click "Convert to Base64" to convert.`}

); } return (

Upload images and click "Convert to Base64" to get started.

); } // -- Results ready: find result for the currently selected file -- const currentFileName = entries[selectedIndex]?.file.name ?? null; const currentResult = currentFileName ? results.find((r) => r.filename === currentFileName) : null; const currentError = currentFileName ? errors.find((e) => e.filename === currentFileName) : null; const hasMultiple = entries.length > 1; return (
{/* Batch summary bar */} {hasMultiple && (

{results.length} of {entries.length} converted {errors.length > 0 ? ` - ${errors.length} failed` : ""}

r.dataUri), null, 2, )} label="Copy All as JSON" />
)} {/* Current file result */}
{currentResult ? ( ) : currentError ? (

{currentError.filename}

{currentError.error}

) : (

No result for this file. It may not have been processed yet.

)}
); }