diff --git a/_sass/styles.scss b/_sass/styles.scss index 36b12ee6..e6aca98b 100644 --- a/_sass/styles.scss +++ b/_sass/styles.scss @@ -164,3 +164,22 @@ table tr:nth-child(2n) { .list-group { --bs-list-group-bg: var(--navbar-col); } + +/* gamepad selector cards */ +.gamepad-selector-card { + transition: all 0.2s ease-in-out; + user-select: none; +} + +.gamepad-selector-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); +} + +.gamepad-selector-card.border-primary { + box-shadow: 0 0 10px rgba(13, 110, 253, 0.3); +} + +.gamepad-selector-card.border-primary:hover { + box-shadow: 0 4px 12px rgba(13, 110, 253, 0.5); +} diff --git a/assets/js/gamepad-tester.js b/assets/js/gamepad-tester.js index 551c598d..ecad6797 100644 --- a/assets/js/gamepad-tester.js +++ b/assets/js/gamepad-tester.js @@ -20,13 +20,15 @@ document.addEventListener('DOMContentLoaded', function() { // Setup gamepad event listeners window.addEventListener("gamepadconnected", function(e) { gamepads[e.gamepad.index] = e.gamepad; - updateGamepadSelector(); + + // Always activate the newly connected gamepad + activeGamepadIndex = e.gamepad.index; + + updateGamepadSelector(); // This will highlight the active card updateStatus(`Gamepad ${e.gamepad.id} connected`); - // If this is the first gamepad, activate it - if (activeGamepadIndex === null) { - activeGamepadIndex = e.gamepad.index; - gamepadSelector.value = activeGamepadIndex; + // Start the loop if it's not already running + if (!animationFrameId) { startGamepadLoop(); } }); @@ -45,18 +47,21 @@ document.addEventListener('DOMContentLoaded', function() { const remainingIndices = Object.keys(gamepads); if (remainingIndices.length > 0) { activeGamepadIndex = Number.parseInt(remainingIndices[0]); - gamepadSelector.value = activeGamepadIndex; } else { stopGamepadLoop(); } } }); - // Event listener for gamepad selector change - gamepadSelector.addEventListener('change', function() { - activeGamepadIndex = Number.parseInt(this.value); - initGamepadButtons(); - initGamepadAxes(); + // Event delegation for gamepad selector cards + gamepadSelector.addEventListener('click', function(e) { + const card = e.target.closest('.gamepad-selector-card'); + if (card) { + activeGamepadIndex = Number.parseInt(card.dataset.index); + updateGamepadSelector(); // Re-render to update active state + initGamepadButtons(); + initGamepadAxes(); + } }); // Event listeners for vibration controls @@ -76,7 +81,7 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('strong-value').textContent = this.value; }); - // Update gamepad selector dropdown + // Update gamepad selector buttons function updateGamepadSelector() { gamepadSelector.innerHTML = ''; @@ -87,20 +92,56 @@ document.addEventListener('DOMContentLoaded', function() { gamepadInfoSection.style.display = 'flex'; gamepadIndices.forEach(index => { - const option = document.createElement('option'); - option.value = index; - option.textContent = `${gamepads[index].id} (Index: ${index})`; - gamepadSelector.appendChild(option); + const card = document.createElement('div'); + card.className = 'card gamepad-selector-card'; + card.dataset.index = index; + card.style.cursor = 'pointer'; + card.style.minWidth = '200px'; + card.style.maxWidth = '300px'; + card.style.borderWidth = '2px'; // Always use 2px border + + const isActive = activeGamepadIndex !== null && Number.parseInt(index) === activeGamepadIndex; + + // Mark active gamepad card + if (isActive) { + card.classList.add('border-primary'); + card.style.backgroundColor = 'rgba(13, 110, 253, 0.15)'; + } else { + card.classList.add('border-secondary'); + card.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; + } + + const cardBody = document.createElement('div'); + cardBody.className = 'card-body p-2'; + + const gamepadInfo = gamepads[index]; + const typeInfo = gamepadHelper.getGamepadInfo(gamepadInfo.id); + + cardBody.innerHTML = ` +