| class GameCard extends HTMLElement { |
| constructor() { |
| super(); |
| this.attachShadow({ mode: 'open' }); |
| } |
|
|
| static get observedAttributes() { |
| return ['title', 'icon', 'color', 'href']; |
| } |
|
|
| connectedCallback() { |
| this.render(); |
| this.addEventListeners(); |
| } |
|
|
| render() { |
| const title = this.getAttribute('title') || 'Game Mode'; |
| const icon = this.getAttribute('icon') || 'play'; |
| const color = this.getAttribute('color') || 'green'; |
| const href = this.getAttribute('href') || '#'; |
| |
| const colorClasses = { |
| green: 'bg-green-600 hover:bg-green-700', |
| yellow: 'bg-yellow-600 hover:bg-yellow-700', |
| blue: 'bg-blue-600 hover:bg-blue-700', |
| purple: 'bg-purple-600 hover:bg-purple-700' |
| }; |
|
|
| this.shadowRoot.innerHTML = ` |
| <style> |
| .card { |
| background: #1f2937; |
| border-radius: 0.75rem; |
| padding: 1.5rem; |
| text-align: center; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| border: 2px solid transparent; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .card::before { |
| content: ''; |
| position: absolute; |
| top: 0; |
| left: 0; |
| right: 0; |
| height: 4px; |
| background: linear-gradient(90deg, #10b981, #3b82f6); |
| opacity: 0; |
| transition: opacity 0.3s ease; |
| } |
| |
| .card:hover::before { |
| opacity: 1; |
| } |
| |
| .card:hover { |
| transform: translateY(-4px); |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3); |
| border-color: rgba(16, 185, 129, 0.3); |
| } |
| |
| .icon-container { |
| width: 60px; |
| height: 60px; |
| border-radius: 50%; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| margin: 0 auto 1rem auto; |
| } |
| |
| .title { |
| font-size: 1.125rem; |
| font-weight: 600; |
| margin-bottom: 0.5rem; |
| } |
| |
| .play-button { |
| background: #10b981; |
| color: white; |
| border: none; |
| padding: 0.5rem 1rem; |
| border-radius: 0.5rem; |
| font-weight: 600; |
| cursor: pointer; |
| transition: all 0.2s ease; |
| } |
| |
| .play-button:hover { |
| background: #059669; |
| transform: scale(1.05); |
| } |
| |
| .card.green .icon-container { background: rgba(16, 185, 129, 0.2); } |
| .card.yellow .icon-container { background: rgba(245, 158, 11, 0.2); } |
| .card.blue { background: rgba(59, 130, 246, 0.2); } |
| .card.purple .icon-container { background: rgba(139, 92, 246, 0.2); } |
| |
| .card.green .play-button { background: #10b981; } |
| .card.yellow .play-button { background: #f59e0b; } |
| .card.blue .play-button { background: #3b82f6; } |
| .card.purple .play-button { background: #8b5cf6; } |
| |
| .card.green:hover::before { background: linear-gradient(90deg, #10b981, #059669); } |
| .card.yellow:hover::before { background: linear-gradient(90deg, #f59e0b, #d97706); } |
| .card.blue:hover::before { background: linear-gradient(90deg, #3b82f6, #1d4ed8); } |
| .card.purple:hover::before { background: linear-gradient(90deg, #8b5cf6, #7c3aed); } |
| </style> |
| <div class="card ${color}"> |
| <div class="icon-container"> |
| <i data-feather="${icon}" class="w-6 h-6"></i> |
| </div> |
| <div class="title">${title}</div> |
| <button class="play-button w-full py-2 rounded-lg font-bold transition-all"> |
| Play Now |
| </button> |
| </div> |
| </div> |
| `; |
| |
| |
| setTimeout(() => { |
| if (this.shadowRoot.querySelector('[data-feather]')) { |
| feather.replace({ |
| root: this.shadowRoot |
| }); |
| } |
| }, 100); |
| } |
| addEventListeners() { |
| this.shadowRoot.querySelector('.play-button').addEventListener('click', (e) => { |
| e.stopPropagation(); |
| const title = this.getAttribute('title'); |
| const color = this.getAttribute('color'); |
| |
| |
| this.showGameOverlay(title, color); |
| }); |
| } |
| showGameOverlay(title, color) { |
| const overlay = document.createElement('div'); |
| overlay.className = 'fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50'; |
| overlay.innerHTML = ` |
| <div class="bg-gray-800 rounded-xl p-8 max-w-md w-full mx-4 border-4 ${this.getBorderColor(color)}"> |
| <div class="text-center"> |
| <h3 class="text-2xl font-bold mb-4">${title}</h3> |
| <div class="mb-6"> |
| <div class="text-4xl font-bold mb-2">⚽</div> |
| <p class="text-gray-300 mb-6">Get ready for the penalty shootout!</p> |
| |
| <div class="grid grid-cols-3 gap-4 mb-6"> |
| <button class="bg-green-600 hover:bg-green-700 py-3 rounded-lg font-bold transition-all" data-action="shoot"> |
| SHOOT |
| </button> |
| <button class="bg-blue-600 hover:bg-blue-700 py-3 rounded-lg font-bold transition-all" data-action="aim"> |
| AIM |
| </button> |
| <button class="bg-red-600 hover:bg-red-700 py-3 rounded-lg font-bold transition-all" data-action="power"> |
| POWER |
| </button> |
| </div> |
| |
| <div class="space-y-3"> |
| <div class="flex items-center justify-between bg-gray-700 p-3 rounded-lg"> |
| <span>Target:</span> |
| <span class="text-yellow-400">GOAL!</span> |
| </div> |
| |
| <div class="mt-6 flex gap-4"> |
| <button class="flex-1 bg-gray-600 hover:bg-gray-700 py-2 rounded-lg transition-all"> |
| Top Left |
| </button> |
| <button class="flex-1 bg-gray-600 hover:bg-gray-700 py-2 rounded-lg transition-all" data-action="close"> |
| Close |
| </button> |
| <button class="flex-1 bg-green-600 hover:bg-green-700 py-2 rounded-lg transition-all"> |
| Start Game |
| </button> |
| </div> |
| </div> |
| </div> |
| `; |
|
|
| |
| overlay.querySelector('[data-action="shoot"]').addEventListener('click', () => { |
| this.simulatePenaltyShot(title); |
| }); |
|
|
| overlay.querySelector('[data-action="aim"]').addEventListener('click', () => { |
| this.showAimInterface(); |
| }); |
|
|
| overlay.querySelector('[data-action="power"]').addEventListener('click', () => { |
| this.showPowerInterface(); |
| }); |
|
|
| overlay.querySelector('[data-action="close"]').addEventListener('click', () => { |
| overlay.remove(); |
| }); |
|
|
| document.body.appendChild(overlay); |
| |
| |
| gsap.from(overlay.querySelector('div'), { |
| duration: 0.5, |
| scale: 0.8, |
| opacity: 0, |
| ease: "back.out(1.7)" |
| }); |
| } |
|
|
| getBorderColor(color) { |
| const colors = { |
| green: 'border-green-500', |
| yellow: 'border-yellow-500', |
| blue: 'border-blue-500', |
| purple: 'border-purple-500' |
| }; |
| return colors[color] || 'border-green-500'; |
| } |
|
|
| simulatePenaltyShot(gameMode) { |
| const isGoal = Math.random() > 0.3; |
| const power = Math.floor(Math.random() * 30) + 70; |
| const speed = Math.floor(Math.random() * 20) + 80; |
| |
| |
| const resultOverlay = document.createElement('div'); |
| resultOverlay.className = 'fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50'; |
| resultOverlay.innerHTML = ` |
| <div class="bg-gray-800 rounded-xl p-8 max-w-md w-full mx-4 text-center'; |
| resultOverlay.innerHTML = ` |
| <div class="text-6xl mb-4">${isGoal ? '⚽🎉' : '❌'}</div> |
| <h3 class="text-3xl font-bold mb-4 ${isGoal ? 'text-green-400' : 'text-red-400'}"> |
| ${isGoal ? 'GOAL!' : 'MISSED!'} |
| </h3> |
| <p class="text-xl mb-6">${isGoal ? 'Perfect shot! The ball is in the net!' : 'The goalkeeper saved it! Better luck next time.'}</p> |
| <div class="space-y-2 mb-6"> |
| <div class="flex justify-between"> |
| <span>Shot Power:</span> |
| <span class="text-yellow-400">${power}%</span> |
| </div> |
| <div class="flex justify-between"> |
| <span>Ball Speed:</span> |
| <span class="text-blue-400">${speed} km/h</span> |
| </div> |
| <button class="bg-green-600 hover:bg-green-700 px-6 py-3 rounded-lg font-bold transition-all"> |
| Continue |
| </button> |
| `; |
|
|
| resultOverlay.querySelector('button').addEventListener('click', () => { |
| resultOverlay.remove(); |
| |
| // Add rewards based on game mode |
| if (isGoal) { |
| const rewards = { |
| 'Quick Match': { coins: 15, xp: 50 }, |
| 'Daily Challenge': { coins: 50, xp: 150 }, |
| 'Training Mode': { coins: 0, xp: 25 }, |
| 'Change Player': { coins: 10, xp: 30 } |
| }; |
| |
| const reward = rewards[gameMode] || { coins: 10, xp: 25 }; |
| |
| // Dispatch custom event to update game state |
| document.dispatchEvent(new CustomEvent('gameAction', { |
| detail: { |
| type: gameMode, |
| success: true, |
| ...reward |
| } |
| }); |
| } |
| }); |
|
|
| document.body.appendChild(resultOverlay); |
| |
| // Animate result |
| gsap.from(resultOverlay.querySelector('div'), { |
| duration: 0.5, |
| scale: 0.8, |
| opacity: 0, |
| ease: "back.out(1.7)" |
| }); |
| } |
|
|
| showAimInterface() { |
| const aimOverlay = document.createElement('div'); |
| aimOverlay.className = 'fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50'; |
| aimOverlay.innerHTML = ` |
| <div class="bg-gray-800 rounded-xl p-8 max-w-md w-full mx-4 text-center'; |
| aimOverlay.innerHTML = ` |
| <h3 class="text-2xl font-bold mb-6">Aim Selection</h3> |
| <div class="grid grid-cols-3 gap-2 mb-6"> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="top-left"> |
| ↖️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="top-center"> |
| ⬆️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="top-right"> |
| ↗️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="middle-left"> |
| ⬅️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="center"> |
| 🎯 |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="middle-right"> |
| ➡️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="bottom-left"> |
| ↙️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="bottom-center"> |
| ⬇️ |
| </button> |
| <button class="bg-gray-700 hover:bg-green-600 p-4 rounded-lg transition-all" data-target="bottom-right"> |
| ↘️ |
| </button> |
| </div> |
| <button class="bg-red-600 hover:bg-red-700 px-6 py-3 rounded-lg font-bold transition-all"> |
| Back |
| </button> |
| `; |
|
|
| aimOverlay.querySelectorAll('[data-target]').forEach(button => { |
| button.addEventListener('click', (e) => { |
| const target = e.target.getAttribute('data-target'); |
| this.showAimConfirmation(target); |
| }); |
| }); |
|
|
| aimOverlay.querySelector('button:last-child').addEventListener('click', () => { |
| aimOverlay.remove(); |
| }); |
|
|
| document.body.appendChild(aimOverlay); |
| } |
|
|
| showAimConfirmation(target) { |
| const confirmation = document.createElement('div'); |
| confirmation.className = 'fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50'; |
| confirmation.innerHTML = ` |
| <div class="bg-gray-800 rounded-xl p-8 max-w-md w-full mx-4 text-center'; |
| confirmation.innerHTML = ` |
| <h3 class="text-xl font-bold mb-4">Aim Set: ${target.replace('-', ' ').toUpperCase()}</h3> |
| <p class="text-gray-300 mb-6">Ready to shoot at ${target.replace('-', ' ')}</p> |
| <div class="flex gap-4"> |
| <button class="flex-1 bg-gray-600 hover:bg-gray-700 py-2 rounded-lg transition-all"> |
| Confirm |
| </button> |
| `; |
|
|
| confirmation.querySelector('button').addEventListener('click', () => { |
| confirmation.remove(); |
| this.simulatePenaltyShot(this.getAttribute('title')); |
| }); |
|
|
| document.body.appendChild(confirmation); |
| } |
|
|
| showPowerInterface() { |
| const powerOverlay = document.createElement('div'); |
| powerOverlay.className = 'fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50'; |
| confirmation.innerHTML = ` |
| <div class="bg-gray-800 rounded-xl p-8 max-w-md w-full mx-4 text-center'; |
| confirmation.innerHTML = ` |
| <h3 class="text-xl font-bold mb-4">Power Selection</h3> |
| <div class="mb-6"> |
| <div class="flex justify-between mb-2"> |
| <span>Shot Power</span> |
| <span class="text-yellow-400">85%</span> |
| </div> |
| <div class="w-full bg-gray-700 rounded-full h-4"> |
| <div class="bg-red-500 h-4 rounded-full" style="width: 85%"></div> |
| </div> |
| <input type="range" min="50" max="100" value="85" class="w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer" min="50" max="100" value="85" class="w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer"> |
| <div class="mt-4 flex gap-4"> |
| <button class="flex-1 bg-green-600 hover:bg-green-700 py-2 rounded-lg transition-all"> |
| Set Power |
| </button> |
| `; |
|
|
| const slider = powerOverlay.querySelector('input[type="range"]'); |
| const powerDisplay = powerOverlay.querySelector('.text-yellow-400'); |
| |
| slider.addEventListener('input', (e) => { |
| const power = e.target.value; |
| powerDisplay.textContent = `${power}%`; |
| powerOverlay.querySelector('.bg-red-500').style.width = `${power}%`; |
| }); |
|
|
| powerOverlay.querySelector('button').addEventListener('click', () => { |
| const power = slider.value; |
| powerOverlay.remove(); |
| this.simulatePenaltyShot(this.getAttribute('title')); |
| }); |
|
|
| document.body.appendChild(powerOverlay); |
| } |
| } |
|
|
| customElements.define('game-card', GameCard); |