Elias207 commited on
Commit
ff92e58
·
verified ·
1 Parent(s): 4de0fae

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +114 -86
index.html CHANGED
@@ -86,8 +86,9 @@
86
  }
87
  label.form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
88
 
89
- /* --- New Uploader Style --- */
90
- #upload-area {
 
91
  border: 2px dashed var(--input-border);
92
  border-radius: var(--radius-input);
93
  padding: 2rem;
@@ -95,50 +96,72 @@
95
  cursor: pointer;
96
  transition: var(--transition-smooth);
97
  background-color: var(--input-bg);
 
 
 
 
 
98
  }
99
- #upload-area.drag-over, #upload-area:hover {
100
  border-color: var(--accent-primary);
101
  background-color: #fff;
102
  box-shadow: 0 0 15px var(--accent-primary-glow);
103
  }
104
- #upload-icon svg { width: 48px; height: 48px; color: var(--accent-primary); margin-bottom: 1rem; stroke-width: 1.5; opacity: 0.8; }
105
- #upload-area p { margin: 0; color: var(--text-secondary); font-weight: 500; }
106
- #file-preview {
107
- display: none;
108
  align-items: center;
109
- justify-content: space-between;
110
- padding: 1rem 1.2rem;
 
 
 
 
 
 
 
 
 
 
111
  background-color: var(--input-bg);
112
- border-radius: var(--radius-input);
113
- border: 1px solid var(--panel-border);
114
- animation: fadeIn 0.3s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
- #file-info { display: flex; align-items: center; gap: 1rem; overflow: hidden; }
117
- #file-info svg { color: var(--accent-secondary); width: 28px; height: 28px; flex-shrink: 0; }
118
- #file-name { font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
119
- #remove-file-btn { background: none; border: none; color: var(--text-tertiary); cursor: pointer; font-size: 1.5rem; transition: all 0.2s; flex-shrink: 0; padding: 0 .5rem; }
120
- #remove-file-btn:hover { color: var(--danger-color); transform: scale(1.1); }
121
 
122
  textarea {
123
- width: 100%;
124
- padding: 1rem 1.2rem;
125
- border-radius: var(--radius-input);
126
- border: 1px solid var(--input-border);
127
- background-color: var(--input-bg);
128
- color: var(--text-primary);
129
- box-shadow: var(--shadow-sm) inset;
130
- font-family: var(--app-font);
131
- font-size: 1rem;
132
- box-sizing: border-box;
133
- transition: var(--transition-smooth);
134
- min-height: 90px;
135
- resize: vertical;
136
  }
137
  textarea:focus {
138
- outline: none;
139
- border-color: var(--accent-primary);
140
- box-shadow: 0 0 0 3px var(--accent-primary-glow), var(--shadow-sm) inset;
141
- background-color: var(--panel-bg);
142
  }
143
  #submit-btn {
144
  display: flex; align-items: center; justify-content: center; gap: 10px;
@@ -157,39 +180,47 @@
157
  #submit-btn .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; }
158
 
159
  #result-container {
160
- min-height: 180px; position: relative;
161
  box-sizing: border-box; padding: 1rem; background-color: var(--input-bg);
162
  border-radius: var(--radius-card); border: 2px dashed var(--input-border);
163
  box-shadow: var(--shadow-sm) inset; transition: var(--transition-smooth);
164
  display: flex; align-items: center; justify-content: center;
165
  }
166
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
167
- #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1rem; }
168
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
169
- /* Using the TTS loader */
170
- .orbital-loader { width: 80px; height: 80px; position: relative; animation: spin 10s linear infinite; }
 
171
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
172
- .orbit:nth-child(1) { width: 25px; height: 25px; margin: -12.5px 0 0 -12.5px; animation: spin 2.8s linear infinite reverse; }
173
- .orbit:nth-child(2) { width: 50px; height: 50px; margin: -25px 0 0 -25px; animation: spin 3.8s linear infinite; }
174
- .orbit .satellite { position: absolute; width: 8px; height: 8px; border-radius: 50%; background-color: var(--accent-primary); box-shadow: 0 0 8px var(--accent-primary), 0 0 12px var(--accent-secondary); }
175
- .orbit:nth-child(1) .satellite { top: -4px; left: 50%; transform: translateX(-50%); }
176
- .orbit:nth-child(2) .satellite { top: 50%; left: -4px; background-color: var(--accent-secondary); transform: translateY(-50%); }
177
  .loading-text { font-weight: 500; color: var(--text-secondary); }
178
 
179
  #result-grid {
180
- display: none; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
181
- gap: 1rem; width: 100%;
 
 
182
  }
183
  #result-container.has-content #result-grid { display: grid; }
184
  #result-grid img {
185
- width: 100%; height: 150px; object-fit: cover; border-radius: var(--radius-input);
186
- cursor: pointer; transition: var(--transition-smooth); box-shadow: var(--shadow-md);
 
 
 
 
 
187
  border: 1px solid var(--panel-border);
188
  }
189
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
190
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
191
 
192
- /* --- History Gallery Styles --- */
193
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
194
  #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; }
195
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
@@ -197,13 +228,12 @@
197
  #history-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 1.5rem; }
198
  #history-grid:empty::before { content: 'هنوز تصویری خلق نکرده‌اید. اولین ویرایش شما اینجا ذخیره خواهد شد.'; color: var(--text-secondary); grid-column: 1 / -1; text-align: center; padding: 3rem 1rem; background-color: var(--input-bg); border-radius: var(--radius-card); }
199
  .history-item { background-color: var(--input-bg); border-radius: var(--radius-card); border: 1px solid var(--panel-border); padding: 1.5rem; transition: var(--transition-smooth); }
200
- .history-item:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); }
201
  .history-item-prompt { font-weight: 600; margin: 0 0 1rem 0; word-break: break-word; }
202
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
203
  .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); }
204
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
205
 
206
- /* --- Lightbox Styles --- */
207
  #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; }
208
  #lightbox.visible { display: flex; opacity: 1; }
209
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
@@ -217,8 +247,6 @@
217
  @media (max-width: 768px) {
218
  main, .gallery-section { padding: 1.5rem; }
219
  h1 { font-size: 2.2rem; }
220
- #result-grid { grid-template-columns: repeat(2, 1fr); }
221
- #result-grid img { height: auto; aspect-ratio: 1/1; }
222
  .history-item-grid { grid-template-columns: repeat(2, 1fr); }
223
  }
224
  </style>
@@ -232,29 +260,24 @@
232
 
233
  <main>
234
  <div class="form-group">
235
- <label for="upload-area" class="form-label">
236
  <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>
237
  ۱. تصویر خود را انتخاب کنید
238
  </label>
239
- <div id="upload-container">
240
- <label id="upload-area">
241
- <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>
242
  <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
243
- </label>
244
- <div id="file-preview">
245
- <div id="file-info">
246
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M13.5,16V19H10.5V16H8L12,12L16,16H13.5M13,9V3.5L18.5,9H13Z" /></svg>
247
- <span id="file-name"></span>
248
- </div>
249
- <button type="button" id="remove-file-btn" title="حذف فایل">&times;</button>
250
  </div>
 
 
251
  </div>
252
  <input type="file" id="file-input" accept="image/*" hidden>
253
  </div>
254
 
255
  <div class="form-group">
256
  <label for="prompt-input" class="form-label">
257
- <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="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
258
  ۲. دستور ویرایش را بنویسید
259
  </label>
260
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
@@ -308,12 +331,11 @@
308
  <script>
309
  const API_URL = 'https://alfa-editor-worker.onrender.com/api/edit';
310
 
311
- // --- DOM Elements ---
312
- const uploadArea = document.getElementById('upload-area');
313
  const fileInput = document.getElementById('file-input');
314
- const filePreview = document.getElementById('file-preview');
315
- const fileNameSpan = document.getElementById('file-name');
316
- const removeFileBtn = document.getElementById('remove-file-btn');
317
  const promptInput = document.getElementById('prompt-input');
318
  const submitBtn = document.getElementById('submit-btn');
319
  const btnText = document.getElementById('btn-text');
@@ -330,35 +352,44 @@
330
 
331
  let uploadedFile = null;
332
 
333
- // --- Uploader Logic ---
334
  const resetUploader = () => {
335
  uploadedFile = null;
336
  fileInput.value = '';
337
- uploadArea.style.display = 'block';
338
- filePreview.style.display = 'none';
 
339
  checkFormState();
340
  };
 
341
  const handleFile = (file) => {
342
  if (!file || !file.type.startsWith('image/')) {
343
  displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.');
344
  return;
345
  }
346
  uploadedFile = file;
347
- fileNameSpan.textContent = file.name;
348
- uploadArea.style.display = 'none';
349
- filePreview.style.display = 'flex';
 
 
 
 
 
350
  checkFormState();
351
  clearResult();
352
  };
353
- uploadArea.addEventListener('click', () => fileInput.click());
 
354
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
355
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
356
- ['dragenter', 'dragover'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.add('drag-over')));
357
- ['dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.remove('drag-over')));
358
- uploadArea.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
359
- removeFileBtn.addEventListener('click', resetUploader);
 
 
 
360
 
361
- // --- Form & Submission ---
362
  promptInput.addEventListener('input', checkFormState);
363
  function checkFormState() {
364
  submitBtn.disabled = !uploadedFile || promptInput.value.trim() === '';
@@ -390,7 +421,6 @@
390
  }
391
  });
392
 
393
- // --- UI State Management ---
394
  function setLoading(isLoading) {
395
  if (isLoading) {
396
  resultContainer.classList.remove('has-content');
@@ -428,7 +458,6 @@
428
  errorMessage.style.display = 'block';
429
  }
430
 
431
- // --- Lightbox Functions ---
432
  function openLightbox(url) {
433
  lightboxImg.src = url;
434
  lightboxDownload.href = url;
@@ -438,7 +467,6 @@
438
  lightboxClose.addEventListener('click', closeLightbox);
439
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
440
 
441
- // --- History Management ---
442
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
443
  const saveHistory = (history) => {
444
  localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history));
@@ -447,7 +475,7 @@
447
  const addToHistory = (item) => {
448
  let history = getHistory();
449
  history.unshift(item);
450
- if (history.length > 15) history.pop(); // Limit history size
451
  saveHistory(history);
452
  };
453
  const handleClearHistory = () => {
 
86
  }
87
  label.form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
88
 
89
+ /* --- New Uploader with Image Preview --- */
90
+ #drop-zone {
91
+ position: relative;
92
  border: 2px dashed var(--input-border);
93
  border-radius: var(--radius-input);
94
  padding: 2rem;
 
96
  cursor: pointer;
97
  transition: var(--transition-smooth);
98
  background-color: var(--input-bg);
99
+ min-height: 250px;
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ overflow: hidden;
104
  }
105
+ #drop-zone.drag-over, #drop-zone:hover {
106
  border-color: var(--accent-primary);
107
  background-color: #fff;
108
  box-shadow: 0 0 15px var(--accent-primary-glow);
109
  }
110
+ #drop-zone-content {
111
+ display: flex;
112
+ flex-direction: column;
 
113
  align-items: center;
114
+ gap: 1rem;
115
+ transition: opacity 0.3s ease;
116
+ }
117
+ #drop-zone-content svg { width: 48px; height: 48px; color: var(--accent-primary); stroke-width: 1.5; opacity: 0.8; }
118
+ #drop-zone-content p { margin: 0; color: var(--text-secondary); font-weight: 500; }
119
+
120
+ #image-preview {
121
+ position: absolute;
122
+ top: 0; left: 0; width: 100%; height: 100%;
123
+ object-fit: contain;
124
+ padding: 1rem;
125
+ box-sizing: border-box;
126
  background-color: var(--input-bg);
127
+ opacity: 0;
128
+ visibility: hidden;
129
+ transition: opacity 0.3s ease, visibility 0.3s;
130
+ pointer-events: none;
131
+ }
132
+ #image-preview.visible { opacity: 1; visibility: visible; pointer-events: auto; }
133
+ #remove-preview-btn {
134
+ position: absolute;
135
+ top: 1rem;
136
+ left: 1rem; /* Adjusted for RTL */
137
+ background-color: rgba(0,0,0,0.5);
138
+ color: white;
139
+ border: none;
140
+ border-radius: 50%;
141
+ width: 32px;
142
+ height: 32px;
143
+ font-size: 1.5rem;
144
+ line-height: 1;
145
+ cursor: pointer;
146
+ display: flex;
147
+ align-items: center;
148
+ justify-content: center;
149
+ opacity: 0;
150
+ visibility: hidden;
151
+ transition: opacity 0.3s ease, visibility 0.3s;
152
+ z-index: 10;
153
  }
154
+ #remove-preview-btn.visible { opacity: 1; visibility: visible; }
 
 
 
 
155
 
156
  textarea {
157
+ width: 100%; padding: 1rem 1.2rem; border-radius: var(--radius-input); border: 1px solid var(--input-border);
158
+ background-color: var(--input-bg); color: var(--text-primary); box-shadow: var(--shadow-sm) inset;
159
+ font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: var(--transition-smooth);
160
+ min-height: 90px; resize: vertical;
 
 
 
 
 
 
 
 
 
161
  }
162
  textarea:focus {
163
+ outline: none; border-color: var(--accent-primary);
164
+ box-shadow: 0 0 0 3px var(--accent-primary-glow), var(--shadow-sm) inset; background-color: var(--panel-bg);
 
 
165
  }
166
  #submit-btn {
167
  display: flex; align-items: center; justify-content: center; gap: 10px;
 
180
  #submit-btn .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; }
181
 
182
  #result-container {
183
+ min-height: 220px; position: relative;
184
  box-sizing: border-box; padding: 1rem; background-color: var(--input-bg);
185
  border-radius: var(--radius-card); border: 2px dashed var(--input-border);
186
  box-shadow: var(--shadow-sm) inset; transition: var(--transition-smooth);
187
  display: flex; align-items: center; justify-content: center;
188
  }
189
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
190
+ #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1.5rem; }
191
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
192
+
193
+ /* Bigger Loader */
194
+ .orbital-loader { width: 100px; height: 100px; position: relative; animation: spin 10s linear infinite; }
195
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
196
+ .orbit:nth-child(1) { width: 35px; height: 35px; margin: -17.5px 0 0 -17.5px; animation: spin 2.8s linear infinite reverse; }
197
+ .orbit:nth-child(2) { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: spin 3.8s linear infinite; }
198
+ .orbit .satellite { position: absolute; width: 10px; height: 10px; border-radius: 50%; background-color: var(--accent-primary); box-shadow: 0 0 8px var(--accent-primary), 0 0 12px var(--accent-secondary); }
199
+ .orbit:nth-child(1) .satellite { top: -5px; left: 50%; transform: translateX(-50%); }
200
+ .orbit:nth-child(2) .satellite { top: 50%; left: -5px; background-color: var(--accent-secondary); transform: translateY(-50%); }
201
  .loading-text { font-weight: 500; color: var(--text-secondary); }
202
 
203
  #result-grid {
204
+ display: none;
205
+ grid-template-columns: repeat(2, 1fr); /* Bigger results */
206
+ gap: 1rem;
207
+ width: 100%;
208
  }
209
  #result-container.has-content #result-grid { display: grid; }
210
  #result-grid img {
211
+ width: 100%;
212
+ aspect-ratio: 1 / 1; /* Make them square */
213
+ object-fit: cover;
214
+ border-radius: var(--radius-input);
215
+ cursor: pointer;
216
+ transition: var(--transition-smooth);
217
+ box-shadow: var(--shadow-md);
218
  border: 1px solid var(--panel-border);
219
  }
220
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
221
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
222
 
223
+ /* History Gallery Styles */
224
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
225
  #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; }
226
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
 
228
  #history-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 1.5rem; }
229
  #history-grid:empty::before { content: 'هنوز تصویری خلق نکرده‌اید. اولین ویرایش شما اینجا ذخیره خواهد شد.'; color: var(--text-secondary); grid-column: 1 / -1; text-align: center; padding: 3rem 1rem; background-color: var(--input-bg); border-radius: var(--radius-card); }
230
  .history-item { background-color: var(--input-bg); border-radius: var(--radius-card); border: 1px solid var(--panel-border); padding: 1.5rem; transition: var(--transition-smooth); }
 
231
  .history-item-prompt { font-weight: 600; margin: 0 0 1rem 0; word-break: break-word; }
232
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
233
  .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); }
234
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
235
 
236
+ /* Lightbox Styles */
237
  #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; }
238
  #lightbox.visible { display: flex; opacity: 1; }
239
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
 
247
  @media (max-width: 768px) {
248
  main, .gallery-section { padding: 1.5rem; }
249
  h1 { font-size: 2.2rem; }
 
 
250
  .history-item-grid { grid-template-columns: repeat(2, 1fr); }
251
  }
252
  </style>
 
260
 
261
  <main>
262
  <div class="form-group">
263
+ <label for="drop-zone" class="form-label">
264
  <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>
265
  ۱. تصویر خود را انتخاب کنید
266
  </label>
267
+ <div id="drop-zone">
268
+ <div id="drop-zone-content">
269
+ <svg><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>
270
  <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
 
 
 
 
 
 
 
271
  </div>
272
+ <img id="image-preview" src="#" alt="پیش‌نمایش تصویر">
273
+ <button type="button" id="remove-preview-btn" title="حذف تصویر">&times;</button>
274
  </div>
275
  <input type="file" id="file-input" accept="image/*" hidden>
276
  </div>
277
 
278
  <div class="form-group">
279
  <label for="prompt-input" class="form-label">
280
+ <svg xmlns="http://www.w.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
281
  ۲. دستور ویرایش را بنویسید
282
  </label>
283
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
 
331
  <script>
332
  const API_URL = 'https://alfa-editor-worker.onrender.com/api/edit';
333
 
334
+ const dropZone = document.getElementById('drop-zone');
335
+ const dropZoneContent = document.getElementById('drop-zone-content');
336
  const fileInput = document.getElementById('file-input');
337
+ const imagePreview = document.getElementById('image-preview');
338
+ const removePreviewBtn = document.getElementById('remove-preview-btn');
 
339
  const promptInput = document.getElementById('prompt-input');
340
  const submitBtn = document.getElementById('submit-btn');
341
  const btnText = document.getElementById('btn-text');
 
352
 
353
  let uploadedFile = null;
354
 
 
355
  const resetUploader = () => {
356
  uploadedFile = null;
357
  fileInput.value = '';
358
+ imagePreview.classList.remove('visible');
359
+ removePreviewBtn.classList.remove('visible');
360
+ dropZoneContent.style.opacity = '1';
361
  checkFormState();
362
  };
363
+
364
  const handleFile = (file) => {
365
  if (!file || !file.type.startsWith('image/')) {
366
  displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.');
367
  return;
368
  }
369
  uploadedFile = file;
370
+ const reader = new FileReader();
371
+ reader.onload = (e) => {
372
+ imagePreview.src = e.target.result;
373
+ imagePreview.classList.add('visible');
374
+ removePreviewBtn.classList.add('visible');
375
+ dropZoneContent.style.opacity = '0';
376
+ };
377
+ reader.readAsDataURL(file);
378
  checkFormState();
379
  clearResult();
380
  };
381
+
382
+ dropZone.addEventListener('click', () => fileInput.click());
383
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
384
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => dropZone.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
385
+ ['dragenter', 'dragover'].forEach(e => dropZone.addEventListener(e, () => dropZone.classList.add('drag-over')));
386
+ ['dragleave', 'drop'].forEach(e => dropZone.addEventListener(e, () => dropZone.classList.remove('drag-over')));
387
+ dropZone.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
388
+ removePreviewBtn.addEventListener('click', (e) => {
389
+ e.stopPropagation(); // prevent drop-zone click event
390
+ resetUploader();
391
+ });
392
 
 
393
  promptInput.addEventListener('input', checkFormState);
394
  function checkFormState() {
395
  submitBtn.disabled = !uploadedFile || promptInput.value.trim() === '';
 
421
  }
422
  });
423
 
 
424
  function setLoading(isLoading) {
425
  if (isLoading) {
426
  resultContainer.classList.remove('has-content');
 
458
  errorMessage.style.display = 'block';
459
  }
460
 
 
461
  function openLightbox(url) {
462
  lightboxImg.src = url;
463
  lightboxDownload.href = url;
 
467
  lightboxClose.addEventListener('click', closeLightbox);
468
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
469
 
 
470
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
471
  const saveHistory = (history) => {
472
  localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history));
 
475
  const addToHistory = (item) => {
476
  let history = getHistory();
477
  history.unshift(item);
478
+ if (history.length > 15) history.pop();
479
  saveHistory(history);
480
  };
481
  const handleClearHistory = () => {