@@ -45,6 +45,9 @@ export default function ImageOptimizeForm({
45
45
aspectRatio : number ;
46
46
} [ ]
47
47
> ( [ ] ) ;
48
+ const [ originalImageNames , setLocalOriginalImageNames ] = useState < string [ ] > (
49
+ [ ] ,
50
+ ) ;
48
51
const [ isQualityEnabled , setIsQualityEnabled ] = useState ( true ) ;
49
52
const [ isResizeEnabled , setIsResizeEnabled ] = useState ( true ) ;
50
53
const [ outputFormat , setOutputFormat ] = useState < string > ( "webp" ) ;
@@ -60,6 +63,7 @@ export default function ImageOptimizeForm({
60
63
format : string ;
61
64
aspectRatio : number ;
62
65
} [ ] = [ ] ;
66
+ const originalNamesTemp : string [ ] = [ ] ;
63
67
64
68
files . forEach ( ( file , index ) => {
65
69
const reader = new FileReader ( ) ;
@@ -77,11 +81,13 @@ export default function ImageOptimizeForm({
77
81
} ;
78
82
previewsTemp [ index ] = reader . result as string ;
79
83
imageInfosTemp [ index ] = imageInfoData ;
84
+ originalNamesTemp [ index ] = file . name ;
80
85
81
86
// Only update state when all files are processed
82
87
if ( previewsTemp . length === files . length ) {
83
88
setPreviews ( [ ...previewsTemp ] ) ;
84
89
setLocalImageInfos ( [ ...imageInfosTemp ] ) ;
90
+ setLocalOriginalImageNames ( [ ...originalNamesTemp ] ) ;
85
91
}
86
92
} ;
87
93
} ;
@@ -90,6 +96,7 @@ export default function ImageOptimizeForm({
90
96
} else {
91
97
setPreviews ( [ ] ) ;
92
98
setLocalImageInfos ( [ ] ) ;
99
+ setLocalOriginalImageNames ( [ ] ) ;
93
100
}
94
101
} , [ files ] ) ;
95
102
@@ -106,6 +113,47 @@ export default function ImageOptimizeForm({
106
113
}
107
114
} ;
108
115
116
+ const handleClone = ( ) => {
117
+ if ( selectedImageIndex < 0 || selectedImageIndex >= files . length ) return ;
118
+
119
+ const originalFile = files [ selectedImageIndex ] ! ;
120
+ const clonedFile = new File (
121
+ [ originalFile ] ,
122
+ generateCloneName ( originalFile . name ) ,
123
+ {
124
+ type : originalFile . type ,
125
+ lastModified : originalFile . lastModified ,
126
+ } ,
127
+ ) ;
128
+
129
+ const updatedFiles = [ ...files , clonedFile ] ;
130
+ setFiles ( updatedFiles ) ;
131
+
132
+ const newPreviewUrl = previews [ selectedImageIndex ] ! ;
133
+ const newImageInfo = { ...imageInfos [ selectedImageIndex ] ! } ;
134
+ const newOriginalName = clonedFile . name ;
135
+
136
+ setPreviews ( [ ...previews , newPreviewUrl ] ) ;
137
+ setLocalImageInfos ( [ ...imageInfos , newImageInfo ] ) ;
138
+ setLocalOriginalImageNames ( [ ...originalImageNames , newOriginalName ] ) ;
139
+
140
+ setSelectedImageIndex ( updatedFiles . length - 1 ) ; // Select the cloned image
141
+ } ;
142
+
143
+ const generateCloneName = ( originalName : string ) => {
144
+ const extension = originalName . slice ( originalName . lastIndexOf ( "." ) ) ;
145
+ const baseName = originalName . slice ( 0 , originalName . lastIndexOf ( "." ) ) ;
146
+ let cloneCount = 1 ;
147
+
148
+ let newName = `${ baseName } -${ cloneCount } ${ extension } ` ;
149
+ while ( originalImageNames . includes ( newName ) ) {
150
+ cloneCount ++ ;
151
+ newName = `${ baseName } -${ cloneCount } ${ extension } ` ;
152
+ }
153
+
154
+ return newName ;
155
+ } ;
156
+
109
157
const handleSubmit = async ( e : React . FormEvent ) => {
110
158
e . preventDefault ( ) ;
111
159
if ( files . length === 0 ) return ;
@@ -216,6 +264,13 @@ export default function ImageOptimizeForm({
216
264
</ option >
217
265
) ) }
218
266
</ select >
267
+ < button
268
+ type = "button"
269
+ className = "mt-2 w-full rounded bg-yellow-500 py-2 text-white hover:bg-yellow-600"
270
+ onClick = { handleClone }
271
+ >
272
+ Clone
273
+ </ button >
219
274
</ div >
220
275
) }
221
276
0 commit comments