diff --git a/src/components/image-converter.tsx b/src/components/image-converter.tsx index 97d7d0d..a7eb76a 100644 --- a/src/components/image-converter.tsx +++ b/src/components/image-converter.tsx @@ -17,7 +17,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Upload, Download, X, Trash2, Check, ArrowRightLeft } from "lucide-react"; +import { Upload, Download, X, Trash2, Check, ArrowRightLeft, HelpCircle } from "lucide-react"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { Switch } from "@/components/ui/switch"; @@ -30,6 +30,12 @@ import { } from "@/components/ui/accordion"; import { Slider } from "@/components/ui/slider"; import { ObjectPositionControl } from "./object-position-control"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; const aspectRatios = [ { name: "Custom", value: "custom" }, @@ -359,285 +365,432 @@ export function ImageConverter() { }; return ( -
-
- - - -
-

Image Settings

-

- Adjust resolution and scaling for all images. -

-
-
- -
-
- - + +
+
+ + + +
+

Image Settings

+

+ Adjust resolution and scaling for all images. +

-
-
- - + + +
+
+ + + + + +

Choose a preset aspect ratio or select 'Custom' to enter dimensions manually.

+
+
+
- -
- - +
+
+ + + + + +

Set the output width in pixels. Leave blank to use the original width.

+
+
+ +
+ + + + + +

Swap the entered width and height values.

+
+
+
+ + + + + +

Set the output height in pixels. Leave blank to use the original height.

+
+
+ +
+
+
+ setKeepOrientation(Boolean(checked))} /> + + + + + +

Automatically swaps width and height to match the original image's orientation.

+
+
-
- setKeepOrientation(Boolean(checked))} /> - -
-
-
- - -
- {scaleMode !== 'fill' && (
- - setObjectPosition(pos)} /> -
- )} -
- - - - -
-

Filename Settings

-

Customize the output filenames.

-
-
- -
-
- - -
- {useDefaultBaseName && ( -
- -
- setDefaultBaseName(e.target.value)} - /> - -
-
- )} -
- - setPrefix(e.target.value)} /> -
-
- - setSuffix(e.target.value)} /> -
-
- - -
- {useCounter && ( -
-
- - setCounterStart(Math.max(0, Number(e.target.value)))} - min="0" - /> -
-
- - setCounterDigits(Math.max(1, Number(e.target.value)))} - min="1" - /> -
-
- )} -
-
-
- - - -
-

Quality Settings

-

Choose format and compression level.

-
-
- -
-
- - setScaleMode(value)}> + - PNG - JPEG - WEBP + Fill (stretch to fit) + Cover (crop to fit) + Contain (letterbox)
-
-
- - {quality}% + {scaleMode !== 'fill' && ( +
+ + + + + +

Sets the anchor point for 'Cover' or 'Contain' scaling.

+
+
+ setObjectPosition(pos)} />
- setQuality(value[0])} - disabled={format === 'png'} - /> - {format === 'png' && ( -

Quality slider is disabled for PNG (lossless format).

+ )} + + + + + +
+

Filename Settings

+

Customize the output filenames.

+
+
+ +
+
+ + + + + + +

When enabled, all newly uploaded images will use the specified default base name.

+
+
+
+ {useDefaultBaseName && ( +
+ +
+ setDefaultBaseName(e.target.value)} + /> + + + + + +

Apply this base name to all currently uploaded images.

+
+
+
+
+ )} +
+ + + + + +

Add text to the beginning of every filename.

+
+
+ setPrefix(e.target.value)} /> +
+
+ + + + + +

Add text to the end of every filename (before the number).

+
+
+ setSuffix(e.target.value)} /> +
+
+ + + + + + +

Append a numbered sequence to each filename.

+
+
+
+ {useCounter && ( +
+
+ + + + + +

The first number to use in the sequence.

+
+
+ setCounterStart(Math.max(0, Number(e.target.value)))} + min="0" + /> +
+
+ + + + + +

Total number of digits for the counter, padded with leading zeros (e.g., 3 for 001).

+
+
+ setCounterDigits(Math.max(1, Number(e.target.value)))} + min="1" + /> +
+
)}
-
- - - - -
+ + -
- - -
-

Upload Images

-
fileInputRef.current?.click()} - > -
- -

Click or drag and drop to upload

-

PNG, JPG, WEBP supported

+ + +
+

Quality Settings

+

Choose format and compression level.

- -
-
- - - - {hasImages && ( - - -
- Uploaded Images -
- - -
-
-
- -
- {previewUrls.map((url, index) => { - const baseFilename = generateFinalFilename(index); - const dimensionSuffix = width && height ? `_${width}x${height}` : ''; - const finalFilename = `${baseFilename}${dimensionSuffix}`; - return ( -
- {`Preview -
- - handleFilenameChange(index, e.target.value)} - className="text-sm font-medium h-8 mt-1" - /> -

- Final name: {finalFilename}.{format} -

-
-
- - -
+ + +
+
+ + + + + +

Choose the output file format for the images.

+
+
+ +
+
+
+ + + + + +

Set compression quality for JPEG/WEBP. Higher is better quality but larger file size.

+
+
+ {quality}%
- ); - })} + setQuality(value[0])} + disabled={format === 'png'} + /> + {format === 'png' && ( +

Quality slider is disabled for PNG (lossless format).

+ )} +
+
+
+ + + + + + + +

Confirm and apply all the settings above. This does not download the images.

+
+
+
+ +
+ + +
+

Upload Images

+
fileInputRef.current?.click()} + > +
+ +

Click or drag and drop to upload

+

PNG, JPG, WEBP supported

+
+ +
- )} + + {hasImages && ( + + +
+ Uploaded Images +
+ + + + + +

Remove all uploaded images.

+
+
+ + + + + +

Convert and download all images with the current settings.

+
+
+
+
+
+ +
+ {previewUrls.map((url, index) => { + const baseFilename = generateFinalFilename(index); + const dimensionSuffix = width && height ? `_${width}x${height}` : ''; + const finalFilename = `${baseFilename}${dimensionSuffix}`; + return ( +
+ {`Preview +
+ + handleFilenameChange(index, e.target.value)} + className="text-sm font-medium h-8 mt-1" + /> +

+ Final name: {finalFilename}.{format} +

+
+
+ + + + + +

Download this image

+
+
+ + + + + +

Remove this image

+
+
+
+
+ ); + })} +
+
+
+ )} +
-
+ ); } \ No newline at end of file