The favorites system allows users to save Pokemon to a personalized collection for quick access.
Overview
The favorites feature provides:
- Add Pokemon to favorites from detail pages
- View all favorites in a dedicated page
- Remove Pokemon from favorites
- State persistence using Pinia store
- Visual indicators for favorited Pokemon
Pinia Store
Favorites are managed using a Pinia store for centralized state management:
import { defineStore } from "pinia";
import { ref } from "vue"
export const useFavoritosStore = defineStore('favoritos',()=>{
const favoritos=ref([]);
const anyadir = (poke)=>{
favoritos.value.push(poke.name);
}
const eliminar = (poke)=>{
favoritos.value.splice(favoritos.value.indexOf(poke),1);
}
return {
favoritos,
anyadir,
eliminar
}
})
The store uses Vue 3’s Composition API style with ref() for reactive state.
Adding to Favorites
From the Pokemon detail page, users can add Pokemon to their favorites:
<script setup>
import { useFavoritosStore } from '@/stores/favoritos';
import { storeToRefs } from 'pinia';
import { computed } from 'vue';
const useFavorito = useFavoritosStore();
const { anyadir } = useFavorito;
const { favoritos } = storeToRefs(useFavorito);
const addToFavorites = () => {
anyadir(datos.value);
notificationMessage.value = `¡${datos.value.name} se ha añadido a favoritos!`;
showNotification.value = true;
setTimeout(() => {
showNotification.value = false;
}, 3000);
};
const isFavorite = computed(() => {
return favoritos.value.some(pokemon => pokemon.name === datos.value?.name);
});
</script>
<template>
<button
@click="addToFavorites"
class="favorite-button"
:class="{ 'is-favorite': isFavorite }"
>
{{ isFavorite ? '★ En favoritos' : '☆ Añadir a favoritos' }}
</button>
</template>
Favorites Page
The dedicated favorites page displays all saved Pokemon:
<script setup>
import { storeToRefs } from "pinia";
import { useFavoritosStore } from '@/stores/favoritos';
import { ref, onMounted } from 'vue';
const useFavoritos = useFavoritosStore();
const { eliminar } = useFavoritos;
const { favoritos } = storeToRefs(useFavoritos);
const pokemons = ref([]);
const cargarFavoritos = async () => {
pokemons.value = []; // Limpiar el array antes de cargar
for (const name of favoritos.value) {
try {
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name.toLowerCase()}`);
const data = await response.json();
pokemons.value.push({
name: data.name,
image: data.sprites.other['official-artwork'].front_default || data.sprites.front_default,
id: data.id
});
} catch (error) {
console.error(`Error cargando datos de ${name}:`, error);
}
}
};
const eliminarFavorito = async (pokemonName) => {
eliminar(pokemonName);
await cargarFavoritos(); // Recargar la lista después de eliminar
};
onMounted(cargarFavoritos);
</script>
The favorites page fetches full Pokemon data for each saved favorite to display images and details.
Removing from Favorites
Users can remove Pokemon from their favorites collection:
<template>
<div v-for="pokemon in pokemons" :key="pokemon.name" class="pokemon-card">
<RouterLink :to="`/pokemons/${pokemon.name}`" class="pokemon-link">
<img :src="pokemon.image" :alt="pokemon.name" class="pokemon-image" />
<h3 class="pokemon-name">{{ pokemon.name.charAt(0).toUpperCase() + pokemon.name.slice(1) }}</h3>
<p class="pokemon-id">#{{ String(pokemon.id).padStart(3, '0') }}</p>
</RouterLink>
<button @click="eliminarFavorito(pokemon.name)" class="remove-button">
<span class="material-icons">♡</span> Quitar de favoritos
</button>
</div>
</template>
Empty State
When no favorites are saved, a helpful empty state is displayed:
<div v-if="pokemons.length === 0" class="empty-state">
<p>No tienes ningún Pokémon en favoritos</p>
</div>
Visual Feedback
Notification
Button State
When adding a Pokemon to favorites, a notification appears:<div class="notification" v-if="showNotification">
{{ notificationMessage }}
</div>
.notification {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #2f855a;
color: white;
padding: 12px 24px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 1000;
animation: slideIn 0.3s ease-out forwards;
}
@keyframes slideIn {
from {
transform: translate(-50%, -100%);
opacity: 0;
}
to {
transform: translate(-50%, 0);
opacity: 1;
}
}
The favorite button changes appearance based on state:.favorite-button {
display: block;
width: calc(100% - 60px);
margin: 20px auto;
padding: 12px;
font-size: 1rem;
font-weight: 600;
color: #f7fafc;
background-color: #2d3748;
border: 2px solid #4a5568;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.favorite-button.is-favorite {
background-color: #2c5282;
border-color: #63b3ed;
color: #63b3ed;
}
State Management Flow
Initialize Store
The Pinia store is initialized with an empty favorites array.
Add Favorite
User clicks “Add to Favorites” button, which calls anyadir() method with Pokemon data.
Update State
The Pokemon’s name is pushed to the favoritos array in the store.
Reactive UI
All components using storeToRefs(useFavoritos) automatically update to reflect the new state.
Display Collection
The favorites page fetches full data for each saved Pokemon and displays them.
Data Structure
The store maintains a simple array of Pokemon names:
favoritos.value = ['pikachu', 'charizard', 'mewtwo']
When displaying favorites, full Pokemon data is fetched:
{
name: 'pikachu',
image: 'https://raw.githubusercontent.com/.../25.png',
id: 25
}
Storing only names keeps the state lightweight, while full data is fetched on-demand when viewing the favorites page.
Pokemon Details
View detailed Pokemon information and add to favorites
Pokemon Browser
Browse all Pokemon to find favorites