import "/style.css"; // Ensure CSS is imported import Pokedex from "pokedex-promise-v2"; const options = { protocol: "https", hostName: "pokeapi.co", versionPath: "/api/v2/", cacheLimit: 100 * 1000, timeout: 10 * 1000, }; const pokemon = new Pokedex(options); // --- DOM Elements --- const searchButton = document.getElementById("searchButton"); const pokemonNameInput = document.getElementById("pokemonName"); const pokemonInfoDiv = document.getElementById("pokemonInfo"); const voiceSearchButton = document.getElementById("voiceSearchButton"); const historyList = document.getElementById("historyList"); // --- State --- let searchHistory = []; // Now stores full data objects const MAX_HISTORY_LENGTH = 3; let lastDisplayedPokemon = null; // Track the last displayed Pokémon // --- Functions --- const updateHistoryDisplay = (justAddedName = null) => { historyList.innerHTML = ""; // Clear current list visually if (searchHistory.length === 0) { historyList.innerHTML = '
  • No history yet.
  • '; } else { searchHistory.forEach((pokemonData, index) => { const li = document.createElement("li"); li.classList.add("cursor-pointer"); // Make whole card clickable // Determine scale based on index let scale = 1.0; // Default scale for the newest item if (index === 1) scale = 0.8; else if (index === 2) scale = 0.6; // Apply scale via inline style li.style.transform = `scale(${scale})`; // Build the inner HTML for the history card li.innerHTML = `

    ${ pokemonData.name.charAt(0).toUpperCase() + pokemonData.name.slice(1) }

    ${
        pokemonData.name
      }

    Type(s): ${pokemonData.types .map((t) => t.type.name) .join(", ")}

    Height: ${pokemonData.height / 10} m

    Weight: ${pokemonData.weight / 10} kg

    `; // Add click listener to the card li.addEventListener("click", () => { pokemonNameInput.value = pokemonData.name; // Set input value searchPokemon(); // Trigger search }); // Animation for the newest item if (index === 0 && pokemonData.name === justAddedName) { li.classList.add("history-item-enter"); // Apply initial scale for animation start li.style.transform = `translateX(-50px) scale(${scale * 0.9})`; // Start smaller setTimeout(() => { li.classList.remove("history-item-enter"); // Transition back to the target scale li.style.transform = `scale(${scale})`; }, 10); // Small delay } historyList.appendChild(li); }); } }; const displayPokemonInfo = (data) => { const pokemonName = data.name; // Keep name for comparison pokemonInfoDiv.innerHTML = `

    ${ pokemonName.charAt(0).toUpperCase() + pokemonName.slice(1) }

    ${pokemonName}

    Type(s): ${data.types .map((typeInfo) => typeInfo.type.name) .join(", ")}

    Height: ${data.height / 10} m

    Weight: ${data.weight / 10} kg

    `; // --- Update History --- // Only add the previous Pokémon to history (not the current one) if (lastDisplayedPokemon && lastDisplayedPokemon.name !== data.name) { // Remove if already exists searchHistory = searchHistory.filter( (item) => item.name !== lastDisplayedPokemon.name ); // Add to beginning searchHistory.unshift(lastDisplayedPokemon); // Limit history length if (searchHistory.length > MAX_HISTORY_LENGTH) { searchHistory = searchHistory.slice(0, MAX_HISTORY_LENGTH); } updateHistoryDisplay(lastDisplayedPokemon.name); } else { updateHistoryDisplay(); } // Update lastDisplayedPokemon to current lastDisplayedPokemon = data; }; const displayError = (error) => { if (error && error.response && error.response.status === 404) { pokemonInfoDiv.innerHTML = `

    Sorry, Pokémon not found. Please check the spelling and try again.

    `; } else { pokemonInfoDiv.innerHTML = `

    An error occurred while fetching Pokémon data. Please try again later.

    `; console.error("Error fetching Pokémon:", error); } }; const searchPokemon = () => { const name = pokemonNameInput.value.trim().toLowerCase(); if (!name) { pokemonInfoDiv.innerHTML = `

    Please enter a Pokémon name.

    `; return; } pokemonInfoDiv.innerHTML = `

    Loading...

    `; pokemon.getPokemonByName(name).then(displayPokemonInfo).catch(displayError); }; // --- Event Listeners & Voice Search --- searchButton.addEventListener("click", searchPokemon); pokemonNameInput.addEventListener("keypress", (event) => { if (event.key === "Enter") { searchPokemon(); } }); const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; let recognition; if (SpeechRecognition) { recognition = new SpeechRecognition(); recognition.continuous = false; recognition.lang = "en-US"; recognition.interimResults = false; recognition.maxAlternatives = 1; voiceSearchButton.addEventListener("click", () => { try { pokemonNameInput.placeholder = "Listening..."; recognition.start(); voiceSearchButton.classList.add("text-red-500"); } catch (e) { console.error("Speech recognition already started.", e); pokemonNameInput.placeholder = "Enter Pokémon name or use mic"; } }); recognition.onresult = (event) => { const speechResult = event.results[0][0].transcript.toLowerCase(); pokemonNameInput.value = speechResult; searchPokemon(); }; recognition.onspeechend = () => { recognition.stop(); pokemonNameInput.placeholder = "Enter Pokémon name or use mic"; voiceSearchButton.classList.remove("text-red-500"); }; recognition.onerror = (event) => { pokemonInfoDiv.innerHTML = `

    Voice recognition error: ${event.error}

    `; console.error("Speech recognition error:", event); pokemonNameInput.placeholder = "Enter Pokémon name or use mic"; voiceSearchButton.classList.remove("text-red-500"); }; recognition.onnomatch = (event) => { pokemonInfoDiv.innerHTML = `

    Didn't recognize that Pokémon name.

    `; pokemonNameInput.placeholder = "Enter Pokémon name or use mic"; voiceSearchButton.classList.remove("text-red-500"); }; } else { console.warn("Web Speech API not supported in this browser."); voiceSearchButton.style.display = "none"; } // --- Initial Setup --- updateHistoryDisplay(); // Initialize history display on page load