Elias207 commited on
Commit
5c3a601
·
verified ·
1 Parent(s): ccaf87d

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +173 -333
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>فتوشاپ هوش مصنوعی (نسخه گالری حرفهای)</title>
7
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700;800&display=swap" rel="stylesheet">
8
  <style>
9
  :root {
@@ -21,16 +21,7 @@
21
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
22
  }
23
 
24
- .dark {
25
- --bg-start: #0f172a;
26
- --bg-end: #0b1120;
27
- --text-color: #e2e8f0;
28
- --card-bg: #1e293b;
29
- --border-color: #334155;
30
- --shadow-color-light: rgba(0, 0, 0, 0.2);
31
- --shadow-color-dark: rgba(0, 0, 0, 0.25);
32
- --drop-zone-bg: #111827;
33
- }
34
 
35
  @keyframes fadeInUp {
36
  from { opacity: 0; transform: translateY(30px); }
@@ -51,43 +42,15 @@
51
  transition: background-color 0.4s, color 0.4s;
52
  }
53
 
54
- .container {
55
- max-width: 750px;
56
- width: 100%;
57
- }
58
-
59
- header {
60
- text-align: center;
61
- margin-bottom: 3rem;
62
- animation: fadeInUp 0.8s var(--ease-out-expo) forwards;
63
- }
64
-
65
- h1 {
66
- font-size: 3rem;
67
- font-weight: 800;
68
- letter-spacing: -1px;
69
- margin: 0;
70
- background: linear-gradient(45deg, var(--primary-color-start), var(--primary-color-end));
71
- -webkit-background-clip: text;
72
- -webkit-text-fill-color: transparent;
73
- }
74
-
75
- p.subtitle {
76
- font-size: 1.2rem;
77
- color: #64748b;
78
- margin-top: 0.75rem;
79
- }
80
- .dark p.subtitle { color: #94a3b8; }
81
 
82
  main, .gallery-section {
83
- background-color: var(--card-bg);
84
- border-radius: 2rem;
85
- border: 1px solid var(--border-color);
86
  box-shadow: 0 4px 10px var(--shadow-color-dark), 0 20px 40px var(--shadow-color-light);
87
- padding: 3rem;
88
- transition: all 0.4s;
89
- animation: fadeInUp 0.8s var(--ease-out-expo) forwards;
90
- opacity: 0;
91
  }
92
  main { animation-delay: 0.2s; }
93
  .gallery-section { margin-top: 3rem; animation-delay: 0.4s; }
@@ -96,237 +59,104 @@
96
  .panel:last-child { margin-bottom: 0; }
97
  .controls { margin-bottom: 2.5rem; }
98
 
99
- h2 {
100
- font-size: 1.4rem;
101
- font-weight: 700;
102
- margin: 0 0 1.5rem 0;
103
- padding-bottom: 1rem;
104
- display: flex;
105
- align-items: center;
106
- gap: 0.75rem;
107
- border-bottom: 1px solid var(--border-color);
108
- }
109
  h2 svg { color: var(--primary-color-start); }
110
 
111
  #drop-zone {
112
- border: 2px dashed var(--border-color); border-radius: 1.5rem;
113
- padding: 2rem; text-align: center; cursor: pointer;
114
- transition: all 0.3s var(--ease-out-expo);
115
- position: relative; overflow: hidden; background-color: var(--drop-zone-bg);
116
- display: flex; flex-direction: column; justify-content: center;
117
  align-items: center; min-height: 250px;
118
  }
119
- #drop-zone::before {
120
- content: ''; position: absolute; inset: -2px; border-radius: 1.5rem;
121
- background: linear-gradient(45deg, var(--primary-color-start), var(--primary-color-end)) border-box;
122
- -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
123
- mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
124
- -webkit-mask-composite: destination-out; mask-composite: subtract;
125
- opacity: 0; transition: opacity 0.3s ease;
126
- }
127
- #drop-zone.dragover, #drop-zone:hover {
128
- border-color: transparent; transform: translateY(-5px);
129
- box-shadow: 0 10px 20px -5px var(--shadow-color-light);
130
- }
131
- #drop-zone.dragover::before, #drop-zone:hover::before { opacity: 1; }
132
- #drop-zone-content { transition: opacity 0.3s ease, transform 0.3s ease; display: flex; flex-direction: column; align-items: center; gap: 1rem; }
133
- #drop-zone:hover #drop-zone-content { transform: translateY(-5px); }
134
- #drop-zone-icon { width: 40px; height: 40px; color: #94a3b8; }
135
- #drop-zone-text { color: #475569; font-weight: 500; }
136
- .dark #drop-zone-text { color: #94a3b8; }
137
-
138
  .upload-btn-styled {
139
- background-image: linear-gradient(45deg, var(--primary-color-start) 0%, var(--primary-color-end) 100%);
140
- color: white; border: none; padding: 0.75rem 1.5rem;
141
- border-radius: 0.75rem; font-family: 'Vazirmatn', sans-serif;
142
- font-weight: 600; font-size: 1rem; cursor: pointer;
143
- margin-top: 1rem; transition: all 0.3s ease;
144
  }
145
  .upload-btn-styled:hover { transform: translateY(-3px) scale(1.05); box-shadow: 0 8px 15px var(--shadow-color-light); }
146
-
147
- #image-preview {
148
- position: absolute; inset: 0; width: 100%; height: 100%;
149
- padding: 1rem; box-sizing: border-box; border-radius: 1.5rem;
150
- object-fit: contain; opacity: 0; transform: scale(0.95);
151
- transition: opacity 0.4s ease, transform 0.4s ease;
152
- pointer-events: none; backdrop-filter: blur(4px);
153
- }
154
  #image-preview.visible { opacity: 1; transform: scale(1); pointer-events: auto; }
155
 
156
- textarea {
157
- width: 100%; padding: 1rem; border: 2px solid var(--border-color);
158
- border-radius: 1rem; background-color: var(--drop-zone-bg);
159
- color: var(--text-color); font-family: 'Vazirmatn', sans-serif;
160
- font-size: 1rem; resize: vertical; min-height: 80px;
161
- box-sizing: border-box; transition: all 0.3s ease;
162
- }
163
- textarea:focus {
164
- outline: none; border-color: var(--primary-color-start);
165
- box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary-color-start) 15%, transparent);
166
- }
167
 
168
- button#submit-btn {
169
- position: relative; overflow: hidden;
170
- width: 100%; padding: 1.1rem; border: none; border-radius: 1rem;
171
- background-image: linear-gradient(45deg, var(--primary-color-start) 0%, var(--primary-color-end) 100%);
172
- background-size: 200% auto; color: white;
173
- font-size: 1.1rem; font-weight: 700; cursor: pointer;
174
- margin-top: 1rem; transition: all 0.4s var(--ease-out-expo);
175
- box-shadow: 0 4px 15px var(--shadow-color-light);
176
- }
177
- button#submit-btn:hover:not(:disabled) {
178
- transform: translateY(-4px);
179
- box-shadow: 0 10px 25px -5px var(--shadow-color-light);
180
- background-position: right center;
181
- }
182
  button#submit-btn:disabled { opacity: 0.5; cursor: not-allowed; }
183
- .loader-dots {
184
- display: flex; justify-content: center; align-items: center;
185
- position: absolute; inset: 0;
186
- }
187
- .loader-dots div {
188
- width: 8px; height: 8px; margin: 0 4px; background-color: white; border-radius: 50%;
189
- animation: bounce 1.4s infinite ease-in-out both;
190
- }
191
- .loader-dots .dot1 { animation-delay: -0.32s; }
192
- .loader-dots .dot2 { animation-delay: -0.16s; }
193
  @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1.0); } }
194
  #btn-text.hidden { visibility: hidden; }
195
 
196
- #result-container {
197
- border: 2px solid var(--border-color); border-radius: 1.5rem;
198
- min-height: 250px;
199
- position: relative;
200
- background-color: var(--drop-zone-bg); overflow: hidden;
201
- padding: 0.5rem; transition: border-color 0.3s ease;
202
- }
203
-
204
- #loading-placeholder {
205
- display: none; flex-direction: column; align-items: center; justify-content: center;
206
- gap: 1.5rem; opacity: 0; animation: fadeIn 0.5s ease forwards;
207
- position: absolute; inset: 0;
208
- }
209
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
210
  #result-container.loading #loading-placeholder { display: flex; }
211
-
212
- .creative-loader { width: 100px; height: 100px; position: relative; }
213
- .creative-loader svg { width: 100%; height: 100%; transform-origin: center; }
214
- .creative-loader .arc { fill: none; stroke-width: 4; stroke-linecap: round; transform-origin: 50% 50%; animation: spin-loader 2s linear infinite; }
215
- .creative-loader .arc1 { stroke: var(--primary-color-start); animation-duration: 2.2s; }
216
- .creative-loader .arc2 { stroke: var(--primary-color-end); animation-duration: 1.8s; animation-direction: reverse; }
217
- .creative-loader .arc3 { stroke: #8b5cf6; animation-duration: 2s; }
218
- .creative-loader .star { fill: var(--primary-color-end); transform-origin: center; animation: pulse-star 1.5s ease-in-out infinite; }
219
- @keyframes spin-loader { to { transform: rotate(360deg); } }
220
- @keyframes pulse-star { 0%, 100% { transform: scale(0.9); opacity: 0.8; } 50% { transform: scale(1.1); opacity: 1; } }
221
-
222
- .loading-text { font-weight: 500; color: #64748b; }
223
- .dark .loading-text { color: #94a3b8; }
224
 
225
- #result-grid {
226
- display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
227
- gap: 0.5rem; width: 100%; height: 100%;
228
- }
229
  @keyframes popIn-spring { 0% { opacity: 0; transform: scale(0.8) translateY(20px); } 80% { opacity: 1; transform: scale(1.05) translateY(-5px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
230
- #result-grid img {
231
- width: 100%; height: 100%; max-height: 250px; object-fit: cover; border-radius: 1rem;
232
- cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease;
233
- opacity: 0; animation: popIn-spring 0.6s var(--ease-out-expo) forwards;
234
- }
235
- #result-grid img:hover { transform: scale(1.05) rotate(1deg); box-shadow: 0 10px 30px -5px var(--shadow-color-dark); }
236
 
237
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
238
 
239
- #lightbox {
240
- position: fixed; top: 0; left: 0; width: 100%; height: 100%;
241
- background-color: rgba(10, 20, 40, 0.85); z-index: 1000; display: none;
242
- justify-content: center; align-items: center; padding: 2rem;
243
- box-sizing: border-box; backdrop-filter: blur(8px);
244
- }
245
- #lightbox-img { max-width: 90vw; max-height: 85vh; object-fit: contain; border-radius: 1rem; box-shadow: 0 20px 50px rgba(0,0,0,0.5); }
246
- #lightbox-controls { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 1rem; }
247
- .lightbox-btn {
248
- background-color: rgba(255, 255, 255, 0.1); color: white; border: 1px solid rgba(255,255,255,0.2);
249
- width: 50px; height: 50px; border-radius: 50%; cursor: pointer; display: flex;
250
- justify-content: center; align-items: center; transition: all 0.2s; text-decoration: none;
251
- }
252
- .lightbox-btn svg { width: 24px; height: 24px; }
253
  .lightbox-btn:hover { background-color: rgba(255, 255, 255, 0.2); transform: scale(1.1); }
254
- #lightbox-close { position: absolute; top: 20px; right: 20px; font-size: 2rem; }
 
 
 
255
 
 
 
 
256
  /* --- History Gallery Styles --- */
257
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
258
- #clear-history-btn {
259
- background: none; border: 1px solid var(--border-color); color: #64748b;
260
- padding: 0.5rem 1rem; border-radius: 0.75rem; cursor: pointer;
261
- display: flex; align-items: center; gap: 0.5rem;
262
- font-family: 'Vazirmatn', sans-serif; font-weight: 500; transition: all 0.2s;
263
- }
264
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
265
- #clear-history-btn svg { width: 18px; height: 18px; }
266
-
267
- #history-grid {
268
- display: grid;
269
- grid-template-columns: 1fr;
270
- gap: 1.5rem;
271
- margin-top: 1.5rem;
272
- }
273
- #history-grid:empty::before {
274
- content: 'هنوز تصویری خلق نکرده‌اید. اولین ویرایش شما اینجا ذخیره خواهد شد.';
275
- color: #64748b;
276
- .dark & { color: #94a3b8; }
277
- grid-column: 1 / -1;
278
- text-align: center;
279
- padding: 3rem 1rem;
280
- background-color: var(--drop-zone-bg);
281
- border-radius: 1rem;
282
- }
283
- .history-item {
284
- background-color: var(--drop-zone-bg);
285
- border-radius: 1.25rem;
286
- border: 1px solid var(--border-color);
287
- overflow: hidden;
288
- box-shadow: 0 2px 8px var(--shadow-color-dark);
289
- transition: transform 0.3s ease, box-shadow 0.3s ease, opacity 0.5s ease;
290
- opacity: 0; animation: popIn-spring 0.6s var(--ease-out-expo) forwards;
291
- display: flex; flex-direction: column;
292
- }
293
  .history-item.removing { transform: scale(0.9); opacity: 0; }
294
  .history-item:hover { transform: translateY(-8px); box-shadow: 0 10px 20px var(--shadow-color-dark); }
295
 
296
- .history-item-thumbnails {
297
- display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; padding: 0.5rem;
298
- }
299
- .history-item-thumbnails img {
300
- width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 0.75rem;
301
- cursor: pointer; transition: transform 0.2s ease;
302
- }
303
  .history-item-thumbnails img:hover { transform: scale(1.08); }
304
 
305
  .history-item-content { padding: 0 1.25rem 1.25rem 1.25rem; border-top: 1px solid var(--border-color); }
306
- .history-item-prompt {
307
- font-size: 0.95rem; font-weight: 500;
308
- margin: 1rem 0 1rem 0;
309
- line-height: 1.6em;
310
- }
311
- .history-item-footer { display: flex; justify-content: space-between; align-items: center; }
312
- .history-btn.delete-btn {
313
- background-color: transparent; color: var(--danger-color); border: 1px solid var(--danger-color);
314
- padding: 0.5rem 1rem; border-radius: 0.75rem; cursor: pointer; display: flex; align-items: center; gap: 0.5rem;
315
- font-weight: 600; transition: all 0.2s;
316
- }
317
- .history-btn.delete-btn:hover { background-color: var(--danger-color); color: white; }
318
 
319
  @media (max-width: 600px) {
320
  body { padding: 1.5rem 1rem; }
321
  main, .gallery-section { padding: 1.5rem; }
322
  h1 { font-size: 2.5rem; }
323
  .history-item-thumbnails { grid-template-columns: repeat(2, 1fr); }
 
 
 
324
  }
325
  </style>
326
  </head>
327
  <body>
328
 
329
  <div class="container">
 
330
  <header>
331
  <h1>فتوشاپ هوش مصنوعی ✨</h1>
332
  <p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی و به زبان ساده ویرایش کنید</p>
@@ -334,13 +164,9 @@
334
 
335
  <main>
336
  <div class="panel">
337
- <h2>
338
- <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="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>
339
- ۱. تصویر خود را انتخاب کنید
340
- </h2>
341
  <div id="drop-zone">
342
  <div id="drop-zone-content">
343
- <svg id="drop-zone-icon" 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="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>
344
  <span id="drop-zone-text">تصویر را اینجا بکشید یا از دکمه زیر استفاده کنید</span>
345
  <button class="upload-btn-styled">انتخاب فایل</button>
346
  </div>
@@ -348,30 +174,17 @@
348
  </div>
349
  <input type="file" id="file-input" accept="image/*" hidden>
350
  </div>
351
-
352
- <!-- Rest of the main content remains the same -->
353
  <div class="controls">
354
- <h2>
355
- <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="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>
356
- ۲. دستور ویرایش را بنویسید
357
- </h2>
358
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
359
- <button id="submit-btn" disabled>
360
- <span id="btn-text">خلق کن</span>
361
- </button>
362
  <p id="error-message"></p>
363
  </div>
364
-
365
  <div class="panel">
366
- <h2>
367
- <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="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>
368
- ۳. نتیجه را ببینید
369
- </h2>
370
  <div id="result-container">
371
  <div id="loading-placeholder">
372
- <div class="creative-loader">
373
- <svg viewBox="0 0 50 50"><g><circle class="arc arc1" cx="25" cy="25" r="22" stroke-dasharray="60 150"></circle><circle class="arc arc2" cx="25" cy="25" r="18" stroke-dasharray="60 150"></circle><circle class="arc arc3" cx="25" cy="25" r="14" stroke-dasharray="60 150"></circle><path class="star" d="M25,21 L26.9,24.1 L30,25 L26.9,25.9 L25,29 L23.1,25.9 L20,25 L23.1,24.1 Z"></path></g></svg>
374
- </div>
375
  <p class="loading-text">هوش مصنوعی در حال خلق اثر شماست...</p>
376
  </div>
377
  <div id="result-grid"></div>
@@ -379,14 +192,11 @@
379
  </div>
380
  </main>
381
 
 
382
  <section class="gallery-section">
383
  <div class="gallery-header">
384
- <h2>
385
- <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"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>
386
- گالری و تاریخچه شما
387
- </h2>
388
  <button id="clear-history-btn" style="display: none;">
389
- <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>
390
  <span>پاک کردن همه</span>
391
  </button>
392
  </div>
@@ -394,14 +204,21 @@
394
  </section>
395
  </div>
396
 
 
397
  <div id="lightbox">
398
- <img id="lightbox-img" src="">
399
- <div id="lightbox-controls">
400
- <a id="lightbox-download" href="#" download="edited-image.png" title="دانلود تصویر" class="lightbox-btn">
401
- <svg fill="white" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
402
- </a>
403
- </div>
404
- <button id="lightbox-close" class="lightbox-btn">&times;</button>
 
 
 
 
 
 
405
  </div>
406
 
407
  <script>
@@ -410,9 +227,10 @@
410
  const HISTORY_KEY = 'aiPhotoshopHistory';
411
 
412
  // Element Selectors
 
413
  const dropZone = document.getElementById('drop-zone');
414
  const dropZoneContent = document.getElementById('drop-zone-content');
415
- const fileInput = document.getElementById('file-input');
416
  const imagePreview = document.getElementById('image-preview');
417
  const promptInput = document.getElementById('prompt-input');
418
  const submitBtn = document.getElementById('submit-btn');
@@ -420,34 +238,38 @@
420
  const resultContainer = document.getElementById('result-container');
421
  const resultGrid = document.getElementById('result-grid');
422
  const errorMessage = document.getElementById('error-message');
 
 
 
423
  const lightbox = document.getElementById('lightbox');
424
  const lightboxImg = document.getElementById('lightbox-img');
425
  const lightboxClose = document.getElementById('lightbox-close');
426
  const lightboxDownload = document.getElementById('lightbox-download');
427
- const historyGrid = document.getElementById('history-grid');
428
- const clearHistoryBtn = document.getElementById('clear-history-btn');
429
- const uploadBtnStyled = document.querySelector('.upload-btn-styled'); // New upload button
430
 
 
431
  let uploadedFile = null;
 
 
 
432
 
433
  // --- Event Listeners Setup ---
434
  dropZone.addEventListener('click', () => fileInput.click());
435
- uploadBtnStyled.addEventListener('click', (e) => {
436
- e.stopPropagation(); // Prevent dropzone click from firing twice
437
- fileInput.click();
438
- });
439
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
440
  ['dragenter', 'dragover'].forEach(eventName => dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dropZone.classList.add('dragover'); }));
441
  ['dragleave', 'drop'].forEach(eventName => dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dropZone.classList.remove('dragover'); }));
442
  dropZone.addEventListener('drop', (e) => handleFile(e.dataTransfer.files[0]));
443
  promptInput.addEventListener('input', checkFormState);
444
  submitBtn.addEventListener('click', handleSubmit);
 
445
  lightboxClose.addEventListener('click', closeLightbox);
446
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
447
- clearHistoryBtn.addEventListener('click', handleClearHistory);
 
448
  document.addEventListener('DOMContentLoaded', renderHistory);
449
 
450
- // --- Core Functions ---
451
  function handleFile(file) {
452
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری انتخاب کنید.'); return; }
453
  uploadedFile = file;
@@ -474,12 +296,9 @@
474
  formData.append('prompt', promptInput.value.trim());
475
  try {
476
  const response = await fetch(API_URL, { method: 'POST', body: formData });
477
- if (!response.ok) {
478
- const errorData = await response.json().catch(() => ({ error: `خطای سرور: ${response.statusText}` }));
479
- throw new Error(errorData.error || `یک خطای ناشناخته رخ داد.`);
480
- }
481
  const result = await response.json();
482
- if (result.image_urls && Array.isArray(result.image_urls) && result.image_urls.length > 0) {
483
  displayResult(result.image_urls);
484
  addToHistory({ prompt: promptInput.value.trim(), urls: result.image_urls, id: Date.now() });
485
  } else {
@@ -496,10 +315,12 @@
496
  if (isLoading) {
497
  resultContainer.classList.add('loading');
498
  btnText.classList.add('hidden');
499
- const loader = document.createElement('div');
500
- loader.className = 'loader-dots';
501
- loader.innerHTML = '<div class="dot1"></div><div class="dot2"></div><div class="dot3"></div>';
502
- submitBtn.appendChild(loader);
 
 
503
  submitBtn.disabled = true;
504
  resultGrid.innerHTML = '';
505
  errorMessage.style.display = 'none';
@@ -507,7 +328,7 @@
507
  resultContainer.classList.remove('loading');
508
  btnText.classList.remove('hidden');
509
  const loader = submitBtn.querySelector('.loader-dots');
510
- if (loader) submitBtn.removeChild(loader);
511
  checkFormState();
512
  }
513
  }
@@ -518,8 +339,9 @@
518
  const img = document.createElement('img');
519
  img.src = url;
520
  img.alt = 'تصویر ویرایش شده';
 
521
  img.style.animationDelay = `${index * 120}ms`;
522
- img.addEventListener('click', () => openLightbox(url));
523
  resultGrid.appendChild(img);
524
  });
525
  }
@@ -528,50 +350,76 @@
528
  resultGrid.innerHTML = '';
529
  errorMessage.style.display = 'none';
530
  }
531
-
532
  function displayError(message) {
533
  errorMessage.textContent = message;
534
  errorMessage.style.display = 'block';
535
  }
536
 
537
- function openLightbox(url) {
538
- lightboxImg.src = url;
539
- lightboxDownload.href = url;
 
540
  lightbox.style.display = 'flex';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
541
  }
542
- function closeLightbox() { lightbox.style.display = 'none'; }
543
 
544
  // --- History Management Functions ---
545
  function getHistory() {
546
- try {
547
- const history = localStorage.getItem(HISTORY_KEY);
548
- return history ? JSON.parse(history) : [];
549
- } catch (e) {
550
- console.error("Failed to parse history from localStorage", e);
551
- return [];
552
- }
553
  }
554
-
555
  function saveHistory(history) {
556
  localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
557
  renderHistory();
558
  }
559
-
560
  function addToHistory(item) {
561
  let history = getHistory();
562
  history.unshift(item);
563
- if (history.length > 20) history.pop();
564
  saveHistory(history);
565
  }
566
-
567
  function deleteHistoryItem(id) {
568
- let history = getHistory();
569
- const updatedHistory = history.filter(item => item.id !== id);
570
- saveHistory(updatedHistory);
571
  }
572
-
573
  function handleClearHistory() {
574
- if (confirm('آیا از پاک کردن تمام تاریخچه ویرایش‌ها مطمئن هستید؟')) {
575
  localStorage.removeItem(HISTORY_KEY);
576
  renderHistory();
577
  }
@@ -580,53 +428,45 @@
580
  function renderHistory() {
581
  const history = getHistory();
582
  historyGrid.innerHTML = '';
583
-
584
  clearHistoryBtn.style.display = history.length > 0 ? 'flex' : 'none';
585
 
586
- history.forEach((item, index) => {
587
  const card = document.createElement('div');
588
  card.className = 'history-item';
589
- card.style.animationDelay = `${index * 80}ms`;
590
 
591
  const thumbnailsContainer = document.createElement('div');
592
  thumbnailsContainer.className = 'history-item-thumbnails';
593
- item.urls.forEach(url => {
594
  const img = document.createElement('img');
595
  img.src = url;
596
- img.alt = 'تصویر کوچک تاریخچه';
597
- img.addEventListener('click', () => openLightbox(url));
598
  thumbnailsContainer.appendChild(img);
599
  });
600
 
601
- card.appendChild(thumbnailsContainer);
602
-
603
- card.innerHTML += `
604
- <div class="history-item-content">
605
- <p class="history-item-prompt">${item.prompt}</p>
606
- <div class="history-item-footer">
607
- <button class="history-btn delete-btn" data-id="${item.id}">
608
- <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>
609
- حذف
610
- </button>
611
- </div>
612
- </div>
613
- `;
614
- // Re-append the thumbnails container because innerHTML overwrites it
615
- card.insertBefore(thumbnailsContainer, card.firstChild);
616
 
617
- card.querySelector('.delete-btn').addEventListener('click', (e) => {
 
618
  const idToDelete = Number(e.currentTarget.getAttribute('data-id'));
619
  const cardElement = e.currentTarget.closest('.history-item');
620
  cardElement.classList.add('removing');
621
- setTimeout(() => {
622
- deleteHistoryItem(idToDelete);
623
- }, 500); // Wait for animation
624
  });
625
 
 
 
626
  historyGrid.appendChild(card);
627
  });
628
  }
629
-
630
  checkFormState();
631
  </script>
632
  </body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>فتوشاپ هوش مصنوعی (نسخه نهایی)</title>
7
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700;800&display=swap" rel="stylesheet">
8
  <style>
9
  :root {
 
21
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
22
  }
23
 
24
+ .dark { /* Dark mode variables can be added here if needed */ }
 
 
 
 
 
 
 
 
 
25
 
26
  @keyframes fadeInUp {
27
  from { opacity: 0; transform: translateY(30px); }
 
42
  transition: background-color 0.4s, color 0.4s;
43
  }
44
 
45
+ .container { max-width: 750px; width: 100%; }
46
+ header { text-align: center; margin-bottom: 3rem; animation: fadeInUp 0.8s var(--ease-out-expo) forwards; }
47
+ h1 { font-size: 3rem; font-weight: 800; letter-spacing: -1px; margin: 0; background: linear-gradient(45deg, var(--primary-color-start), var(--primary-color-end)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
48
+ p.subtitle { font-size: 1.2rem; color: #64748b; margin-top: 0.75rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  main, .gallery-section {
51
+ background-color: var(--card-bg); border-radius: 2rem; border: 1px solid var(--border-color);
 
 
52
  box-shadow: 0 4px 10px var(--shadow-color-dark), 0 20px 40px var(--shadow-color-light);
53
+ padding: 3rem; transition: all 0.4s; animation: fadeInUp 0.8s var(--ease-out-expo) forwards; opacity: 0;
 
 
 
54
  }
55
  main { animation-delay: 0.2s; }
56
  .gallery-section { margin-top: 3rem; animation-delay: 0.4s; }
 
59
  .panel:last-child { margin-bottom: 0; }
60
  .controls { margin-bottom: 2.5rem; }
61
 
62
+ h2 { font-size: 1.4rem; font-weight: 700; margin: 0 0 1.5rem 0; padding-bottom: 1rem; display: flex; align-items: center; gap: 0.75rem; border-bottom: 1px solid var(--border-color); }
 
 
 
 
 
 
 
 
 
63
  h2 svg { color: var(--primary-color-start); }
64
 
65
  #drop-zone {
66
+ border: 2px dashed var(--border-color); border-radius: 1.5rem; padding: 2rem; text-align: center;
67
+ cursor: pointer; transition: all 0.3s var(--ease-out-expo); position: relative; overflow: hidden;
68
+ background-color: var(--drop-zone-bg); display: flex; flex-direction: column; justify-content: center;
 
 
69
  align-items: center; min-height: 250px;
70
  }
71
+ #drop-zone.dragover { border-color: var(--primary-color-start); }
72
+ #drop-zone-content { transition: opacity 0.3s ease; display: flex; flex-direction: column; align-items: center; gap: 1rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  .upload-btn-styled {
74
+ background-image: linear-gradient(45deg, var(--primary-color-start) 0%, var(--primary-color-end) 100%); color: white;
75
+ border: none; padding: 0.75rem 1.5rem; border-radius: 0.75rem; font-family: 'Vazirmatn', sans-serif;
76
+ font-weight: 600; font-size: 1rem; cursor: pointer; margin-top: 1rem; transition: all 0.3s ease;
 
 
77
  }
78
  .upload-btn-styled:hover { transform: translateY(-3px) scale(1.05); box-shadow: 0 8px 15px var(--shadow-color-light); }
79
+ #image-preview { position: absolute; inset: 0; width: 100%; height: 100%; padding: 1rem; box-sizing: border-box; border-radius: 1.5rem; object-fit: contain; opacity: 0; transform: scale(0.95); transition: opacity 0.4s ease, transform 0.4s ease; pointer-events: none; backdrop-filter: blur(4px); }
 
 
 
 
 
 
 
80
  #image-preview.visible { opacity: 1; transform: scale(1); pointer-events: auto; }
81
 
82
+ textarea { width: 100%; padding: 1rem; border: 2px solid var(--border-color); border-radius: 1rem; background-color: var(--drop-zone-bg); color: var(--text-color); font-family: 'Vazirmatn', sans-serif; font-size: 1rem; resize: vertical; min-height: 80px; box-sizing: border-box; transition: all 0.3s ease; }
83
+ textarea:focus { outline: none; border-color: var(--primary-color-start); box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary-color-start) 15%, transparent); }
 
 
 
 
 
 
 
 
 
84
 
85
+ button#submit-btn { position: relative; overflow: hidden; width: 100%; padding: 1.1rem; border: none; border-radius: 1rem; background-image: linear-gradient(45deg, var(--primary-color-start) 0%, var(--primary-color-end) 100%); background-size: 200% auto; color: white; font-size: 1.1rem; font-weight: 700; cursor: pointer; margin-top: 1rem; transition: all 0.4s var(--ease-out-expo); box-shadow: 0 4px 15px var(--shadow-color-light); }
86
+ button#submit-btn:hover:not(:disabled) { transform: translateY(-4px); box-shadow: 0 10px 25px -5px var(--shadow-color-light); background-position: right center; }
 
 
 
 
 
 
 
 
 
 
 
 
87
  button#submit-btn:disabled { opacity: 0.5; cursor: not-allowed; }
88
+ .loader-dots { display: flex; justify-content: center; align-items: center; position: absolute; inset: 0; }
89
+ .loader-dots div { width: 8px; height: 8px; margin: 0 4px; background-color: white; border-radius: 50%; animation: bounce 1.4s infinite ease-in-out both; }
90
+ .loader-dots .dot1 { animation-delay: -0.32s; } .loader-dots .dot2 { animation-delay: -0.16s; }
 
 
 
 
 
 
 
91
  @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1.0); } }
92
  #btn-text.hidden { visibility: hidden; }
93
 
94
+ #result-container { border: 2px solid var(--border-color); border-radius: 1.5rem; min-height: 300px; position: relative; background-color: var(--drop-zone-bg); overflow: hidden; padding: 0.75rem; transition: border-color 0.3s ease; }
95
+ #loading-placeholder { display: none; flex-direction: column; align-items: center; justify-content: center; gap: 1.5rem; opacity: 0; animation: fadeIn 0.5s ease forwards; position: absolute; inset: 0; }
 
 
 
 
 
 
 
 
 
 
 
96
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
97
  #result-container.loading #loading-placeholder { display: flex; }
98
+ .creative-loader { width: 100px; height: 100px; position: relative; } /* Styles for creative loader remain the same */
99
+ .creative-loader svg { width: 100%; height: 100%; } .creative-loader .arc { fill: none; stroke-width: 4; stroke-linecap: round; transform-origin: 50% 50%; animation: spin-loader 2s linear infinite; } .creative-loader .arc1 { stroke: var(--primary-color-start); animation-duration: 2.2s; } .creative-loader .arc2 { stroke: var(--primary-color-end); animation-duration: 1.8s; animation-direction: reverse; } .creative-loader .arc3 { stroke: #8b5cf6; animation-duration: 2s; } .creative-loader .star { fill: var(--primary-color-end); transform-origin: center; animation: pulse-star 1.5s ease-in-out infinite; } @keyframes spin-loader { to { transform: rotate(360deg); } } @keyframes pulse-star { 0%, 100% { transform: scale(0.9); opacity: 0.8; } 50% { transform: scale(1.1); opacity: 1; } } .loading-text { font-weight: 500; color: #64748b; }
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ #result-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.75rem; }
 
 
 
102
  @keyframes popIn-spring { 0% { opacity: 0; transform: scale(0.8) translateY(20px); } 80% { opacity: 1; transform: scale(1.05) translateY(-5px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
103
+ .result-img { width: 100%; height: 100%; object-fit: cover; border-radius: 1rem; cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; opacity: 0; animation: popIn-spring 0.6s var(--ease-out-expo) forwards; }
104
+ .result-img:hover { transform: scale(1.05) rotate(1deg); box-shadow: 0 10px 30px -5px var(--shadow-color-dark); }
 
 
 
 
105
 
106
  #error-message { color: var(--danger-color); text-align: center; margin-top: 1rem; display: none; font-weight: 500; }
107
 
108
+ /* -- LIGHTBOX IMPROVEMENTS -- */
109
+ #lightbox { position: fixed; inset: 0; background-color: rgba(10, 20, 40, 0.9); z-index: 1000; display: none; justify-content: center; align-items: center; padding: 1rem; box-sizing: border-box; backdrop-filter: blur(8px); }
110
+ #lightbox-content { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
111
+ #lightbox-img { max-width: 85vw; max-height: 85vh; object-fit: contain; border-radius: 1rem; box-shadow: 0 20px 50px rgba(0,0,0,0.5); }
112
+
113
+ .lightbox-btn { background-color: rgba(255, 255, 255, 0.1); color: white; border: 1px solid rgba(255,255,255,0.2); width: 50px; height: 50px; border-radius: 50%; cursor: pointer; display: flex; justify-content: center; align-items: center; transition: all 0.2s; text-decoration: none; }
 
 
 
 
 
 
 
 
114
  .lightbox-btn:hover { background-color: rgba(255, 255, 255, 0.2); transform: scale(1.1); }
115
+ .lightbox-btn.disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
116
+
117
+ #lightbox-close { position: absolute; top: 20px; right: 20px; z-index: 1002; }
118
+ #lightbox-download { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 1002; }
119
 
120
+ #lightbox-prev, #lightbox-next { position: absolute; top: 50%; transform: translateY(-50%); z-index: 1001; }
121
+ #lightbox-prev { left: 20px; } #lightbox-next { right: 20px; }
122
+
123
  /* --- History Gallery Styles --- */
124
  .gallery-header { display: flex; justify-content: space-between; align-items: center; }
125
+ #clear-history-btn { background: none; border: 1px solid var(--border-color); color: #64748b; padding: 0.5rem 1rem; border-radius: 0.75rem; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; font-family: 'Vazirmatn', sans-serif; font-weight: 500; transition: all 0.2s; }
 
 
 
 
 
126
  #clear-history-btn:hover { border-color: var(--danger-color); color: var(--danger-color); }
127
+
128
+ #history-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; margin-top: 1.5rem; }
129
+ #history-grid:empty::before { content: 'هنوز تصویری خلق نکرده‌اید. اولین ویرایش شما اینجا ذخیره خواهد شد.'; color: #64748b; grid-column: 1 / -1; text-align: center; padding: 3rem 1rem; background-color: var(--drop-zone-bg); border-radius: 1rem; }
130
+ .history-item { background-color: var(--drop-zone-bg); border-radius: 1.25rem; border: 1px solid var(--border-color); overflow: hidden; box-shadow: 0 2px 8px var(--shadow-color-dark); transition: all 0.4s ease; opacity: 0; animation: popIn-spring 0.6s var(--ease-out-expo) forwards; display: flex; flex-direction: column; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  .history-item.removing { transform: scale(0.9); opacity: 0; }
132
  .history-item:hover { transform: translateY(-8px); box-shadow: 0 10px 20px var(--shadow-color-dark); }
133
 
134
+ .history-item-thumbnails { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; padding: 0.5rem; }
135
+ .history-item-thumbnails img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 0.75rem; cursor: pointer; transition: transform 0.2s ease; }
 
 
 
 
 
136
  .history-item-thumbnails img:hover { transform: scale(1.08); }
137
 
138
  .history-item-content { padding: 0 1.25rem 1.25rem 1.25rem; border-top: 1px solid var(--border-color); }
139
+ .history-item-prompt { font-size: 0.95rem; font-weight: 500; margin: 1rem 0; line-height: 1.6em; }
140
+ .history-item-footer { display: flex; justify-content: flex-end; align-items: center; }
141
+ .delete-btn { background-color: transparent; color: var(--danger-color); border: 1px solid transparent; padding: 0.5rem; border-radius: 50%; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; transition: all 0.2s; }
142
+ .delete-btn:hover { background-color: color-mix(in srgb, var(--danger-color) 10%, transparent); border-color: color-mix(in srgb, var(--danger-color) 20%, transparent); }
143
+ .delete-btn svg { width: 20px; height: 20px; }
 
 
 
 
 
 
 
144
 
145
  @media (max-width: 600px) {
146
  body { padding: 1.5rem 1rem; }
147
  main, .gallery-section { padding: 1.5rem; }
148
  h1 { font-size: 2.5rem; }
149
  .history-item-thumbnails { grid-template-columns: repeat(2, 1fr); }
150
+ #lightbox-prev, #lightbox-next { bottom: 20px; top: auto; transform: translateY(0); }
151
+ #lightbox-prev { left: 20px; } #lightbox-next { right: 20px; }
152
+ #lightbox-download { left: 50%; transform: translateX(-50%); }
153
  }
154
  </style>
155
  </head>
156
  <body>
157
 
158
  <div class="container">
159
+ <!-- HEADER AND UPLOAD SECTIONS (UNCHANGED HTML) -->
160
  <header>
161
  <h1>فتوشاپ هوش مصنوعی ✨</h1>
162
  <p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی و به زبان ساده ویرایش کنید</p>
 
164
 
165
  <main>
166
  <div class="panel">
167
+ <h2>1. تصویر خود را انتخاب کنید</h2>
 
 
 
168
  <div id="drop-zone">
169
  <div id="drop-zone-content">
 
170
  <span id="drop-zone-text">تصویر را اینجا بکشید یا از دکمه زیر استفاده کنید</span>
171
  <button class="upload-btn-styled">انتخاب فایل</button>
172
  </div>
 
174
  </div>
175
  <input type="file" id="file-input" accept="image/*" hidden>
176
  </div>
 
 
177
  <div class="controls">
178
+ <h2>2. دستور ویرایش را بنویسید</h2>
 
 
 
179
  <textarea id="prompt-input" rows="3" placeholder="مثال: پس‌زمینه را حذف کن و یک ساحل آفتابی قرار بده"></textarea>
180
+ <button id="submit-btn" disabled><span id="btn-text">خلق کن</span></button>
 
 
181
  <p id="error-message"></p>
182
  </div>
 
183
  <div class="panel">
184
+ <h2>3. نتیجه را ببینید</h2>
 
 
 
185
  <div id="result-container">
186
  <div id="loading-placeholder">
187
+ <div class="creative-loader"><svg viewBox="0 0 50 50"><g><circle class="arc arc1" cx="25" cy="25" r="22"></circle><circle class="arc arc2" cx="25" cy="25" r="18"></circle><circle class="arc arc3" cx="25" cy="25" r="14"></circle><path class="star" d="M25,21 L26.9,24.1 L30,25 L26.9,25.9 L25,29 L23.1,25.9 L20,25 L23.1,24.1 Z"></path></g></svg></div>
 
 
188
  <p class="loading-text">هوش مصنوعی در حال خلق اثر شماست...</p>
189
  </div>
190
  <div id="result-grid"></div>
 
192
  </div>
193
  </main>
194
 
195
+ <!-- HISTORY SECTION (UNCHANGED HTML) -->
196
  <section class="gallery-section">
197
  <div class="gallery-header">
198
+ <h2>گالری و تاریخچه شما</h2>
 
 
 
199
  <button id="clear-history-btn" style="display: none;">
 
200
  <span>پاک کردن همه</span>
201
  </button>
202
  </div>
 
204
  </section>
205
  </div>
206
 
207
+ <!-- IMPROVED LIGHTBOX WITH NAVIGATION -->
208
  <div id="lightbox">
209
+ <div id="lightbox-content">
210
+ <button id="lightbox-prev" class="lightbox-btn" title="تصویر قبلی">
211
+ <svg fill="white" width="24" height="24" viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
212
+ </button>
213
+ <img id="lightbox-img" src="">
214
+ <button id="lightbox-next" class="lightbox-btn" title="تصویر بعدی">
215
+ <svg fill="white" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
216
+ </button>
217
+ </div>
218
+ <a id="lightbox-download" href="#" download="edited-image.png" title="دانلود تصویر" class="lightbox-btn">
219
+ <svg fill="white" width="24" height="24" viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
220
+ </a>
221
+ <button id="lightbox-close" class="lightbox-btn">&times;</button>
222
  </div>
223
 
224
  <script>
 
227
  const HISTORY_KEY = 'aiPhotoshopHistory';
228
 
229
  // Element Selectors
230
+ const fileInput = document.getElementById('file-input');
231
  const dropZone = document.getElementById('drop-zone');
232
  const dropZoneContent = document.getElementById('drop-zone-content');
233
+ const uploadBtnStyled = document.querySelector('.upload-btn-styled');
234
  const imagePreview = document.getElementById('image-preview');
235
  const promptInput = document.getElementById('prompt-input');
236
  const submitBtn = document.getElementById('submit-btn');
 
238
  const resultContainer = document.getElementById('result-container');
239
  const resultGrid = document.getElementById('result-grid');
240
  const errorMessage = document.getElementById('error-message');
241
+ const historyGrid = document.getElementById('history-grid');
242
+ const clearHistoryBtn = document.getElementById('clear-history-btn');
243
+ // Lightbox Elements
244
  const lightbox = document.getElementById('lightbox');
245
  const lightboxImg = document.getElementById('lightbox-img');
246
  const lightboxClose = document.getElementById('lightbox-close');
247
  const lightboxDownload = document.getElementById('lightbox-download');
248
+ const lightboxPrev = document.getElementById('lightbox-prev');
249
+ const lightboxNext = document.getElementById('lightbox-next');
 
250
 
251
+ // State variables
252
  let uploadedFile = null;
253
+ let currentLightboxGroup = [];
254
+ let currentLightboxIndex = 0;
255
+ let currentBlobUrl = null;
256
 
257
  // --- Event Listeners Setup ---
258
  dropZone.addEventListener('click', () => fileInput.click());
259
+ uploadBtnStyled.addEventListener('click', (e) => { e.stopPropagation(); fileInput.click(); });
 
 
 
260
  fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
261
  ['dragenter', 'dragover'].forEach(eventName => dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dropZone.classList.add('dragover'); }));
262
  ['dragleave', 'drop'].forEach(eventName => dropZone.addEventListener(eventName, (e) => { e.preventDefault(); dropZone.classList.remove('dragover'); }));
263
  dropZone.addEventListener('drop', (e) => handleFile(e.dataTransfer.files[0]));
264
  promptInput.addEventListener('input', checkFormState);
265
  submitBtn.addEventListener('click', handleSubmit);
266
+ clearHistoryBtn.addEventListener('click', handleClearHistory);
267
  lightboxClose.addEventListener('click', closeLightbox);
268
  lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
269
+ lightboxPrev.addEventListener('click', showPrevImage);
270
+ lightboxNext.addEventListener('click', showNextImage);
271
  document.addEventListener('DOMContentLoaded', renderHistory);
272
 
 
273
  function handleFile(file) {
274
  if (!file || !file.type.startsWith('image/')) { displayError('لطفا یک فایل تصویری انتخاب کنید.'); return; }
275
  uploadedFile = file;
 
296
  formData.append('prompt', promptInput.value.trim());
297
  try {
298
  const response = await fetch(API_URL, { method: 'POST', body: formData });
299
+ if (!response.ok) throw new Error(`خطای سرور: ${response.statusText}`);
 
 
 
300
  const result = await response.json();
301
+ if (result.image_urls && result.image_urls.length > 0) {
302
  displayResult(result.image_urls);
303
  addToHistory({ prompt: promptInput.value.trim(), urls: result.image_urls, id: Date.now() });
304
  } else {
 
315
  if (isLoading) {
316
  resultContainer.classList.add('loading');
317
  btnText.classList.add('hidden');
318
+ if (!submitBtn.querySelector('.loader-dots')) {
319
+ const loader = document.createElement('div');
320
+ loader.className = 'loader-dots';
321
+ loader.innerHTML = '<div></div><div></div><div></div>';
322
+ submitBtn.appendChild(loader);
323
+ }
324
  submitBtn.disabled = true;
325
  resultGrid.innerHTML = '';
326
  errorMessage.style.display = 'none';
 
328
  resultContainer.classList.remove('loading');
329
  btnText.classList.remove('hidden');
330
  const loader = submitBtn.querySelector('.loader-dots');
331
+ if (loader) loader.remove();
332
  checkFormState();
333
  }
334
  }
 
339
  const img = document.createElement('img');
340
  img.src = url;
341
  img.alt = 'تصویر ویرایش شده';
342
+ img.className = 'result-img';
343
  img.style.animationDelay = `${index * 120}ms`;
344
+ img.addEventListener('click', () => openLightbox(imageUrls, index));
345
  resultGrid.appendChild(img);
346
  });
347
  }
 
350
  resultGrid.innerHTML = '';
351
  errorMessage.style.display = 'none';
352
  }
 
353
  function displayError(message) {
354
  errorMessage.textContent = message;
355
  errorMessage.style.display = 'block';
356
  }
357
 
358
+ // --- Lightbox Functions ---
359
+ function openLightbox(urls, index) {
360
+ currentLightboxGroup = urls;
361
+ currentLightboxIndex = index;
362
  lightbox.style.display = 'flex';
363
+ updateLightboxImage();
364
+ }
365
+
366
+ function closeLightbox() {
367
+ lightbox.style.display = 'none';
368
+ if (currentBlobUrl) {
369
+ URL.revokeObjectURL(currentBlobUrl);
370
+ currentBlobUrl = null;
371
+ }
372
+ }
373
+
374
+ function showPrevImage() {
375
+ currentLightboxIndex = (currentLightboxIndex - 1 + currentLightboxGroup.length) % currentLightboxGroup.length;
376
+ updateLightboxImage();
377
+ }
378
+ function showNextImage() {
379
+ currentLightboxIndex = (currentLightboxIndex + 1) % currentLightboxGroup.length;
380
+ updateLightboxImage();
381
+ }
382
+
383
+ async function updateLightboxImage() {
384
+ const url = currentLightboxGroup[currentLightboxIndex];
385
+ lightboxImg.src = url;
386
+
387
+ // --- ROBUST DOWNLOAD LOGIC ---
388
+ lightboxDownload.classList.add('disabled'); // Disable while fetching
389
+ if (currentBlobUrl) URL.revokeObjectURL(currentBlobUrl);
390
+ try {
391
+ const response = await fetch(url);
392
+ const blob = await response.blob();
393
+ currentBlobUrl = URL.createObjectURL(blob);
394
+ lightboxDownload.href = currentBlobUrl;
395
+ lightboxDownload.download = `ai-photoshop-${Date.now()}.png`;
396
+ lightboxDownload.classList.remove('disabled');
397
+ } catch (error) {
398
+ console.error('Download failed:', error);
399
+ // Optionally hide or keep it disabled
400
+ }
401
  }
 
402
 
403
  // --- History Management Functions ---
404
  function getHistory() {
405
+ try { return JSON.parse(localStorage.getItem(HISTORY_KEY)) || []; } catch (e) { return []; }
 
 
 
 
 
 
406
  }
 
407
  function saveHistory(history) {
408
  localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
409
  renderHistory();
410
  }
 
411
  function addToHistory(item) {
412
  let history = getHistory();
413
  history.unshift(item);
414
+ if (history.length > 20) history.pop(); // Limit history size
415
  saveHistory(history);
416
  }
 
417
  function deleteHistoryItem(id) {
418
+ let history = getHistory().filter(item => item.id !== id);
419
+ saveHistory(history);
 
420
  }
 
421
  function handleClearHistory() {
422
+ if (confirm('آیا از پاک کردن تمام تاریخچه مطمئن هستید؟')) {
423
  localStorage.removeItem(HISTORY_KEY);
424
  renderHistory();
425
  }
 
428
  function renderHistory() {
429
  const history = getHistory();
430
  historyGrid.innerHTML = '';
 
431
  clearHistoryBtn.style.display = history.length > 0 ? 'flex' : 'none';
432
 
433
+ history.forEach((item, historyIndex) => {
434
  const card = document.createElement('div');
435
  card.className = 'history-item';
436
+ card.style.animationDelay = `${historyIndex * 80}ms`;
437
 
438
  const thumbnailsContainer = document.createElement('div');
439
  thumbnailsContainer.className = 'history-item-thumbnails';
440
+ item.urls.forEach((url, urlIndex) => {
441
  const img = document.createElement('img');
442
  img.src = url;
443
+ img.addEventListener('click', () => openLightbox(item.urls, urlIndex));
 
444
  thumbnailsContainer.appendChild(img);
445
  });
446
 
447
+ const contentContainer = document.createElement('div');
448
+ contentContainer.className = 'history-item-content';
449
+ contentContainer.innerHTML = `
450
+ <p class="history-item-prompt">${item.prompt}</p>
451
+ <div class="history-item-footer">
452
+ <button class="delete-btn" data-id="${item.id}" title="حذف این آیتم">
453
+ <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>
454
+ </button>
455
+ </div>`;
 
 
 
 
 
 
456
 
457
+ contentContainer.querySelector('.delete-btn').addEventListener('click', (e) => {
458
+ e.stopPropagation();
459
  const idToDelete = Number(e.currentTarget.getAttribute('data-id'));
460
  const cardElement = e.currentTarget.closest('.history-item');
461
  cardElement.classList.add('removing');
462
+ setTimeout(() => deleteHistoryItem(idToDelete), 400);
 
 
463
  });
464
 
465
+ card.appendChild(thumbnailsContainer);
466
+ card.appendChild(contentContainer);
467
  historyGrid.appendChild(card);
468
  });
469
  }
 
470
  checkFormState();
471
  </script>
472
  </body>