Elias207 commited on
Commit
f4b8e2e
·
verified ·
1 Parent(s): 89691ac

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +313 -111
index.html CHANGED
@@ -35,23 +35,40 @@
35
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
36
 
37
  body {
38
- font-family: var(--app-font); background-color: var(--app-bg); color: var(--text-primary);
39
- margin: 0; padding: 2.5rem 1rem; display: flex; justify-content: center;
40
- align-items: flex-start; min-height: 100vh;
 
 
 
 
 
 
41
  }
42
  .container { max-width: 820px; width: 100%; }
43
 
44
- header { text-align: center; margin-bottom: 2.5rem; animation: fadeIn 0.8s 0.1s ease-out backwards; }
 
 
 
 
45
  h1 {
46
- font-size: 2.8rem; font-weight: 800; margin: 0 0 0.8rem 0;
 
 
47
  background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
48
- -webkit-background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -1px;
 
 
49
  }
50
  .subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-top: 0; }
51
 
52
  main, .gallery-section {
53
- padding: 3rem; background-color: var(--panel-bg); border-radius: var(--radius-card);
54
- box-shadow: var(--shadow-xl); border: 1px solid var(--panel-border);
 
 
 
55
  animation: fadeIn 0.8s 0.3s ease-out backwards;
56
  }
57
  .gallery-section { margin-top: 3rem; animation-delay: 0.5s; }
@@ -59,26 +76,59 @@
59
  .form-group { margin-bottom: 2.5rem; }
60
  .form-group:last-child { margin-bottom: 0; }
61
  label.form-label {
62
- display: flex; align-items: center; gap: 0.75rem; font-weight: 700;
63
- color: var(--text-primary); font-size: 1.2em; margin-bottom: 1.2rem;
 
 
 
 
 
64
  }
65
  label.form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
66
 
67
- /* --- Uploader Style to Match Reference Image --- */
68
- #drop-zone {
69
- position: relative; border: 2px dashed var(--input-border); border-radius: var(--radius-input);
70
- padding: 2rem; text-align: center; cursor: pointer; transition: var(--transition-smooth);
71
- background-color: var(--input-bg); min-height: 250px; display: flex; align-items: center;
72
- justify-content: center; overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
- #drop-zone.drag-over, #drop-zone:hover { border-color: var(--accent-primary); background-color: #fff; box-shadow: 0 0 15px var(--accent-primary-glow); }
75
- #drop-zone-content { display: flex; flex-direction: column; align-items: center; gap: 1rem; transition: opacity 0.3s ease; }
76
- #drop-zone-content svg { width: 48px; height: 48px; color: var(--accent-primary); stroke-width: 1.5; opacity: 0.8; }
77
- #drop-zone-content p { margin: 0; color: var(--text-secondary); font-weight: 500; }
78
- #image-preview { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; padding: 1rem; box-sizing: border-box; background-color: var(--input-bg); opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s; pointer-events: none; }
79
- #image-preview.visible { opacity: 1; visibility: visible; pointer-events: auto; }
80
- #remove-preview-btn { position: absolute; top: 1rem; left: 1rem; background-color: rgba(0,0,0,0.5); color: white; border: none; border-radius: 50%; width: 32px; height: 32px; font-size: 1.5rem; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s; z-index: 10; }
81
- #remove-preview-btn.visible { opacity: 1; visibility: visible; }
 
 
 
 
82
 
83
  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; }
84
  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); }
@@ -87,11 +137,17 @@
87
  #submit-btn:disabled { background: var(--text-tertiary); cursor: not-allowed; box-shadow: none; opacity: 0.7; }
88
  #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; }
89
 
90
- #result-container { min-height: 220px; position: relative; box-sizing: border-box; padding: 1rem; background-color: var(--input-bg); border-radius: var(--radius-card); border: 2px dashed var(--input-border); box-shadow: var(--shadow-sm) inset; transition: var(--transition-smooth); display: flex; align-items: center; justify-content: center; }
 
 
 
 
 
 
91
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
92
  #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1.5rem; }
93
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
94
- .orbital-loader { width: 100px; height: 100px; position: relative; animation: spin 10s linear infinite; }
95
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
96
  .orbit:nth-child(1) { width: 35px; height: 35px; margin: -17.5px 0 0 -17.5px; animation: spin 2.8s linear infinite reverse; }
97
  .orbit:nth-child(2) { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: spin 3.8s linear infinite; }
@@ -100,13 +156,13 @@
100
  .orbit:nth-child(2) .satellite { top: 50%; left: -5px; background-color: var(--accent-secondary); transform: translateY(-50%); }
101
  .loading-text { font-weight: 500; color: var(--text-secondary); }
102
 
103
- #result-grid { display: none; grid-template-columns: repeat(2, 1fr); gap: 1rem; width: 100%; }
104
  #result-container.has-content #result-grid { display: grid; }
105
- #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); }
106
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
107
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
108
 
109
- /* History Gallery Styles */
110
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
111
  #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; }
112
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
@@ -114,14 +170,16 @@
114
  #history-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 1.5rem; }
115
  #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); }
116
  .history-item { position: relative; background-color: var(--input-bg); border-radius: var(--radius-card); border: 1px solid var(--panel-border); padding: 1.5rem; transition: var(--transition-smooth); }
117
- .history-item-prompt { font-weight: 600; margin: 0 0 1rem 0; word-break: break-word; }
 
118
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
119
  .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); }
120
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
121
- .history-item-delete-btn { position: absolute; top: 0.75rem; left: 0.75rem; background-color: rgba(255, 255, 255, 0.8); backdrop-filter: blur(2px); color: var(--danger-color); border: 1px solid var(--panel-border); width: 28px; height: 28px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; line-height: 1; opacity: 0; transition: all 0.2s; }
122
- .history-item:hover .history-item-delete-btn { opacity: 1; }
 
123
 
124
- /* Lightbox Styles */
125
  #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; }
126
  #lightbox.visible { display: flex; opacity: 1; }
127
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
@@ -131,169 +189,313 @@
131
  #lightbox-close { top: -50px; right: 0; font-size: 1.8rem; }
132
  #lightbox-download { top: -50px; left: 0; }
133
  #lightbox-download svg { width: 22px; height: 22px; }
 
134
 
135
  @media (max-width: 768px) {
136
  main, .gallery-section { padding: 1.5rem; }
137
  h1 { font-size: 2.2rem; }
138
- #result-grid { grid-template-columns: 1fr; } /* Single column on small screens for bigger images */
139
  .history-item-grid { grid-template-columns: repeat(2, 1fr); }
140
  }
141
  </style>
142
  </head>
143
  <body>
144
  <div class="container">
145
- <header><h1>فتوشاپ هوش مصنوعی ✨</h1><p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی و به زبان ساده ویرایش کنید</p></header>
 
 
 
 
146
  <main>
147
  <div class="form-group">
148
- <label for="drop-zone" class="form-label"><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>۱. تصویر خود را انتخاب کنید</label>
149
- <div id="drop-zone">
150
- <div id="drop-zone-content"><svg><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg><p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p></div>
151
- <img id="image-preview" src="#" alt="پیش‌نمایش تصویر"><button type="button" id="remove-preview-btn" title="حذف تصویر">&times;</button>
 
 
 
 
 
 
 
 
 
 
 
 
152
  </div>
153
  <input type="file" id="file-input" accept="image/*" hidden>
154
  </div>
 
155
  <div class="form-group">
156
- <label for="prompt-input" class="form-label"><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>۲. دستور ویرایش را بنویسید</label>
 
 
 
157
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
158
- <button id="submit-btn" disabled><span id="btn-text">خلق کن</span><div class="spinner"></div></button>
 
 
 
159
  <p id="error-message"></p>
160
  </div>
 
161
  <div class="form-group">
162
- <label class="form-label"><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="M10 3L12 8L17 10L12 12L10 17L8 12L3 10L8 8L10 3z"/><path d="M21 14l-1.5 3-3-1.5 3-3 1.5 3z"/><path d="M19.5 2.5l-3 1.5 1.5 3 3-1.5-1.5-3z"/></svg>۳. نتیجه را ببینید</label>
 
 
 
163
  <div id="result-container">
164
- <div id="loading-placeholder"><div class="orbital-loader"><div class="orbit"><div class="satellite"></div></div><div class="orbit"><div class="satellite"></div></div></div><p class="loading-text">هوش مصنوعی در حال خلق اثر شماست...</p></div>
 
 
 
165
  <div id="result-grid"></div>
166
  </div>
167
  </div>
168
  </main>
 
169
  <section class="gallery-section">
170
  <div class="gallery-header">
171
- <label class="form-label"><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"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>گالری و تاریخچه شما</label>
172
- <button id="clear-history-btn"><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="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg><span>پاک کردن</span></button>
 
 
 
 
 
 
173
  </div>
174
  <div id="history-grid"></div>
175
  </section>
176
  </div>
 
177
  <div id="lightbox">
178
  <div id="lightbox-content">
179
- <img id="lightbox-img" src=""><button id="lightbox-close" class="lightbox-btn">&times;</button>
180
- <a id="lightbox-download" href="#" title="دانلود تصویر" class="lightbox-btn"><svg fill="white" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg></a>
 
 
 
 
181
  </div>
182
  </div>
183
 
184
  <script>
185
  const API_URL = 'https://alfa-editor-worker.onrender.com/api/edit';
186
 
187
- const dropZone = document.getElementById('drop-zone'), dropZoneContent = document.getElementById('drop-zone-content'), fileInput = document.getElementById('file-input'), imagePreview = document.getElementById('image-preview'), removePreviewBtn = document.getElementById('remove-preview-btn'), promptInput = document.getElementById('prompt-input'), submitBtn = document.getElementById('submit-btn'), btnText = document.getElementById('btn-text'), btnSpinner = submitBtn.querySelector('.spinner'), resultContainer = document.getElementById('result-container'), resultGrid = document.getElementById('result-grid'), errorMessage = document.getElementById('error-message'), lightbox = document.getElementById('lightbox'), lightboxImg = document.getElementById('lightbox-img'), lightboxClose = document.getElementById('lightbox-close'), lightboxDownload = document.getElementById('lightbox-download'), historyGrid = document.getElementById('history-grid'), clearHistoryBtn = document.getElementById('clear-history-btn');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  let uploadedFile = null;
 
190
 
191
- const resetUploader = () => { uploadedFile = null; fileInput.value = ''; imagePreview.classList.remove('visible'); removePreviewBtn.classList.remove('visible'); dropZoneContent.style.opacity = '1'; checkFormState(); };
 
 
 
 
 
 
192
  const handleFile = (file) => {
193
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.'); return; }
194
  uploadedFile = file;
 
 
195
  const reader = new FileReader();
196
- reader.onload = (e) => { imagePreview.src = e.target.result; imagePreview.classList.add('visible'); removePreviewBtn.classList.add('visible'); dropZoneContent.style.opacity = '0'; };
197
- reader.readAsDataURL(file); checkFormState(); clearResult();
198
- };
199
 
200
- dropZone.addEventListener('click', () => fileInput.click());
 
 
 
 
201
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
202
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => dropZone.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
203
- ['dragenter', 'dragover'].forEach(e => dropZone.addEventListener(e, () => dropZone.classList.add('drag-over')));
204
- ['dragleave', 'drop'].forEach(e => dropZone.addEventListener(e, () => dropZone.classList.remove('drag-over')));
205
- dropZone.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
206
- removePreviewBtn.addEventListener('click', (e) => { e.stopPropagation(); resetUploader(); });
207
 
 
208
  promptInput.addEventListener('input', checkFormState);
209
  function checkFormState() { submitBtn.disabled = !uploadedFile || promptInput.value.trim() === ''; }
210
-
211
  submitBtn.addEventListener('click', async () => {
212
- if (submitBtn.disabled) return; setLoading(true);
213
- const formData = new FormData(); formData.append('image', uploadedFile); formData.append('prompt', promptInput.value.trim());
 
 
 
214
  try {
215
  const response = await fetch(API_URL, { method: 'POST', body: formData });
216
- if (!response.ok) { const errorData = await response.json().catch(() => ({ error: `خطای سرور: ${response.statusText}` })); throw new Error(errorData.error || `یک خطای ناشناخته رخ داد.`); }
 
 
 
217
  const result = await response.json();
218
- if (result.image_urls?.length > 0) { displayResult(result.image_urls); addToHistory({ prompt: promptInput.value.trim(), urls: result.image_urls }); }
219
- else { throw new Error('��اسخ معتبری از سرور دریافت نشد.'); }
220
- } catch (error) { displayError(error.message); } finally { setLoading(false); }
 
 
 
221
  });
222
 
223
  function setLoading(isLoading) {
224
- resultContainer.classList.remove('has-content'); resultContainer.classList.toggle('loading', isLoading);
225
- btnSpinner.style.display = isLoading ? 'inline-block' : 'none';
226
- btnText.textContent = isLoading ? 'در حال پردازش...' : 'خلق کن';
227
- submitBtn.disabled = isLoading;
228
- if(isLoading) { resultGrid.innerHTML = ''; errorMessage.style.display = 'none'; }
 
 
 
 
 
 
 
 
 
229
  }
230
  function displayResult(imageUrls) {
231
  resultGrid.innerHTML = '';
232
- imageUrls.forEach((url) => { const img = document.createElement('img'); img.src = url; img.alt = 'تصویر ویرایش شده'; img.addEventListener('click', () => openLightbox(url)); resultGrid.appendChild(img); });
 
 
 
 
 
 
233
  resultContainer.classList.add('has-content');
234
  }
235
- function clearResult() { resultGrid.innerHTML = ''; errorMessage.style.display = 'none'; resultContainer.classList.remove('has-content'); }
236
- function displayError(message) { errorMessage.textContent = message; errorMessage.style.display = 'block'; }
 
 
 
 
 
 
 
237
 
238
- function openLightbox(url) { lightboxImg.src = url; lightbox.classList.add('visible'); }
239
- function closeLightbox() { lightbox.classList.remove('visible'); }
240
- lightboxClose.addEventListener('click', closeLightbox);
241
- lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
242
-
243
- // --- FIXED DOWNLOAD FUNCTION ---
244
- lightboxDownload.addEventListener('click', async (e) => {
245
- e.preventDefault();
246
- const url = lightboxImg.src;
 
 
 
 
 
 
 
 
 
247
  try {
248
- const response = await fetch(url);
249
  const blob = await response.blob();
250
- const blobUrl = URL.createObjectURL(blob);
251
- const link = document.createElement('a');
252
- link.href = blobUrl;
253
- link.download = `ai-edited-${Date.now()}.png`;
254
- document.body.appendChild(link);
255
- link.click();
256
- document.body.removeChild(link);
257
- URL.revokeObjectURL(blobUrl);
258
- } catch (error) {
259
- console.error('Download failed:', error);
260
- alert('دانلود ��ا مشکل مواجه شد. لطفا دوباره تلاش کنید.');
 
 
 
261
  }
262
- });
 
 
 
 
263
 
 
264
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
265
- const saveHistory = (history) => { localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history)); renderHistory(); };
266
- const addToHistory = (item) => { let history = getHistory(); history.unshift(item); if (history.length > 15) history.pop(); saveHistory(history); };
267
- const handleClearHistory = () => { if (confirm('آیا از پاک کردن تمام تاریخچه مطمئن هستید؟')) { localStorage.removeItem('aiPhotoshopHistory'); renderHistory(); }};
268
-
269
- // --- NEW: DELETE INDIVIDUAL HISTORY ITEM ---
270
- function handleDeleteHistoryItem(index) {
271
- if (confirm('آیا از حذف این مورد از تاریخچه مطمئن هستید؟')) {
272
- let history = getHistory();
273
- history.splice(index, 1);
274
- saveHistory(history);
 
 
 
275
  }
 
 
 
 
 
276
  }
277
-
278
  function renderHistory() {
279
  const history = getHistory();
280
  historyGrid.innerHTML = '';
281
  clearHistoryBtn.style.display = history.length > 0 ? 'flex' : 'none';
 
282
  history.forEach((item, index) => {
283
  const card = document.createElement('div');
284
  card.className = 'history-item';
285
- const imagesHTML = item.urls.map(url => `<img src="${url}" alt="تصویر از تاریخچه" onclick="openLightbox('${url}')">`).join('');
 
 
 
286
  card.innerHTML = `
287
- <button class="history-item-delete-btn" title="حذف این مورد" onclick="handleDeleteHistoryItem(${index})">&times;</button>
 
 
288
  <p class="history-item-prompt">${item.prompt}</p>
289
- <div class="history-item-grid">${imagesHTML}</div>`;
 
290
  historyGrid.appendChild(card);
291
  });
292
  }
293
  clearHistoryBtn.addEventListener('click', handleClearHistory);
294
- document.addEventListener('DOMContentLoaded', renderHistory);
 
 
 
 
 
 
295
 
296
- checkFormState();
 
 
 
297
  </script>
298
  </body>
299
  </html>
 
35
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
36
 
37
  body {
38
+ font-family: var(--app-font);
39
+ background-color: var(--app-bg);
40
+ color: var(--text-primary);
41
+ margin: 0;
42
+ padding: 2.5rem 1rem;
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: flex-start;
46
+ min-height: 100vh;
47
  }
48
  .container { max-width: 820px; width: 100%; }
49
 
50
+ header {
51
+ text-align: center;
52
+ margin-bottom: 2.5rem;
53
+ animation: fadeIn 0.8s 0.1s ease-out backwards;
54
+ }
55
  h1 {
56
+ font-size: 2.8rem;
57
+ font-weight: 800;
58
+ margin: 0 0 0.8rem 0;
59
  background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
60
+ -webkit-background-clip: text;
61
+ -webkit-text-fill-color: transparent;
62
+ letter-spacing: -1px;
63
  }
64
  .subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-top: 0; }
65
 
66
  main, .gallery-section {
67
+ padding: 3rem;
68
+ background-color: var(--panel-bg);
69
+ border-radius: var(--radius-card);
70
+ box-shadow: var(--shadow-xl);
71
+ border: 1px solid var(--panel-border);
72
  animation: fadeIn 0.8s 0.3s ease-out backwards;
73
  }
74
  .gallery-section { margin-top: 3rem; animation-delay: 0.5s; }
 
76
  .form-group { margin-bottom: 2.5rem; }
77
  .form-group:last-child { margin-bottom: 0; }
78
  label.form-label {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 0.75rem;
82
+ font-weight: 700;
83
+ color: var(--text-primary);
84
+ font-size: 1.2em;
85
+ margin-bottom: 1.2rem;
86
  }
87
  label.form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
88
 
89
+ /* --- Uploader Style with Image Preview --- */
90
+ #upload-container.has-file #upload-area { display: none; }
91
+ #upload-container:not(.has-file) #file-preview { display: none; }
92
+
93
+ #upload-area {
94
+ border: 2px dashed var(--input-border);
95
+ border-radius: var(--radius-input);
96
+ padding: 2.5rem;
97
+ text-align: center;
98
+ cursor: pointer;
99
+ transition: var(--transition-smooth);
100
+ background-color: var(--input-bg);
101
+ }
102
+ #upload-area.drag-over, #upload-area:hover {
103
+ border-color: var(--accent-primary);
104
+ background-color: #fff;
105
+ box-shadow: 0 0 15px var(--accent-primary-glow);
106
+ }
107
+ #upload-icon svg { width: 48px; height: 48px; color: var(--accent-primary); margin-bottom: 1rem; stroke-width: 1.5; opacity: 0.8; }
108
+ #upload-area p { margin: 0; color: var(--text-secondary); font-weight: 500; }
109
+
110
+ #file-preview {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 1.5rem;
114
+ padding: 1rem;
115
+ background-color: var(--input-bg);
116
+ border-radius: var(--radius-input);
117
+ border: 1px solid var(--panel-border);
118
+ animation: fadeIn 0.3s;
119
  }
120
+ #preview-image {
121
+ width: 80px;
122
+ height: 80px;
123
+ object-fit: cover;
124
+ border-radius: 8px;
125
+ flex-shrink: 0;
126
+ border: 1px solid var(--panel-border);
127
+ }
128
+ #file-details { flex-grow: 1; }
129
+ #file-name { font-weight: 600; color: var(--text-primary); display: block; margin-bottom: 0.5rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
130
+ #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); }
131
+ #remove-file-btn:hover { color: var(--danger-color); border-color: var(--danger-color); }
132
 
133
  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; }
134
  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); }
 
137
  #submit-btn:disabled { background: var(--text-tertiary); cursor: not-allowed; box-shadow: none; opacity: 0.7; }
138
  #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; }
139
 
140
+ #result-container {
141
+ min-height: 250px; position: relative;
142
+ padding: 1rem; background-color: var(--input-bg);
143
+ border-radius: var(--radius-card); border: 2px dashed var(--input-border);
144
+ box-shadow: var(--shadow-sm) inset; transition: var(--transition-smooth);
145
+ display: flex; align-items: center; justify-content: center;
146
+ }
147
  #result-container.loading, #result-container.has-content { border-style: solid; border-color: var(--panel-border); }
148
  #loading-placeholder { display: none; flex-direction: column; align-items: center; gap: 1.5rem; }
149
  #result-container.loading #loading-placeholder { display: flex; animation: fadeIn 0.5s; }
150
+ .orbital-loader { width: 110px; height: 110px; position: relative; animation: spin 10s linear infinite; } /* MODIFIED: Increased size */
151
  .orbit { position: absolute; top: 50%; left: 50%; border: 2px dashed rgba(74, 108, 250, 0.35); border-radius: 50%; transform-origin: center center; }
152
  .orbit:nth-child(1) { width: 35px; height: 35px; margin: -17.5px 0 0 -17.5px; animation: spin 2.8s linear infinite reverse; }
153
  .orbit:nth-child(2) { width: 70px; height: 70px; margin: -35px 0 0 -35px; animation: spin 3.8s linear infinite; }
 
156
  .orbit:nth-child(2) .satellite { top: 50%; left: -5px; background-color: var(--accent-secondary); transform: translateY(-50%); }
157
  .loading-text { font-weight: 500; color: var(--text-secondary); }
158
 
159
+ #result-grid { display: none; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; width: 100%; } /* MODIFIED: Larger results */
160
  #result-container.has-content #result-grid { display: grid; }
161
+ #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); }
162
  #result-grid img:hover { transform: scale(1.05); box-shadow: var(--shadow-lg); z-index: 10; position: relative; }
163
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
164
 
165
+ /* --- History Gallery Styles --- */
166
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
167
  #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; }
168
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
 
170
  #history-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 1.5rem; }
171
  #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); }
172
  .history-item { position: relative; background-color: var(--input-bg); border-radius: var(--radius-card); border: 1px solid var(--panel-border); padding: 1.5rem; transition: var(--transition-smooth); }
173
+ .history-item:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); }
174
+ .history-item-prompt { font-weight: 600; margin: 0 0 1rem 0; word-break: break-word; padding-left: 30px; }
175
  .history-item-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
176
  .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); }
177
  .history-item-grid img:hover { transform: scale(1.1); box-shadow: var(--shadow-md); z-index: 5; position: relative; }
178
+ .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); }
179
+ .history-delete-btn:hover { background-color: var(--panel-border); color: var(--danger-color); }
180
+ .history-delete-btn svg { width: 18px; height: 18px; }
181
 
182
+ /* --- Lightbox Styles --- */
183
  #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; }
184
  #lightbox.visible { display: flex; opacity: 1; }
185
  #lightbox-content { position: relative; animation: fadeIn 0.3s ease; }
 
189
  #lightbox-close { top: -50px; right: 0; font-size: 1.8rem; }
190
  #lightbox-download { top: -50px; left: 0; }
191
  #lightbox-download svg { width: 22px; height: 22px; }
192
+ #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; }
193
 
194
  @media (max-width: 768px) {
195
  main, .gallery-section { padding: 1.5rem; }
196
  h1 { font-size: 2.2rem; }
 
197
  .history-item-grid { grid-template-columns: repeat(2, 1fr); }
198
  }
199
  </style>
200
  </head>
201
  <body>
202
  <div class="container">
203
+ <header>
204
+ <h1>فتوشاپ هوش مصنوعی ✨</h1>
205
+ <p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی و به زبان ساده ویرایش کنید</p>
206
+ </header>
207
+
208
  <main>
209
  <div class="form-group">
210
+ <label for="upload-area" class="form-label">
211
+ <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="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>
212
+ ۱. تصویر خود را انتخاب کنید
213
+ </label>
214
+ <div id="upload-container">
215
+ <label id="upload-area">
216
+ <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>
217
+ <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
218
+ </label>
219
+ <div id="file-preview">
220
+ <img id="preview-image" src="" alt="Preview"> <!-- NEW: Image preview element -->
221
+ <div id="file-details">
222
+ <span id="file-name"></span>
223
+ <button type="button" id="remove-file-btn">حذف و انتخاب مجدد</button>
224
+ </div>
225
+ </div>
226
  </div>
227
  <input type="file" id="file-input" accept="image/*" hidden>
228
  </div>
229
+
230
  <div class="form-group">
231
+ <label for="prompt-input" class="form-label">
232
+ <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>
233
+ ۲. دستور ویرایش را بنویسید
234
+ </label>
235
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
236
+ <button id="submit-btn" disabled>
237
+ <span id="btn-text">خلق کن</span>
238
+ <div class="spinner"></div>
239
+ </button>
240
  <p id="error-message"></p>
241
  </div>
242
+
243
  <div class="form-group">
244
+ <label class="form-label">
245
+ <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="M10 3L12 8L17 10L12 12L10 17L8 12L3 10L8 8L10 3z"/><path d="M21 14l-1.5 3-3-1.5 3-3 1.5 3z"/><path d="M19.5 2.5l-3 1.5 1.5 3 3-1.5-1.5-3z"/></svg>
246
+ ۳. نتیجه را ببینید
247
+ </label>
248
  <div id="result-container">
249
+ <div id="loading-placeholder">
250
+ <div class="orbital-loader"><div class="orbit"><div class="satellite"></div></div><div class="orbit"><div class="satellite"></div></div></div>
251
+ <p class="loading-text">هوش مصنوعی در حال خلق اثر شماست...</p>
252
+ </div>
253
  <div id="result-grid"></div>
254
  </div>
255
  </div>
256
  </main>
257
+
258
  <section class="gallery-section">
259
  <div class="gallery-header">
260
+ <label class="form-label">
261
+ <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"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>
262
+ گالری و تاریخچه شما
263
+ </label>
264
+ <button id="clear-history-btn">
265
+ <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="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
266
+ <span>پاک کردن همه</span>
267
+ </button>
268
  </div>
269
  <div id="history-grid"></div>
270
  </section>
271
  </div>
272
+
273
  <div id="lightbox">
274
  <div id="lightbox-content">
275
+ <img id="lightbox-img" src="">
276
+ <button id="lightbox-close" class="lightbox-btn">&times;</button>
277
+ <a id="lightbox-download" title="دانلود تصویر" class="lightbox-btn">
278
+ <svg fill="white" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
279
+ <div class="spinner"></div>
280
+ </a>
281
  </div>
282
  </div>
283
 
284
  <script>
285
  const API_URL = 'https://alfa-editor-worker.onrender.com/api/edit';
286
 
287
+ const uploadContainer = document.getElementById('upload-container');
288
+ const uploadArea = document.getElementById('upload-area');
289
+ const fileInput = document.getElementById('file-input');
290
+ const filePreview = document.getElementById('file-preview');
291
+ const previewImage = document.getElementById('preview-image');
292
+ const fileNameSpan = document.getElementById('file-name');
293
+ const removeFileBtn = document.getElementById('remove-file-btn');
294
+ const promptInput = document.getElementById('prompt-input');
295
+ const submitBtn = document.getElementById('submit-btn');
296
+ const btnText = document.getElementById('btn-text');
297
+ const btnSpinner = submitBtn.querySelector('.spinner');
298
+ const resultContainer = document.getElementById('result-container');
299
+ const resultGrid = document.getElementById('result-grid');
300
+ const errorMessage = document.getElementById('error-message');
301
+ const lightbox = document.getElementById('lightbox');
302
+ const lightboxImg = document.getElementById('lightbox-img');
303
+ const lightboxClose = document.getElementById('lightbox-close');
304
+ const lightboxDownload = document.getElementById('lightbox-download');
305
+ const historyGrid = document.getElementById('history-grid');
306
+ const clearHistoryBtn = document.getElementById('clear-history-btn');
307
 
308
  let uploadedFile = null;
309
+ let currentLightboxUrl = null;
310
 
311
+ // --- Uploader Logic ---
312
+ const resetUploader = () => {
313
+ uploadedFile = null;
314
+ fileInput.value = '';
315
+ uploadContainer.classList.remove('has-file');
316
+ checkFormState();
317
+ };
318
  const handleFile = (file) => {
319
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری معتبر انتخاب کنید.'); return; }
320
  uploadedFile = file;
321
+ fileNameSpan.textContent = file.name;
322
+
323
  const reader = new FileReader();
324
+ reader.onload = (e) => { previewImage.src = e.target.result; };
325
+ reader.readAsDataURL(file);
 
326
 
327
+ uploadContainer.classList.add('has-file');
328
+ checkFormState();
329
+ clearResult();
330
+ };
331
+ uploadArea.addEventListener('click', () => fileInput.click());
332
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
333
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, p => { p.preventDefault(); p.stopPropagation(); }));
334
+ ['dragenter', 'dragover'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.add('drag-over')));
335
+ ['dragleave', 'drop'].forEach(e => uploadArea.addEventListener(e, () => uploadArea.classList.remove('drag-over')));
336
+ uploadArea.addEventListener('drop', e => handleFile(e.dataTransfer.files[0]));
337
+ removeFileBtn.addEventListener('click', resetUploader);
338
 
339
+ // --- Form & Submission ---
340
  promptInput.addEventListener('input', checkFormState);
341
  function checkFormState() { submitBtn.disabled = !uploadedFile || promptInput.value.trim() === ''; }
 
342
  submitBtn.addEventListener('click', async () => {
343
+ if (submitBtn.disabled) return;
344
+ setLoading(true);
345
+ const formData = new FormData();
346
+ formData.append('image', uploadedFile);
347
+ formData.append('prompt', promptInput.value.trim());
348
  try {
349
  const response = await fetch(API_URL, { method: 'POST', body: formData });
350
+ if (!response.ok) {
351
+ const errorData = await response.json().catch(() => ({ error: `خطای سرور: ${response.statusText}` }));
352
+ throw new Error(errorData.error || `یک خطای ناشناخته رخ داد.`);
353
+ }
354
  const result = await response.json();
355
+ if (result.image_urls && Array.isArray(result.image_urls) && result.image_urls.length > 0) {
356
+ displayResult(result.image_urls);
357
+ addToHistory({ prompt: promptInput.value.trim(), urls: result.image_urls });
358
+ } else { throw new Error('پاسخ معتبری از سرور دریافت نشد.'); }
359
+ } catch (error) { displayError(error.message); }
360
+ finally { setLoading(false); }
361
  });
362
 
363
  function setLoading(isLoading) {
364
+ if (isLoading) {
365
+ resultContainer.classList.remove('has-content');
366
+ resultContainer.classList.add('loading');
367
+ btnSpinner.style.display = 'inline-block';
368
+ btnText.textContent = 'در حال پردازش...';
369
+ submitBtn.disabled = true;
370
+ resultGrid.innerHTML = '';
371
+ errorMessage.style.display = 'none';
372
+ } else {
373
+ resultContainer.classList.remove('loading');
374
+ btnSpinner.style.display = 'none';
375
+ btnText.textContent = 'خلق کن';
376
+ checkFormState();
377
+ }
378
  }
379
  function displayResult(imageUrls) {
380
  resultGrid.innerHTML = '';
381
+ imageUrls.forEach((url) => {
382
+ const img = document.createElement('img');
383
+ img.src = url;
384
+ img.alt = 'تصویر ویرایش شده';
385
+ img.addEventListener('click', () => openLightbox(url));
386
+ resultGrid.appendChild(img);
387
+ });
388
  resultContainer.classList.add('has-content');
389
  }
390
+ function clearResult() {
391
+ resultGrid.innerHTML = '';
392
+ errorMessage.style.display = 'none';
393
+ resultContainer.classList.remove('has-content');
394
+ }
395
+ function displayError(message) {
396
+ errorMessage.textContent = message;
397
+ errorMessage.style.display = 'block';
398
+ }
399
 
400
+ // --- Lightbox Functions & Download Fix ---
401
+ function openLightbox(url) {
402
+ currentLightboxUrl = url;
403
+ lightboxImg.src = url;
404
+ lightbox.classList.add('visible');
405
+ }
406
+ function closeLightbox() {
407
+ lightbox.classList.remove('visible');
408
+ currentLightboxUrl = null;
409
+ }
410
+ async function handleDownload() {
411
+ if (!currentLightboxUrl) return;
412
+ const downloadBtn = lightboxDownload;
413
+ const spinner = downloadBtn.querySelector('.spinner');
414
+ const icon = downloadBtn.querySelector('svg');
415
+
416
+ spinner.style.display = 'block';
417
+ icon.style.display = 'none';
418
  try {
419
+ const response = await fetch(currentLightboxUrl);
420
  const blob = await response.blob();
421
+ const objectUrl = URL.createObjectURL(blob);
422
+ const a = document.createElement('a');
423
+ a.href = objectUrl;
424
+ a.download = `edited-image-${Date.now()}.png`;
425
+ document.body.appendChild(a);
426
+ a.click();
427
+ document.body.removeChild(a);
428
+ URL.revokeObjectURL(objectUrl);
429
+ } catch (e) {
430
+ console.error('Download failed:', e);
431
+ alert('خطا در دانلود تصویر. لطفا دوباره تلاش کنید.');
432
+ } finally {
433
+ spinner.style.display = 'none';
434
+ icon.style.display = 'block';
435
  }
436
+ }
437
+ lightboxClose.addEventListener('click', closeLightbox);
438
+ lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
439
+ lightboxDownload.addEventListener('click', handleDownload);
440
+
441
 
442
+ // --- History Management with Individual Delete ---
443
  const getHistory = () => JSON.parse(localStorage.getItem('aiPhotoshopHistory') || '[]');
444
+ const saveHistory = (history) => {
445
+ localStorage.setItem('aiPhotoshopHistory', JSON.stringify(history));
446
+ renderHistory();
447
+ };
448
+ const addToHistory = (item) => {
449
+ let history = getHistory();
450
+ history.unshift(item);
451
+ if (history.length > 15) history.pop();
452
+ saveHistory(history);
453
+ };
454
+ const handleClearHistory = () => {
455
+ if (confirm('آیا از پاک کردن تمام تاریخچه مطمئن هستید؟')) {
456
+ saveHistory([]);
457
  }
458
+ };
459
+ const handleDeleteItem = (index) => {
460
+ let history = getHistory();
461
+ history.splice(index, 1);
462
+ saveHistory(history);
463
  }
 
464
  function renderHistory() {
465
  const history = getHistory();
466
  historyGrid.innerHTML = '';
467
  clearHistoryBtn.style.display = history.length > 0 ? 'flex' : 'none';
468
+
469
  history.forEach((item, index) => {
470
  const card = document.createElement('div');
471
  card.className = 'history-item';
472
+ const imagesHTML = item.urls.map(url =>
473
+ `<img src="${url}" alt="تصویر از تاریخچه" onclick="openLightbox('${url}')">`
474
+ ).join('');
475
+
476
  card.innerHTML = `
477
+ <button class="history-delete-btn" data-index="${index}" title="حذف این مورد">
478
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
479
+ </button>
480
  <p class="history-item-prompt">${item.prompt}</p>
481
+ <div class="history-item-grid">${imagesHTML}</div>
482
+ `;
483
  historyGrid.appendChild(card);
484
  });
485
  }
486
  clearHistoryBtn.addEventListener('click', handleClearHistory);
487
+ historyGrid.addEventListener('click', (e) => {
488
+ const deleteBtn = e.target.closest('.history-delete-btn');
489
+ if (deleteBtn) {
490
+ const indexToDelete = parseInt(deleteBtn.dataset.index, 10);
491
+ handleDeleteItem(indexToDelete);
492
+ }
493
+ });
494
 
495
+ document.addEventListener('DOMContentLoaded', () => {
496
+ renderHistory();
497
+ checkFormState();
498
+ });
499
  </script>
500
  </body>
501
  </html>