[dyad] Enable per-image filename editing - wrote 1 file(s)

This commit is contained in:
[dyad]
2026-01-18 11:13:32 +01:00
parent 39410d1aa1
commit db23ab08a8

View File

@@ -34,7 +34,7 @@ import {
export function ImageConverter() { export function ImageConverter() {
const [images, setImages] = useState<File[]>([]); const [images, setImages] = useState<File[]>([]);
const [previewUrls, setPreviewUrls] = useState<string[]>([]); const [previewUrls, setPreviewUrls] = useState<string[]>([]);
const [originalFilenames, setOriginalFilenames] = useState<string[]>([]); const [filenames, setFilenames] = useState<string[]>([]);
const [width, setWidth] = useState<number | string>(""); const [width, setWidth] = useState<number | string>("");
const [height, setHeight] = useState<number | string>(""); const [height, setHeight] = useState<number | string>("");
const [format, setFormat] = useState<"png" | "jpeg" | "webp">("png"); const [format, setFormat] = useState<"png" | "jpeg" | "webp">("png");
@@ -71,8 +71,8 @@ export function ImageConverter() {
...previewUrls, ...previewUrls,
...imageFiles.map((file) => URL.createObjectURL(file)), ...imageFiles.map((file) => URL.createObjectURL(file)),
]; ];
const newOriginalFilenames = [ const newFilenames = [
...originalFilenames, ...filenames,
...imageFiles.map((file) => ...imageFiles.map((file) =>
file.name.substring(0, file.name.lastIndexOf(".")) file.name.substring(0, file.name.lastIndexOf("."))
), ),
@@ -80,7 +80,7 @@ export function ImageConverter() {
setImages(newImages); setImages(newImages);
setPreviewUrls(newPreviewUrls); setPreviewUrls(newPreviewUrls);
setOriginalFilenames(newOriginalFilenames); setFilenames(newFilenames);
toast.success(`${imageFiles.length} image(s) added.`); toast.success(`${imageFiles.length} image(s) added.`);
}; };
@@ -110,28 +110,34 @@ export function ImageConverter() {
URL.revokeObjectURL(previewUrls[indexToRemove]); URL.revokeObjectURL(previewUrls[indexToRemove]);
const newImages = images.filter((_, i) => i !== indexToRemove); const newImages = images.filter((_, i) => i !== indexToRemove);
const newPreviewUrls = previewUrls.filter((_, i) => i !== indexToRemove); const newPreviewUrls = previewUrls.filter((_, i) => i !== indexToRemove);
const newOriginalFilenames = originalFilenames.filter((_, i) => i !== indexToRemove); const newFilenames = filenames.filter((_, i) => i !== indexToRemove);
setImages(newImages); setImages(newImages);
setPreviewUrls(newPreviewUrls); setPreviewUrls(newPreviewUrls);
setOriginalFilenames(newOriginalFilenames); setFilenames(newFilenames);
}; };
const handleClearAll = () => { const handleClearAll = () => {
previewUrls.forEach((url) => URL.revokeObjectURL(url)); previewUrls.forEach((url) => URL.revokeObjectURL(url));
setImages([]); setImages([]);
setPreviewUrls([]); setPreviewUrls([]);
setOriginalFilenames([]); setFilenames([]);
toast.info("All images cleared."); toast.info("All images cleared.");
}; };
const handleFilenameChange = (index: number, newName: string) => {
const newFilenames = [...filenames];
newFilenames[index] = newName;
setFilenames(newFilenames);
};
const generateFinalFilename = (index: number) => { const generateFinalFilename = (index: number) => {
if (useCounter) { if (useCounter) {
const counter = (index + 1).toString().padStart(counterDigits, '0'); const counter = (index + 1).toString().padStart(counterDigits, '0');
return `${prefix}${counter}${suffix}`; return `${prefix}${counter}${suffix}`;
} }
const originalName = originalFilenames[index] || "filename"; const baseName = filenames[index] || "filename";
return `${prefix}${originalName}${suffix}`; return `${prefix}${baseName}${suffix}`;
}; };
const handleConvertAndDownload = async () => { const handleConvertAndDownload = async () => {
@@ -319,11 +325,16 @@ export function ImageConverter() {
<div key={url} className="p-4 border rounded-lg flex items-center gap-4"> <div key={url} className="p-4 border rounded-lg flex items-center gap-4">
<img src={url} alt={`Preview ${index + 1}`} className="w-20 h-20 object-cover rounded-md shrink-0" /> <img src={url} alt={`Preview ${index + 1}`} className="w-20 h-20 object-cover rounded-md shrink-0" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate text-gray-700 dark:text-gray-300" title={images[index].name}> <Label htmlFor={`filename-${index}`} className="text-xs text-muted-foreground">Base Name</Label>
{images[index].name} <Input
</p> id={`filename-${index}`}
<p className="text-xs text-muted-foreground truncate" title={`${generateFinalFilename(index)}_${width || 'w'}x${height || 'h'}.${format}`}> value={filenames[index]}
New name: {generateFinalFilename(index)} onChange={(e) => handleFilenameChange(index, e.target.value)}
disabled={useCounter}
className="text-sm font-medium h-8 mt-1"
/>
<p className="text-xs text-muted-foreground truncate mt-1" title={`${generateFinalFilename(index)}_${width || 'w'}x${height || 'h'}.${format}`}>
Final name: {generateFinalFilename(index)}.{format}
</p> </p>
</div> </div>
<Button variant="ghost" size="icon" className="shrink-0 text-gray-500 hover:text-destructive" onClick={() => handleRemoveImage(index)}> <Button variant="ghost" size="icon" className="shrink-0 text-gray-500 hover:text-destructive" onClick={() => handleRemoveImage(index)}>