| class CustomFeatureCard extends HTMLElement { | |
| static get observedAttributes() { | |
| return ['type', 'title', 'description', 'icon', 'color']; | |
| } | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.render(); | |
| } | |
| getColors(color) { | |
| const colors = { | |
| primary: { from: '#0ea5e9', to: '#0284c7', glow: 'rgba(14, 165, 233, 0.3)' }, | |
| secondary: { from: '#d946ef', to: '#c026d3', glow: 'rgba(217, 70, 239, 0.3)' }, | |
| accent: { from: '#f97316', to: '#ea580c', glow: 'rgba(249, 115, 22, 0.3)' } | |
| }; | |
| return colors[color] || colors.primary; | |
| } | |
| render() { | |
| const type = this.getAttribute('type') || 'image'; | |
| const title = this.getAttribute('title') || 'Feature'; | |
| const description = this.getAttribute('description') || ''; | |
| const icon = this.getAttribute('icon') || 'star'; | |
| const colorKey = this.getAttribute('color') || 'primary'; | |
| const colors = this.getColors(colorKey); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| } | |
| .card { | |
| position: relative; | |
| height: 100%; | |
| background: rgba(30, 41, 59, 0.4); | |
| backdrop-filter: blur(12px); | |
| border: 1px solid rgba(148, 163, 184, 0.1); | |
| border-radius: 24px; | |
| padding: 2rem; | |
| transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); | |
| overflow: hidden; | |
| cursor: pointer; | |
| } | |
| .card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 4px; | |
| background: linear-gradient(90deg, ${colors.from}, ${colors.to}); | |
| transform: scaleX(0); | |
| transition: transform 0.4s ease; | |
| } | |
| .card:hover { | |
| transform: translateY(-8px) scale(1.02); | |
| border-color: ${colors.from}40; | |
| box-shadow: 0 30px 60px -15px ${colors.glow}; | |
| } | |
| .card:hover::before { | |
| transform: scaleX(1); | |
| } | |
| .icon-wrapper { | |
| width: 64px; | |
| height: 64px; | |
| border-radius: 20px; | |
| background: linear-gradient(135deg, ${colors.from}20, ${colors.to}20); | |
| border: 1px solid ${colors.from}30; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin-bottom: 1.5rem; | |
| transition: all 0.3s ease; | |
| } | |
| .card:hover .icon-wrapper { | |
| transform: scale(1.1) rotate(-5deg); | |
| background: linear-gradient(135deg, ${colors.from}, ${colors.to}); | |
| } | |
| .icon-wrapper i { | |
| color: ${colors.from}; | |
| transition: color 0.3s ease; | |
| } | |
| .card:hover .icon-wrapper i { | |
| color: white; | |
| } | |
| .badge { | |
| position: absolute; | |
| top: 1.5rem; | |
| right: 1.5rem; | |
| padding: 0.375rem 0.875rem; | |
| background: ${colors.from}15; | |
| border: 1px solid ${colors.from}30; | |
| border-radius: 9999px; | |
| color: ${colors.from}; | |
| font-size: 0.75rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| h3 { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| color: #f8fafc; | |
| margin-bottom: 0.75rem; | |
| } | |
| p { | |
| color: #94a3b8; | |
| font-size: 0.9375rem; | |
| line-height: 1.7; | |
| margin-bottom: 1.5rem; | |
| } | |
| .features { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.75rem; | |
| } | |
| .feature-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| font-size: 0.875rem; | |
| color: #64748b; | |
| } | |
| .feature-item i { | |
| color: ${colors.from}; | |
| width: 16px; | |
| height: 16px; | |
| } | |
| .resolution-badges { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.5rem; | |
| margin-top: 1rem; | |
| } | |
| .res-badge { | |
| padding: 0.25rem 0.5rem; | |
| background: rgba(15, 23, 42, 0.6); | |
| border: 1px solid ${colors.from}40; | |
| border-radius: 6px; | |
| font-size: 0.65rem; | |
| color: ${colors.from}; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| } | |
| .res-badge.ultra { | |
| background: linear-gradient(135deg, ${colors.from}30, ${colors.to}30); | |
| border-color: ${colors.from}; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 0.6; } | |
| 50% { opacity: 1; } | |
| } | |
| .cta-arrow { | |
| position: absolute; | |
| bottom: 1.5rem; | |
| right: 1.5rem; | |
| width: 48px; | |
| height: 48px; | |
| border-radius: 50%; | |
| background: rgba(148, 163, 184, 0.1); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| opacity: 0; | |
| transform: translateX(-10px); | |
| transition: all 0.3s ease; | |
| } | |
| .card:hover .cta-arrow { | |
| opacity: 1; | |
| transform: translateX(0); | |
| background: ${colors.from}; | |
| } | |
| .cta-arrow i { | |
| color: white; | |
| } | |
| </style> | |
| <div class="card" onclick="window.location.href='#studio'"> | |
| <span class="badge">${type}</span> | |
| <div class="icon-wrapper"> | |
| <i data-feather="${icon}" style="width: 28px; height: 28px;"></i> | |
| </div> | |
| <h3>${title}</h3> | |
| <p>${description}</p> | |
| <div class="features"> | |
| ${this.getFeatureItems(type, colors.from)} | |
| </div> | |
| <div class="resolution-badges"> | |
| <span class="res-badge">4K</span> | |
| <span class="res-badge">8K</span> | |
| <span class="res-badge ultra">16K</span> | |
| <span class="res-badge ultra">20K+</span> | |
| </div> | |
| <div class="cta-arrow"> | |
| <i data-feather="arrow-right" style="width: 20px; height: 20px;"></i> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| getFeatureItems(type, color) { | |
| const features = { | |
| image: [ | |
| { icon: 'maximize', text: 'Up to 20K resolution' }, | |
| { icon: 'layers', text: 'AI Upscaling 4x' }, | |
| { icon: 'sliders', text: 'Pro color grading' } | |
| ], | |
| video: [ | |
| { icon: 'clock', text: 'Up to 8K 120fps' }, | |
| { icon: 'repeat', text: 'HDR10+ support' }, | |
| { icon: 'film', text: 'Cinema quality' } | |
| ], | |
| gif: [ | |
| { icon: 'loader', text: '4K 60fps loops' }, | |
| { icon: 'palette', text: 'Lossless encoding' }, | |
| { icon: 'share-2', text: 'Web optimized' } | |
| ], | |
| '3d': [ | |
| { icon: 'box', text: '8K texture maps' }, | |
| { icon: 'grid', text: 'PBR 4K materials' }, | |
| { icon: 'printer', text: 'Micron precision' } | |
| ] | |
| }; | |
| return (features[type] || features.image).map(f => ` | |
| <div class="feature-item"> | |
| <i data-feather="${f.icon}" style="color: ${color};"></i> | |
| <span>${f.text}</span> | |
| </div> | |
| `).join(''); | |
| } | |
| } | |
| customElements.define('custom-feature-card', CustomFeatureCard); |