import React, { useState, useCallback } from 'react'; import { Image, Trash2 } from 'lucide-react'; import { CompressionOptions } from './components/CompressionOptions'; import { DropZone } from './components/DropZone'; import { ImageList } from './components/ImageList'; import { DownloadAll } from './components/DownloadAll'; import { useImageQueue } from './hooks/useImageQueue'; import { DEFAULT_QUALITY_SETTINGS } from './utils/formatDefaults'; import type { ImageFile, OutputType, CompressionOptions as CompressionOptionsType } from './types'; export function App() { const [images, setImages] = useState([]); const [outputType, setOutputType] = useState('webp'); const [options, setOptions] = useState({ quality: DEFAULT_QUALITY_SETTINGS.webp, }); const { addToQueue } = useImageQueue(options, outputType, setImages); const handleOutputTypeChange = useCallback((type: OutputType) => { setOutputType(type); if (type !== 'png') { setOptions({ quality: DEFAULT_QUALITY_SETTINGS[type] }); } }, []); const handleFilesDrop = useCallback((newImages: ImageFile[]) => { // First add all images to state setImages((prev) => [...prev, ...newImages]); // Use requestAnimationFrame to wait for render to complete requestAnimationFrame(() => { // Then add to queue after UI has updated newImages.forEach(image => addToQueue(image.id)); }); }, [addToQueue]); const handleRemoveImage = useCallback((id: string) => { setImages((prev) => { const image = prev.find(img => img.id === id); if (image?.preview) { URL.revokeObjectURL(image.preview); } return prev.filter(img => img.id !== id); }); }, []); const handleClearAll = useCallback(() => { images.forEach(image => { if (image.preview) { URL.revokeObjectURL(image.preview); } }); setImages([]); }, [images]); const handleDownloadAll = useCallback(async () => { const completedImages = images.filter((img) => img.status === "complete"); for (const image of completedImages) { if (image.blob && image.outputType) { const link = document.createElement("a"); link.href = URL.createObjectURL(image.blob); link.download = `${image.file.name.split(".")[0]}.${image.outputType}`; link.click(); URL.revokeObjectURL(link.href); } await new Promise((resolve) => setTimeout(resolve, 100)); } }, [images]); const completedImages = images.filter(img => img.status === 'complete').length; return (

Squish

Compress and convert your images to AVIF, JPEG, JPEG XL, PNG, or WebP

{completedImages > 0 && ( )} {images.length > 0 && ( )}
); }