import { Download, Loader2 } from "lucide-react"; import { useState } from "react"; import { useFileStore } from "@/stores/file-store"; function getToken(): string { return localStorage.getItem("stirling-token") || ""; } const SIZES = [ { name: "favicon-16x16.png", size: "16x16" }, { name: "favicon-32x32.png", size: "32x32" }, { name: "favicon-48x48.png", size: "48x48" }, { name: "apple-touch-icon.png", size: "180x180" }, { name: "android-chrome-192x192.png", size: "192x192" }, { name: "android-chrome-512x512.png", size: "512x512" }, { name: "favicon.ico", size: "32x32" }, ]; export function FaviconSettings() { const { files, processing, error, setProcessing, setError } = useFileStore(); const [downloadReady, setDownloadReady] = useState(false); const handleProcess = async () => { if (files.length === 0) return; setProcessing(true); setError(null); setDownloadReady(false); try { const formData = new FormData(); formData.append("file", files[0]); const res = await fetch("/api/v1/tools/favicon", { method: "POST", headers: { Authorization: `Bearer ${getToken()}` }, body: formData, }); if (!res.ok) { const text = await res.text(); throw new Error(text || `Failed: ${res.status}`); } const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "favicons.zip"; a.click(); URL.revokeObjectURL(url); setDownloadReady(true); } catch (err) { setError(err instanceof Error ? err.message : "Generation failed"); } finally { setProcessing(false); } }; const hasFile = files.length > 0; return (
Upload a square image (recommended 512x512 or larger) to generate all favicon and app icon sizes.
Generated Sizes
+ manifest.json + HTML snippet
{error}
} {downloadReady && (