Sada8888 commited on
Commit
61aad51
·
verified ·
1 Parent(s): fb69e3f

Update templates/image_studio.html

Browse files
Files changed (1) hide show
  1. templates/image_studio.html +153 -23
templates/image_studio.html CHANGED
@@ -219,6 +219,33 @@
219
  @keyframes fadeInBackdrop { from { opacity: 0; } to { opacity: 1; } }
220
  @keyframes fadeInModal { from { opacity: 0; transform: translateY(-20px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /* --- History Section Styles --- */
223
  .history-section {
224
  margin-top: 1rem;
@@ -254,11 +281,12 @@
254
  width: 100%; height: 200px; object-fit: cover; cursor: pointer; border-bottom: 1px solid var(--input-border);
255
  }
256
  .history-details {
257
- padding: 12px; display: flex; flex-direction: column; gap: 10px; flex-grow: 1;
258
  }
 
259
  .history-prompt {
260
  font-size: 0.85rem; color: var(--text-primary); font-weight: 600;
261
- display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; direction: auto; text-align: right;
262
  }
263
  .history-meta {
264
  font-size: 0.75rem; color: var(--text-tertiary); display: flex; justify-content: space-between; font-weight: 600; background: var(--panel-bg); padding: 4px 8px; border-radius: 6px; border: 1px solid var(--panel-border);
@@ -270,23 +298,38 @@
270
  background: var(--danger-color); color: white; border-style: solid;
271
  }
272
 
 
273
  .image-view-modal {
274
  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
275
  background-color: rgba(26, 32, 44, 0.9); z-index: 2000;
276
  display: flex; align-items: center; justify-content: center;
277
  opacity: 0; animation: fadeInBackdrop 0.3s forwards;
 
278
  }
279
  .image-view-modal img {
280
- max-width: 90%; max-height: 90vh; border-radius: var(--radius-card); box-shadow: 0 0 30px rgba(0,0,0,0.5);
281
  }
282
  .image-view-close {
283
  position: absolute; top: 25px; right: 25px; background: rgba(255,255,255,0.1); border: 2px solid rgba(255,255,255,0.3);
284
  color: white; font-size: 1.5rem; cursor: pointer; width: 45px; height: 45px; border-radius: 50%;
285
- display: flex; align-items: center; justify-content: center; transition: all 0.3s;
286
  }
287
  .image-view-close:hover {
288
  background: rgba(255,255,255,0.2); border-color: white; transform: scale(1.1);
289
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
  @media (max-width: 650px) {
292
  .model-grid { gap: 10px; }
@@ -296,6 +339,8 @@
296
  .empty-placeholder { height: 250px; }
297
  .text-overlay { font-size: 16px; }
298
  .history-item img { height: 140px; }
 
 
299
  }
300
  </style>
301
  </head>
@@ -417,6 +462,44 @@
417
  </div>
418
 
419
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  // --- مدیریت دیتابیس تصاویر (IndexedDB) ---
421
  const dbName = 'ImageStudioDB';
422
  const storeName = 'ImageHistory';
@@ -511,31 +594,41 @@
511
  const div = document.createElement('div');
512
  div.className = 'history-item';
513
 
 
 
 
514
  div.innerHTML = `
515
- <img src="${blobUrl}" alt="History Image" title="برای مشاهده کلیک کنید" onclick="viewHistoryImage('${blobUrl}')">
516
  <div class="history-details">
517
- <div class="history-prompt" dir="auto" title="${item.prompt.replace(/"/g, '&quot;')}">${item.prompt}</div>
518
  <div class="history-meta">
519
  <span>${item.model}</span>
520
  <span>${item.ratio}</span>
521
  </div>
522
- <button class="history-delete-btn" onclick="deleteHistoryItem(${item.id})">حذف تصویر</button>
523
  </div>
524
  `;
 
 
 
 
 
 
 
 
 
 
525
  grid.appendChild(div);
526
  });
527
  }
528
 
529
- window.deleteHistoryItem = async function(id) {
530
- if (!db) await initDB();
531
- return new Promise((resolve, reject) => {
532
  const transaction = db.transaction([storeName], 'readwrite');
533
  const store = transaction.objectStore(storeName);
534
  store.delete(id);
535
- transaction.oncomplete = () => {
536
- loadHistory();
537
- resolve();
538
- };
539
  });
540
  };
541
 
@@ -552,25 +645,62 @@
552
  });
553
  }
554
 
555
- window.viewHistoryImage = function(url) {
 
 
 
 
 
 
556
  const modal = document.createElement('div');
557
  modal.className = 'image-view-modal';
558
  modal.innerHTML = `
559
  <button class="image-view-close" onclick="this.parentElement.remove()">×</button>
560
- <img src="${url}" alt="Full Image">
 
 
 
 
 
 
 
 
 
 
561
  `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
  modal.onclick = (e) => {
563
- if(e.target === modal) modal.remove();
564
  };
565
  document.body.appendChild(modal);
566
  };
567
 
568
- document.getElementById('clear-history-btn').addEventListener('click', () => {
569
- if(confirm('آیا از حذف تمام سابقه تصاویر اطمینان دارید؟')) {
570
- deleteAllHistory();
571
- }
572
- });
573
-
574
 
575
  // --- سیستم اعتبا�� و شناسایی کاربر ---
576
  let userSubscriptionStatus = 'free';
 
219
  @keyframes fadeInBackdrop { from { opacity: 0; } to { opacity: 1; } }
220
  @keyframes fadeInModal { from { opacity: 0; transform: translateY(-20px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
221
 
222
+ /* --- Custom Confirm Dialog --- */
223
+ .confirm-modal-backdrop {
224
+ position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
225
+ background-color: rgba(26, 32, 44, 0.7); z-index: 3000;
226
+ display: flex; align-items: center; justify-content: center;
227
+ opacity: 0; animation: fadeInBackdrop 0.3s forwards;
228
+ backdrop-filter: blur(5px);
229
+ }
230
+ .confirm-modal-content {
231
+ background: var(--panel-bg); border-radius: var(--radius-card); padding: 25px;
232
+ width: 90%; max-width: 400px; text-align: center; box-shadow: var(--shadow-xl);
233
+ transform: scale(0.9); animation: popIn 0.3s forwards; border: 1px solid var(--panel-border);
234
+ }
235
+ @keyframes popIn { to { transform: scale(1); opacity: 1; } }
236
+ .confirm-icon {
237
+ width: 60px; height: 60px; color: var(--danger-color); margin: 0 auto 15px;
238
+ background: rgba(229, 62, 62, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center;
239
+ }
240
+ .confirm-title { font-size: 1.2rem; font-weight: 800; color: var(--text-primary); margin-bottom: 10px; }
241
+ .confirm-message { font-size: 0.95rem; color: var(--text-secondary); margin-bottom: 25px; line-height: 1.6; }
242
+ .confirm-actions { display: flex; gap: 10px; justify-content: center; }
243
+ .confirm-btn { flex: 1; padding: 12px; border-radius: var(--radius-btn); font-weight: 700; font-size: 1rem; cursor: pointer; border: none; transition: var(--transition-smooth); font-family: inherit; }
244
+ .btn-cancel { background: var(--input-bg); color: var(--text-secondary); border: 1px solid var(--input-border); }
245
+ .btn-cancel:hover { background: #e2e8f0; color: var(--text-primary); }
246
+ .btn-danger { background: var(--danger-color); color: white; box-shadow: 0 4px 10px rgba(229,62,62,0.3); }
247
+ .btn-danger:hover { background: #C53030; transform: translateY(-2px); box-shadow: 0 6px 15px rgba(229,62,62,0.4); }
248
+
249
  /* --- History Section Styles --- */
250
  .history-section {
251
  margin-top: 1rem;
 
281
  width: 100%; height: 200px; object-fit: cover; cursor: pointer; border-bottom: 1px solid var(--input-border);
282
  }
283
  .history-details {
284
+ padding: 12px; display: flex; flex-direction: column; gap: 10px; flex-grow: 1; overflow: hidden;
285
  }
286
+ /* One line prompt with ellipsis */
287
  .history-prompt {
288
  font-size: 0.85rem; color: var(--text-primary); font-weight: 600;
289
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: auto; text-align: right;
290
  }
291
  .history-meta {
292
  font-size: 0.75rem; color: var(--text-tertiary); display: flex; justify-content: space-between; font-weight: 600; background: var(--panel-bg); padding: 4px 8px; border-radius: 6px; border: 1px solid var(--panel-border);
 
298
  background: var(--danger-color); color: white; border-style: solid;
299
  }
300
 
301
+ /* --- Image View Modal & Toolbar --- */
302
  .image-view-modal {
303
  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
304
  background-color: rgba(26, 32, 44, 0.9); z-index: 2000;
305
  display: flex; align-items: center; justify-content: center;
306
  opacity: 0; animation: fadeInBackdrop 0.3s forwards;
307
+ flex-direction: column;
308
  }
309
  .image-view-modal img {
310
+ max-width: 90%; max-height: 80vh; border-radius: var(--radius-card); box-shadow: 0 0 30px rgba(0,0,0,0.5); object-fit: contain;
311
  }
312
  .image-view-close {
313
  position: absolute; top: 25px; right: 25px; background: rgba(255,255,255,0.1); border: 2px solid rgba(255,255,255,0.3);
314
  color: white; font-size: 1.5rem; cursor: pointer; width: 45px; height: 45px; border-radius: 50%;
315
+ display: flex; align-items: center; justify-content: center; transition: all 0.3s; z-index: 2002;
316
  }
317
  .image-view-close:hover {
318
  background: rgba(255,255,255,0.2); border-color: white; transform: scale(1.1);
319
  }
320
+
321
+ .image-view-toolbar {
322
+ position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%);
323
+ display: flex; gap: 15px; z-index: 2001; background: rgba(0,0,0,0.7); padding: 12px 20px; border-radius: 20px; backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1);
324
+ }
325
+ .iv-action-btn {
326
+ background: var(--accent-primary); color: white; border: none; padding: 10px 18px; border-radius: var(--radius-btn);
327
+ font-family: inherit; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.2s; font-size: 0.95rem; box-shadow: 0 4px 10px rgba(0,0,0,0.3);
328
+ }
329
+ .iv-action-btn:hover { background: var(--accent-primary-hover); transform: translateY(-3px); box-shadow: 0 6px 15px rgba(0,0,0,0.4); }
330
+ .iv-action-btn svg { width: 20px; height: 20px; }
331
+ .iv-btn-copy { background: #4A5568; }
332
+ .iv-btn-copy:hover { background: #2D3748; }
333
 
334
  @media (max-width: 650px) {
335
  .model-grid { gap: 10px; }
 
339
  .empty-placeholder { height: 250px; }
340
  .text-overlay { font-size: 16px; }
341
  .history-item img { height: 140px; }
342
+ .image-view-toolbar { bottom: 20px; width: 90%; justify-content: center; padding: 10px; }
343
+ .iv-action-btn { padding: 8px 12px; font-size: 0.85rem; flex: 1; justify-content: center;}
344
  }
345
  </style>
346
  </head>
 
462
  </div>
463
 
464
  <script>
465
+ // --- توابع پاپ‌آپ سفارشی (تاییدیه حذف) ---
466
+ function showCustomConfirm(title, message, onConfirm) {
467
+ const backdrop = document.createElement('div');
468
+ backdrop.className = 'confirm-modal-backdrop';
469
+
470
+ const content = document.createElement('div');
471
+ content.className = 'confirm-modal-content';
472
+
473
+ content.innerHTML = `
474
+ <div class="confirm-icon">
475
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
476
+ </div>
477
+ <div class="confirm-title">${title}</div>
478
+ <div class="confirm-message">${message}</div>
479
+ <div class="confirm-actions">
480
+ <button class="confirm-btn btn-cancel" id="confirm-cancel">انصراف</button>
481
+ <button class="confirm-btn btn-danger" id="confirm-ok">تایید و حذف</button>
482
+ </div>
483
+ `;
484
+
485
+ backdrop.appendChild(content);
486
+ document.body.appendChild(backdrop);
487
+
488
+ const close = () => {
489
+ backdrop.style.opacity = '0';
490
+ setTimeout(() => backdrop.remove(), 300);
491
+ };
492
+
493
+ backdrop.querySelector('#confirm-cancel').onclick = close;
494
+ backdrop.querySelector('#confirm-ok').onclick = () => {
495
+ onConfirm();
496
+ close();
497
+ };
498
+ backdrop.onclick = (e) => {
499
+ if(e.target === backdrop) close();
500
+ }
501
+ }
502
+
503
  // --- مدیریت دیتابیس تصاویر (IndexedDB) ---
504
  const dbName = 'ImageStudioDB';
505
  const storeName = 'ImageHistory';
 
594
  const div = document.createElement('div');
595
  div.className = 'history-item';
596
 
597
+ // پاک‌سازی نقل قول‌ها برای نمایش در تایتل (تولتیپ)
598
+ const safeTitle = item.prompt.replace(/"/g, '&quot;');
599
+
600
  div.innerHTML = `
601
+ <img src="${blobUrl}" alt="History Image" title="برای مشاهده کلیک کنید">
602
  <div class="history-details">
603
+ <div class="history-prompt" dir="auto" title="${safeTitle}">${item.prompt}</div>
604
  <div class="history-meta">
605
  <span>${item.model}</span>
606
  <span>${item.ratio}</span>
607
  </div>
608
+ <button class="history-delete-btn">حذف تصویر</button>
609
  </div>
610
  `;
611
+
612
+ // استفاده از EventListener برای جلوگیری از بهم ریختگی کاراکترها هنگام کلیک
613
+ div.querySelector('img').addEventListener('click', () => {
614
+ viewHistoryImage(blobUrl, item.prompt);
615
+ });
616
+
617
+ div.querySelector('.history-delete-btn').addEventListener('click', () => {
618
+ deleteHistoryItem(item.id);
619
+ });
620
+
621
  grid.appendChild(div);
622
  });
623
  }
624
 
625
+ window.deleteHistoryItem = function(id) {
626
+ showCustomConfirm('حذف از سابقه', 'آیا از حذف دائمی این تصویر از حافظه مرورگر خود اطمینان دارید؟', async () => {
627
+ if (!db) await initDB();
628
  const transaction = db.transaction([storeName], 'readwrite');
629
  const store = transaction.objectStore(storeName);
630
  store.delete(id);
631
+ transaction.oncomplete = () => loadHistory();
 
 
 
632
  });
633
  };
634
 
 
645
  });
646
  }
647
 
648
+ document.getElementById('clear-history-btn').addEventListener('click', () => {
649
+ showCustomConfirm('حذف تمام تصاویر', 'آیا از پاک کردن تمامی ۵۰ تصویر آخر از سابقه مطمئن هستید؟ این عمل غیرقابل بازگشت است.', () => {
650
+ deleteAllHistory();
651
+ });
652
+ });
653
+
654
+ window.viewHistoryImage = function(url, promptText) {
655
  const modal = document.createElement('div');
656
  modal.className = 'image-view-modal';
657
  modal.innerHTML = `
658
  <button class="image-view-close" onclick="this.parentElement.remove()">×</button>
659
+ <img src="${url}" alt="Full Image" class="full-view-img">
660
+ <div class="image-view-toolbar" onclick="event.stopPropagation()">
661
+ <button class="iv-action-btn iv-btn-copy" id="btn-copy-prompt">
662
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
663
+ کپی پرامپت
664
+ </button>
665
+ <button class="iv-action-btn" id="btn-download-img">
666
+ <svg 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"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
667
+ دانلود تصویر
668
+ </button>
669
+ </div>
670
  `;
671
+
672
+ // رویداد دانلود تصویر لوکال
673
+ modal.querySelector('#btn-download-img').onclick = () => {
674
+ const a = document.createElement('a');
675
+ a.href = url;
676
+ a.download = 'AI_Image_' + Date.now() + '.png';
677
+ document.body.appendChild(a);
678
+ a.click();
679
+ document.body.removeChild(a);
680
+ };
681
+
682
+ // رویداد کپی پرامپت با افکت جذاب
683
+ const copyBtn = modal.querySelector('#btn-copy-prompt');
684
+ copyBtn.onclick = () => {
685
+ navigator.clipboard.writeText(promptText).then(() => {
686
+ const originalHtml = copyBtn.innerHTML;
687
+ copyBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg> کپی شد!`;
688
+ copyBtn.style.background = 'var(--accent-secondary)';
689
+ copyBtn.style.color = '#1A202C';
690
+ setTimeout(() => {
691
+ copyBtn.innerHTML = originalHtml;
692
+ copyBtn.style.background = '';
693
+ copyBtn.style.color = '';
694
+ }, 2000);
695
+ });
696
+ };
697
+
698
  modal.onclick = (e) => {
699
+ if(e.target === modal || e.target.classList.contains('full-view-img')) modal.remove();
700
  };
701
  document.body.appendChild(modal);
702
  };
703
 
 
 
 
 
 
 
704
 
705
  // --- سیستم اعتبا�� و شناسایی کاربر ---
706
  let userSubscriptionStatus = 'free';