| class CustomGalleryGrid extends HTMLElement { | |
| static get observedAttributes() { | |
| return ['items']; | |
| } | |
| constructor() { | |
| super(); | |
| this.items = []; | |
| } | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.render(); | |
| } | |
| setItems(items) { | |
| this.items = items; | |
| this.render(); | |
| } | |
| render() { | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| } | |
| .gallery-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 1.5rem; | |
| } | |
| @media (max-width: 768px) { | |
| .gallery-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); | |
| } | |
| } | |
| .gallery-item { | |
| position: relative; | |
| aspect-ratio: 16/10; | |
| border-radius: 16px; | |
| overflow: hidden; | |
| cursor: pointer; | |
| transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); | |
| background: rgba(30, 41, 59, 0.5); | |
| } | |
| .gallery-item:hover { | |
| transform: translateY(-8px) scale(1.02); | |
| box-shadow: 0 30px 60px rgba(14, 165, 233, 0.2); | |
| } | |
| .gallery-item img, | |
| .gallery-item video { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| transition: transform 0.6s ease; | |
| } | |
| .gallery-item:hover img, | |
| .gallery-item:hover video { | |
| transform: scale(1.1); | |
| } | |
| .item-overlay { | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(to top, rgba(15, 23, 42, 0.95) 0%, rgba(15, 23, 42, 0.3) 50%, transparent 100%); | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: flex-end; | |
| padding: 1.5rem; | |
| } | |
| .gallery-item:hover .item-overlay { | |
| opacity: 1; | |
| } | |
| .resolution-badge { | |
| position: absolute; | |
| top: 1rem; | |
| right: 1rem; | |
| padding: 0.375rem 0.75rem; | |
| background: linear-gradient(135deg, #0ea5e9, #d946ef); | |
| border-radius: 8px; | |
| font-size: 0.75rem; | |
| font-weight: 700; | |
| color: white; | |
| text-transform: uppercase; | |
| } | |
| .item-prompt { | |
| font-size: 0.875rem; | |
| color: #e2e8f0; | |
| line-height: 1.5; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| margin-bottom: 0.75rem; | |
| } | |
| .item-meta { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| font-size: 0.75rem; | |
| color: #94a3b8; | |
| } | |
| .item-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .action-btn { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 10px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| color: white; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .action-btn:hover { | |
| background: #0ea5e9; | |
| border-color: #0ea5e9; | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 4rem; | |
| color: #64748b; | |
| } | |
| .loading-skeleton { | |
| aspect-ratio: 16/10; | |
| border-radius: 16px; | |
| background: linear-gradient(90deg, rgba(30, 41, 59, 0.5) 25%, rgba(30, 41, 59, 0.8) 50%, rgba(30, 41, 59, 0.5) 75%); | |
| background-size: 200% 100%; | |
| animation: shimmer 1.5s infinite; | |
| } | |
| @keyframes shimmer { | |
| 0% { background-position: 200% 0; } | |
| 100% { background-position: -200% 0; } | |
| } | |
| </style> | |
| <div class="gallery-grid"> | |
| ${this.items.length === 0 ? ` | |
| <div class="loading-skeleton"></div> | |
| <div class="loading-skeleton"></div> | |
| <div class="loading-skeleton"></div> | |
| <div class="loading-skeleton"></div> | |
| ` : this.items.map(item => ` | |
| <div class="gallery-item" data-id="${item.id}"> | |
| ${item.result.qualityLabel ? ` | |
| <span class="resolution-badge ${item.isFallback ? 'bg-amber-500/20 text-amber-400' : ''}"> | |
| ${item.result.qualityLabel} | |
| ${item.isFallback ? ' (Demo)' : ''} | |
| </span> | |
| ` : ''} | |
| <img src="${item.result.url}" alt="${item.prompt}" loading="lazy"> | |
| <div class="item-overlay"> | |
| <p class="item-prompt">${item.prompt}</p> | |
| <div class="item-meta"> | |
| <span>${item.mode.toUpperCase()} • ${item.result.resolution || 'Standard'}</span> | |
| <div class="item-actions"> | |
| <button class="action-btn" title="Download"> | |
| <i data-feather="download" style="width: 16px; height: 16px;"></i> | |
| </button> | |
| <button class="action-btn" title="Expand"> | |
| <i data-feather="maximize-2" style="width: 16px; height: 16px;"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `).join('')} | |
| </div> | |
| `; | |
| if (window.feather) { | |
| setTimeout(() => feather.replace(), 0); | |
| } | |
| } | |
| } | |
| customElements.define('custom-gallery-grid', CustomGalleryGrid); |