feat: wire up batch processing across tool settings components

This commit is contained in:
Siddharth Kumar Sah
2026-03-23 14:11:08 +08:00
parent 846a51a9fd
commit 9e2c28f191
10 changed files with 80 additions and 33 deletions
@@ -6,7 +6,7 @@ import { ProgressCard } from "@/components/common/progress-card";
export function BorderSettings() { export function BorderSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("border"); useToolProcessor("border");
const [borderWidth, setBorderWidth] = useState(10); const [borderWidth, setBorderWidth] = useState(10);
@@ -16,7 +16,12 @@ export function BorderSettings() {
const [shadowBlur, setShadowBlur] = useState(0); const [shadowBlur, setShadowBlur] = useState(0);
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { borderWidth, borderColor, cornerRadius, padding, shadowBlur }); const settings = { borderWidth, borderColor, cornerRadius, padding, shadowBlur };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -84,7 +89,7 @@ export function BorderSettings() {
disabled={!hasFile || processing} disabled={!hasFile || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Add Border {files.length > 1 ? `Apply Border (${files.length} files)` : "Apply Border"}
</button> </button>
)} )}
@@ -14,7 +14,7 @@ interface ColorSettingsProps {
export function ColorSettings({ toolId }: ColorSettingsProps) { export function ColorSettings({ toolId }: ColorSettingsProps) {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor(toolId); useToolProcessor(toolId);
const [tab, setTab] = useState<Tab>(() => { const [tab, setTab] = useState<Tab>(() => {
@@ -37,7 +37,7 @@ export function ColorSettings({ toolId }: ColorSettingsProps) {
const [effect, setEffect] = useState<Effect>("none"); const [effect, setEffect] = useState<Effect>("none");
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { const settings = {
brightness, brightness,
contrast, contrast,
saturation, saturation,
@@ -45,7 +45,12 @@ export function ColorSettings({ toolId }: ColorSettingsProps) {
green, green,
blue, blue,
effect, effect,
}); };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -215,7 +220,7 @@ export function ColorSettings({ toolId }: ColorSettingsProps) {
disabled={!hasFile || !hasChanges || processing} disabled={!hasFile || !hasChanges || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Apply {files.length > 1 ? `Apply (${files.length} files)` : "Apply"}
</button> </button>
)} )}
@@ -8,7 +8,7 @@ type CompressMode = "quality" | "targetSize";
export function CompressSettings() { export function CompressSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("compress"); useToolProcessor("compress");
const [mode, setMode] = useState<CompressMode>("quality"); const [mode, setMode] = useState<CompressMode>("quality");
@@ -22,7 +22,11 @@ export function CompressSettings() {
} else { } else {
settings.targetSizeKb = Number(targetSizeKb); settings.targetSizeKb = Number(targetSizeKb);
} }
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings); processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -124,7 +128,7 @@ export function CompressSettings() {
disabled={!hasFile || !canProcess || processing} disabled={!hasFile || !canProcess || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Compress {files.length > 1 ? `Compress (${files.length} files)` : "Compress"}
</button> </button>
)} )}
@@ -9,7 +9,7 @@ const LOSSY_FORMATS = new Set(["jpg", "webp", "avif"]);
export function ConvertSettings() { export function ConvertSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("convert"); useToolProcessor("convert");
const [format, setFormat] = useState<string>("png"); const [format, setFormat] = useState<string>("png");
@@ -28,7 +28,11 @@ export function ConvertSettings() {
if (isLossy) { if (isLossy) {
settings.quality = quality; settings.quality = quality;
} }
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings); processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -118,7 +122,7 @@ export function ConvertSettings() {
disabled={!hasFile || processing} disabled={!hasFile || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Convert {files.length > 1 ? `Convert (${files.length} files)` : "Convert"}
</button> </button>
)} )}
@@ -14,7 +14,7 @@ const ASPECT_PRESETS = [
export function CropSettings() { export function CropSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("crop"); useToolProcessor("crop");
const [left, setLeft] = useState("0"); const [left, setLeft] = useState("0");
@@ -31,12 +31,17 @@ export function CropSettings() {
}; };
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { const settings = {
left: Number(left), left: Number(left),
top: Number(top), top: Number(top),
width: Number(width), width: Number(width),
height: Number(height), height: Number(height),
}); };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -141,7 +146,7 @@ export function CropSettings() {
disabled={!hasFile || !hasSize || processing} disabled={!hasFile || !hasSize || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Crop {files.length > 1 ? `Crop (${files.length} files)` : "Crop"}
</button> </button>
)} )}
@@ -6,7 +6,7 @@ import { ProgressCard } from "@/components/common/progress-card";
export function ReplaceColorSettings() { export function ReplaceColorSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("replace-color"); useToolProcessor("replace-color");
const [sourceColor, setSourceColor] = useState("#FF0000"); const [sourceColor, setSourceColor] = useState("#FF0000");
@@ -15,7 +15,12 @@ export function ReplaceColorSettings() {
const [tolerance, setTolerance] = useState(30); const [tolerance, setTolerance] = useState(30);
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { sourceColor, targetColor, makeTransparent, tolerance }); const settings = { sourceColor, targetColor, makeTransparent, tolerance };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -81,7 +86,7 @@ export function ReplaceColorSettings() {
disabled={!hasFile || processing} disabled={!hasFile || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Replace Color {files.length > 1 ? `Replace Color (${files.length} files)` : "Replace Color"}
</button> </button>
)} )}
@@ -19,7 +19,7 @@ const platforms = [...new Set(SOCIAL_MEDIA_PRESETS.map((p) => p.platform))];
export function ResizeSettings() { export function ResizeSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, progress } =
useToolProcessor("resize"); useToolProcessor("resize");
const [tab, setTab] = useState<ResizeTab>("presets"); const [tab, setTab] = useState<ResizeTab>("presets");
@@ -56,7 +56,11 @@ export function ResizeSettings() {
settings.withoutEnlargement = withoutEnlargement; settings.withoutEnlargement = withoutEnlargement;
} }
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings); processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -252,7 +256,7 @@ export function ResizeSettings() {
disabled={!canProcess} disabled={!canProcess}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Resize {files.length > 1 ? `Resize (${files.length} files)` : "Resize"}
</button> </button>
)} )}
@@ -22,7 +22,7 @@ interface RotateSettingsProps {
export function RotateSettings({ onPreviewTransform }: RotateSettingsProps) { export function RotateSettings({ onPreviewTransform }: RotateSettingsProps) {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, progress } =
useToolProcessor("rotate"); useToolProcessor("rotate");
const [angle, setAngle] = useState(0); const [angle, setAngle] = useState(0);
@@ -38,11 +38,16 @@ export function RotateSettings({ onPreviewTransform }: RotateSettingsProps) {
const rotateRight = () => setAngle((a) => (a + 90) % 360); const rotateRight = () => setAngle((a) => (a + 90) % 360);
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { const settings = {
angle, angle,
horizontal: flipH, horizontal: flipH,
vertical: flipV, vertical: flipV,
}); };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -144,7 +149,7 @@ export function RotateSettings({ onPreviewTransform }: RotateSettingsProps) {
disabled={!hasFile || !hasChanges || processing} disabled={!hasFile || !hasChanges || processing}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Apply {files.length > 1 ? `Apply (${files.length} files)` : "Apply"}
</button> </button>
)} )}
@@ -6,7 +6,7 @@ import { ProgressCard } from "@/components/common/progress-card";
export function TextOverlaySettings() { export function TextOverlaySettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("text-overlay"); useToolProcessor("text-overlay");
const [text, setText] = useState("Your Text Here"); const [text, setText] = useState("Your Text Here");
@@ -18,7 +18,12 @@ export function TextOverlaySettings() {
const [shadow, setShadow] = useState(true); const [shadow, setShadow] = useState(true);
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { text, fontSize, color, position, backgroundBox, backgroundColor, shadow }); const settings = { text, fontSize, color, position, backgroundBox, backgroundColor, shadow };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -102,7 +107,7 @@ export function TextOverlaySettings() {
disabled={!hasFile || processing || !text} disabled={!hasFile || processing || !text}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Add Text {files.length > 1 ? `Apply Overlay (${files.length} files)` : "Apply Overlay"}
</button> </button>
)} )}
@@ -8,7 +8,7 @@ type Position = "center" | "top-left" | "top-right" | "bottom-left" | "bottom-ri
export function WatermarkTextSettings() { export function WatermarkTextSettings() {
const { files } = useFileStore(); const { files } = useFileStore();
const { processFiles, processing, error, downloadUrl, originalSize, processedSize, progress } = const { processFiles, processAllFiles, processing, error, downloadUrl, originalSize, processedSize, progress } =
useToolProcessor("watermark-text"); useToolProcessor("watermark-text");
const [text, setText] = useState("Sample Watermark"); const [text, setText] = useState("Sample Watermark");
@@ -19,7 +19,12 @@ export function WatermarkTextSettings() {
const [rotation, setRotation] = useState(0); const [rotation, setRotation] = useState(0);
const handleProcess = () => { const handleProcess = () => {
processFiles(files, { text, fontSize, color, opacity, position, rotation }); const settings = { text, fontSize, color, opacity, position, rotation };
if (files.length > 1) {
processAllFiles(files, settings);
} else {
processFiles(files, settings);
}
}; };
const hasFile = files.length > 0; const hasFile = files.length > 0;
@@ -106,7 +111,7 @@ export function WatermarkTextSettings() {
disabled={!hasFile || processing || !text} disabled={!hasFile || processing || !text}
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2" className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
> >
Add Watermark {files.length > 1 ? `Apply Watermark (${files.length} files)` : "Apply Watermark"}
</button> </button>
)} )}