import { Download } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { ProgressCard } from "@/components/common/progress-card"; import { useTranslation } from "@/contexts/i18n-context"; import { useToolProcessor } from "@/hooks/use-tool-processor"; import { useFileStore } from "@/stores/file-store"; export function VignetteSettings({ onImageStyle, onImageOverlay, }: { onImageStyle?: (style: React.CSSProperties | null) => void; onImageOverlay?: (node: React.ReactNode) => void; }) { const { t } = useTranslation(); const { files } = useFileStore(); const { processFiles, processAllFiles, processing, error, downloadUrl, progress } = useToolProcessor("vignette"); const [strength, setStrength] = useState(0.5); const [color, setColor] = useState("#000000"); const [radius, setRadius] = useState(70); const [softness, setSoftness] = useState(50); const [roundness, setRoundness] = useState(100); const [centerX, setCenterX] = useState(50); const [centerY, setCenterY] = useState(50); // Stable refs for the preview callbacks to avoid re-render loops const onOverlayRef = useRef(onImageOverlay); useEffect(() => { onOverlayRef.current = onImageOverlay; }); const onStyleRef = useRef(onImageStyle); useEffect(() => { onStyleRef.current = onImageStyle; }); // Live preview overlay via onImageOverlay useEffect(() => { const outerR = radius / 100; const innerStop = Math.max(0, Math.min(1, outerR * (1 - softness / 100))); const innerPct = (innerStop * 100).toFixed(1); const shape = roundness === 100 ? "circle" : "ellipse"; const gradientColor = `${color}`; const bg = `radial-gradient(${shape} at ${centerX}% ${centerY}%, transparent ${innerPct}%, ${gradientColor} ${(outerR * 100).toFixed(1)}%)`; const overlay = (
); // onImageStyle activates the wrapper branch in image-viewer so the overlay // child actually mounts; without it the overlay node is never rendered. onStyleRef.current?.({}); onOverlayRef.current?.(overlay); return () => { onStyleRef.current?.(null); onOverlayRef.current?.(null); }; }, [strength, color, radius, softness, roundness, centerX, centerY]); const handleProcess = () => { const settings = { strength, color, radius, softness, roundness, centerX, centerY }; if (files.length > 1) { processAllFiles(files, settings); } else { processFiles(files, settings); } }; const hasFile = files.length > 0; const canProcess = hasFile && !processing; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (canProcess) handleProcess(); }; return ( ); }