Elias207 commited on
Commit
7fecf66
·
verified ·
1 Parent(s): dcd2127

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +90 -46
index.html CHANGED
@@ -75,8 +75,6 @@
75
 
76
  .form-group { margin-bottom: 2.5rem; }
77
  .form-group:last-child { margin-bottom: 0; }
78
-
79
- /* --- CHANGE 1: Made the selector more generic to apply to any tag, not just label --- */
80
  .form-label {
81
  display: flex;
82
  align-items: center;
@@ -88,7 +86,7 @@
88
  }
89
  .form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
90
 
91
- /* --- Uploader Style with Image Preview --- */
92
  #upload-container.has-file #upload-area { display: none; }
93
  #upload-container:not(.has-file) #file-preview { display: none; }
94
 
@@ -110,27 +108,42 @@
110
  #upload-area p { margin: 0; color: var(--text-secondary); font-weight: 500; }
111
 
112
  #file-preview {
113
- display: flex;
114
- align-items: center;
115
- gap: 1.5rem;
116
- padding: 1rem;
117
- background-color: var(--input-bg);
118
- border-radius: var(--radius-input);
119
- border: 1px solid var(--panel-border);
120
  animation: fadeIn 0.3s;
121
  }
122
  #preview-image {
123
- width: 80px;
124
- height: 80px;
125
- object-fit: cover;
126
- border-radius: 8px;
127
- flex-shrink: 0;
128
  border: 1px solid var(--panel-border);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  }
130
- #file-details { flex-grow: 1; }
131
- #file-name { font-weight: 600; color: var(--text-primary); display: block; margin-bottom: 0.5rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
132
- #remove-file-btn { background: none; border: 1px solid var(--input-border); color: var(--text-secondary); cursor: pointer; transition: all 0.2s; padding: 0.5rem 1rem; border-radius: 8px; font-weight: 500; font-family: var(--app-font); }
133
- #remove-file-btn:hover { color: var(--danger-color); border-color: var(--danger-color); }
134
 
135
  textarea { width: 100%; padding: 1rem 1.2rem; border-radius: var(--radius-input); border: 1px solid var(--input-border); background-color: var(--input-bg); color: var(--text-primary); box-shadow: var(--shadow-sm) inset; font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: var(--transition-smooth); min-height: 90px; resize: vertical; }
136
  textarea:focus { outline: none; border-color: var(--accent-primary); box-shadow: 0 0 0 3px var(--accent-primary-glow), var(--shadow-sm) inset; background-color: var(--panel-bg); }
@@ -149,7 +162,7 @@
149
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
150
  #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1.5rem; }
151
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
152
- .orbital-loader { width: 110px; height: 110px; position: relative; animation: spin 10s linear infinite; } /* MODIFIED: Increased size */
153
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
154
  .orbit:nth-child(1) { width: 35px; height: 35px; margin: -17.5px 0 0 -17.5px; animation: spin 2.8s linear infinite reverse; }
155
  .orbit:nth-child(2) { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: spin 3.8s linear infinite; }
@@ -158,13 +171,13 @@
158
  .orbit:nth-child(2) .satellite { top: 50%; left: -5px; background-color: var(--accent-secondary); transform: translateY(-50%); }
159
  .loading-text { font-weight: 500; color: var(--text-secondary); }
160
 
161
- #result-grid { display: none; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; width: 100%; } /* MODIFIED: Larger results */
162
  #result-container.has-content #result-grid { display: grid; }
163
  #result-grid img { width: 100%; aspect-ratio: 1/1; object-fit: cover; border-radius: var(--radius-input); cursor: pointer; transition: var(--transition-smooth); box-shadow: var(--shadow-md); border: 1px solid var(--panel-border); }
164
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
165
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
166
 
167
- /* --- History Gallery Styles --- */
168
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
169
  #clear-history-btn { background: none; border: 1px solid var(--panel-border); color: var(--text-secondary); padding: 0.5rem 1rem; border-radius: var(--radius-btn); cursor: pointer; display: none; align-items: center; gap: 0.5rem; font-family: var(--app-font); font-weight: 500; transition: all 0.2s; }
170
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
@@ -177,11 +190,10 @@
177
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
178
  .history-item-grid img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--radius-input); cursor: pointer; transition: transform 0.2s ease, box-shadow 0.2s ease; border: 1px solid var(--panel-border); }
179
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
180
- .history-delete-btn { /* NEW */ position: absolute; top: 1rem; left: 1rem; background: none; border: none; cursor: pointer; padding: 0.5rem; border-radius: 50%; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; color: var(--text-tertiary); transition: var(--transition-smooth); }
181
  .history-delete-btn:hover { background-color: var(--panel-border); color: var(--danger-color); }
182
  .history-delete-btn svg { width: 18px; height: 18px; }
183
 
184
- /* --- Lightbox Styles --- */
185
  #lightbox { position: fixed; inset: 0; background-color: rgba(18, 24, 38, 0.6); backdrop-filter: blur(10px) saturate(150%); display: none; align-items: center; justify-content: center; z-index: 1000; opacity: 0; transition: opacity 0.3s; }
186
  #lightbox.visible { display: flex; opacity: 1; }
187
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
@@ -191,7 +203,8 @@
191
  #lightbox-close { top: -50px; right: 0; font-size: 1.8rem; }
192
  #lightbox-download { top: -50px; left: 0; }
193
  #lightbox-download svg { width: 22px; height: 22px; }
194
- /* --- CHANGE 2: Spinner CSS removed as it's no longer needed --- */
 
195
 
196
  @media (max-width: 768px) {
197
  main, .gallery-section { padding: 1.5rem; }
@@ -208,7 +221,6 @@
208
  </header>
209
 
210
  <main>
211
- <!-- --- CHANGE 1: Simplified the structure to exactly match the screenshot's concept --- -->
212
  <div class="form-group">
213
  <div class="form-label">
214
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4Z"/></svg>
@@ -219,12 +231,10 @@
219
  <div id="upload-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg></div>
220
  <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
221
  </label>
 
222
  <div id="file-preview">
223
  <img id="preview-image" src="" alt="Preview">
224
- <div id="file-details">
225
- <span id="file-name"></span>
226
- <button type="button" id="remove-file-btn">حذف و انتخاب مجدد</button>
227
- </div>
228
  </div>
229
  </div>
230
  <input type="file" id="file-input" accept="image/*" hidden>
@@ -277,9 +287,10 @@
277
  <div id="lightbox-content">
278
  <img id="lightbox-img" src="">
279
  <button id="lightbox-close" class="lightbox-btn">&times;</button>
280
- <!-- --- CHANGE 2: Added 'download' attribute and removed spinner div. It's now a simple download link. --- -->
281
- <a id="lightbox-download" title="دانلود تصویر" class="lightbox-btn" download>
282
  <svg fill="white" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
 
283
  </a>
284
  </div>
285
  </div>
@@ -292,8 +303,8 @@
292
  const fileInput = document.getElementById('file-input');
293
  const filePreview = document.getElementById('file-preview');
294
  const previewImage = document.getElementById('preview-image');
295
- const fileNameSpan = document.getElementById('file-name');
296
- const removeFileBtn = document.getElementById('remove-file-btn');
297
  const promptInput = document.getElementById('prompt-input');
298
  const submitBtn = document.getElementById('submit-btn');
299
  const btnText = document.getElementById('btn-text');
@@ -309,6 +320,8 @@
309
  const clearHistoryBtn = document.getElementById('clear-history-btn');
310
 
311
  let uploadedFile = null;
 
 
312
 
313
  // --- Uploader Logic ---
314
  const resetUploader = () => {
@@ -320,7 +333,6 @@
320
  const handleFile = (file) => {
321
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.'); return; }
322
  uploadedFile = file;
323
- fileNameSpan.textContent = file.name;
324
 
325
  const reader = new FileReader();
326
  reader.onload = (e) => { previewImage.src = e.target.result; };
@@ -330,17 +342,14 @@
330
  checkFormState();
331
  clearResult();
332
  };
333
-
334
- // This line was slightly modified to not need a specific ID on the clickable area
335
- // since the <label> now has a 'for' attribute pointing to the input.
336
  uploadArea.addEventListener('click', () => fileInput.click());
337
-
338
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
339
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
340
  ['dragenter', 'dragover'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.add('drag-over')));
341
  ['dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.remove('drag-over')));
342
  uploadArea.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
343
- removeFileBtn.addEventListener('click', resetUploader);
 
344
 
345
  // --- Form & Submission ---
346
  promptInput.addEventListener('input', checkFormState);
@@ -403,22 +412,57 @@
403
  errorMessage.style.display = 'block';
404
  }
405
 
406
- // --- CHANGE 2: Simplified Lightbox and Download logic ---
407
  function openLightbox(url) {
 
408
  lightboxImg.src = url;
409
- lightboxDownload.href = url; // Set the href for the download link
410
  lightbox.classList.add('visible');
411
  }
412
  function closeLightbox() {
413
  lightbox.classList.remove('visible');
414
- lightboxDownload.href = '#'; // Clear href on close
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  }
416
-
417
  lightboxClose.addEventListener('click', closeLightbox);
418
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
419
- // The complex handleDownload function and its event listener are no longer needed.
 
420
 
421
- // --- History Management with Individual Delete ---
422
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
423
  const saveHistory = (history) => {
424
  localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history));
 
75
 
76
  .form-group { margin-bottom: 2.5rem; }
77
  .form-group:last-child { margin-bottom: 0; }
 
 
78
  .form-label {
79
  display: flex;
80
  align-items: center;
 
86
  }
87
  .form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
88
 
89
+ /* --- CHANGE 1: Styles for the new uploader preview --- */
90
  #upload-container.has-file #upload-area { display: none; }
91
  #upload-container:not(.has-file) #file-preview { display: none; }
92
 
 
108
  #upload-area p { margin: 0; color: var(--text-secondary); font-weight: 500; }
109
 
110
  #file-preview {
111
+ position: relative;
 
 
 
 
 
 
112
  animation: fadeIn 0.3s;
113
  }
114
  #preview-image {
115
+ display: block;
116
+ width: 100%;
117
+ max-height: 450px;
118
+ object-fit: contain;
119
+ border-radius: var(--radius-input);
120
  border: 1px solid var(--panel-border);
121
+ background-color: var(--input-bg);
122
+ }
123
+ #remove-preview-btn {
124
+ position: absolute;
125
+ top: 1rem;
126
+ left: 1rem;
127
+ width: 36px;
128
+ height: 36px;
129
+ border-radius: 50%;
130
+ border: none;
131
+ background-color: rgba(26, 32, 44, 0.6);
132
+ color: white;
133
+ font-size: 24px;
134
+ font-weight: bold;
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: center;
138
+ cursor: pointer;
139
+ transition: var(--transition-smooth);
140
+ line-height: 1;
141
+ padding-bottom: 4px; /* Optical alignment */
142
+ }
143
+ #remove-preview-btn:hover {
144
+ background-color: var(--danger-color);
145
+ transform: scale(1.1);
146
  }
 
 
 
 
147
 
148
  textarea { width: 100%; padding: 1rem 1.2rem; border-radius: var(--radius-input); border: 1px solid var(--input-border); background-color: var(--input-bg); color: var(--text-primary); box-shadow: var(--shadow-sm) inset; font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: var(--transition-smooth); min-height: 90px; resize: vertical; }
149
  textarea:focus { outline: none; border-color: var(--accent-primary); box-shadow: 0 0 0 3px var(--accent-primary-glow), var(--shadow-sm) inset; background-color: var(--panel-bg); }
 
162
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
163
  #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1.5rem; }
164
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
165
+ .orbital-loader { width: 110px; height: 110px; position: relative; animation: spin 10s linear infinite; }
166
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
167
  .orbit:nth-child(1) { width: 35px; height: 35px; margin: -17.5px 0 0 -17.5px; animation: spin 2.8s linear infinite reverse; }
168
  .orbit:nth-child(2) { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: spin 3.8s linear infinite; }
 
171
  .orbit:nth-child(2) .satellite { top: 50%; left: -5px; background-color: var(--accent-secondary); transform: translateY(-50%); }
172
  .loading-text { font-weight: 500; color: var(--text-secondary); }
173
 
174
+ #result-grid { display: none; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; width: 100%; }
175
  #result-container.has-content #result-grid { display: grid; }
176
  #result-grid img { width: 100%; aspect-ratio: 1/1; object-fit: cover; border-radius: var(--radius-input); cursor: pointer; transition: var(--transition-smooth); box-shadow: var(--shadow-md); border: 1px solid var(--panel-border); }
177
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
178
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
179
 
180
+ .gallery-section { margin-top: 3rem; animation-delay: 0.5s; }
181
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
182
  #clear-history-btn { background: none; border: 1px solid var(--panel-border); color: var(--text-secondary); padding: 0.5rem 1rem; border-radius: var(--radius-btn); cursor: pointer; display: none; align-items: center; gap: 0.5rem; font-family: var(--app-font); font-weight: 500; transition: all 0.2s; }
183
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
 
190
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
191
  .history-item-grid img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--radius-input); cursor: pointer; transition: transform 0.2s ease, box-shadow 0.2s ease; border: 1px solid var(--panel-border); }
192
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
193
+ .history-delete-btn { position: absolute; top: 1rem; left: 1rem; background: none; border: none; cursor: pointer; padding: 0.5rem; border-radius: 50%; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; color: var(--text-tertiary); transition: var(--transition-smooth); }
194
  .history-delete-btn:hover { background-color: var(--panel-border); color: var(--danger-color); }
195
  .history-delete-btn svg { width: 18px; height: 18px; }
196
 
 
197
  #lightbox { position: fixed; inset: 0; background-color: rgba(18, 24, 38, 0.6); backdrop-filter: blur(10px) saturate(150%); display: none; align-items: center; justify-content: center; z-index: 1000; opacity: 0; transition: opacity 0.3s; }
198
  #lightbox.visible { display: flex; opacity: 1; }
199
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
 
203
  #lightbox-close { top: -50px; right: 0; font-size: 1.8rem; }
204
  #lightbox-download { top: -50px; left: 0; }
205
  #lightbox-download svg { width: 22px; height: 22px; }
206
+ /* --- CHANGE 2: Spinner CSS for download button is back --- */
207
+ #lightbox-download .spinner { width: 20px; height: 20px; border: 3px solid rgba(255, 255, 255, 0.4); border-top-color: #fff; border-radius: 50%; animation: spin 0.8s linear infinite; display: none; }
208
 
209
  @media (max-width: 768px) {
210
  main, .gallery-section { padding: 1.5rem; }
 
221
  </header>
222
 
223
  <main>
 
224
  <div class="form-group">
225
  <div class="form-label">
226
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4Z"/></svg>
 
231
  <div id="upload-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg></div>
232
  <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
233
  </label>
234
+ <!-- --- CHANGE 1: HTML for the new preview is simplified --- -->
235
  <div id="file-preview">
236
  <img id="preview-image" src="" alt="Preview">
237
+ <button type="button" id="remove-preview-btn" title="حذف تصویر">&times;</button>
 
 
 
238
  </div>
239
  </div>
240
  <input type="file" id="file-input" accept="image/*" hidden>
 
287
  <div id="lightbox-content">
288
  <img id="lightbox-img" src="">
289
  <button id="lightbox-close" class="lightbox-btn">&times;</button>
290
+ <!-- --- CHANGE 2: Spinner is added back for download feedback --- -->
291
+ <a id="lightbox-download" title="دانلود تصویر" class="lightbox-btn">
292
  <svg fill="white" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
293
+ <div class="spinner"></div>
294
  </a>
295
  </div>
296
  </div>
 
303
  const fileInput = document.getElementById('file-input');
304
  const filePreview = document.getElementById('file-preview');
305
  const previewImage = document.getElementById('preview-image');
306
+ // --- CHANGE 1: Old variables removed, new one added ---
307
+ const removePreviewBtn = document.getElementById('remove-preview-btn');
308
  const promptInput = document.getElementById('prompt-input');
309
  const submitBtn = document.getElementById('submit-btn');
310
  const btnText = document.getElementById('btn-text');
 
320
  const clearHistoryBtn = document.getElementById('clear-history-btn');
321
 
322
  let uploadedFile = null;
323
+ // --- CHANGE 2: Variable to store the current image URL for download ---
324
+ let currentLightboxUrl = null;
325
 
326
  // --- Uploader Logic ---
327
  const resetUploader = () => {
 
333
  const handleFile = (file) => {
334
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.'); return; }
335
  uploadedFile = file;
 
336
 
337
  const reader = new FileReader();
338
  reader.onload = (e) => { previewImage.src = e.target.result; };
 
342
  checkFormState();
343
  clearResult();
344
  };
 
 
 
345
  uploadArea.addEventListener('click', () => fileInput.click());
 
346
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
347
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
348
  ['dragenter', 'dragover'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.add('drag-over')));
349
  ['dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.remove('drag-over')));
350
  uploadArea.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
351
+ // --- CHANGE 1: Event listener is now on the new 'X' button ---
352
+ removePreviewBtn.addEventListener('click', resetUploader);
353
 
354
  // --- Form & Submission ---
355
  promptInput.addEventListener('input', checkFormState);
 
412
  errorMessage.style.display = 'block';
413
  }
414
 
415
+ // --- CHANGE 2: Robust download and lightbox logic ---
416
  function openLightbox(url) {
417
+ currentLightboxUrl = url;
418
  lightboxImg.src = url;
 
419
  lightbox.classList.add('visible');
420
  }
421
  function closeLightbox() {
422
  lightbox.classList.remove('visible');
423
+ currentLightboxUrl = null;
424
+ }
425
+ async function handleDownload() {
426
+ if (!currentLightboxUrl) return;
427
+ const downloadBtn = lightboxDownload;
428
+ const spinner = downloadBtn.querySelector('.spinner');
429
+ const icon = downloadBtn.querySelector('svg');
430
+
431
+ spinner.style.display = 'block';
432
+ icon.style.display = 'none';
433
+ try {
434
+ // Fetch the image data
435
+ const response = await fetch(currentLightboxUrl);
436
+ // Convert it to a blob (a file-like object)
437
+ const blob = await response.blob();
438
+ // Create a temporary local URL for the blob
439
+ const objectUrl = URL.createObjectURL(blob);
440
+
441
+ // Create a temporary link element to trigger the download
442
+ const a = document.createElement('a');
443
+ a.href = objectUrl;
444
+ a.download = `edited-image-${Date.now()}.png`; // Set a default filename
445
+ document.body.appendChild(a);
446
+ a.click(); // Programmatically click the link
447
+ document.body.removeChild(a); // Clean up by removing the link
448
+
449
+ // Release the memory used by the object URL
450
+ URL.revokeObjectURL(objectUrl);
451
+ } catch (e) {
452
+ console.error('Download failed:', e);
453
+ alert('خطا در دانلود تصویر. لطفا دوباره تلاش کنید.');
454
+ } finally {
455
+ // Restore the button to its normal state
456
+ spinner.style.display = 'none';
457
+ icon.style.display = 'block';
458
+ }
459
  }
 
460
  lightboxClose.addEventListener('click', closeLightbox);
461
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
462
+ lightboxDownload.addEventListener('click', handleDownload);
463
+
464
 
465
+ // --- History Management (No changes here) ---
466
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
467
  const saveHistory = (history) => {
468
  localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history));