Skip to content

Instantly share code, notes, and snippets.

@diegoolipa
Created November 20, 2024 05:02
Show Gist options
  • Save diegoolipa/edefdb43e87f693f6698c020acb64f87 to your computer and use it in GitHub Desktop.
Save diegoolipa/edefdb43e87f693f6698c020acb64f87 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard de APIs</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
padding: 20px;
background-color: #f0f2f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card-title {
font-size: 1.2em;
margin-bottom: 15px;
color: #333;
}
.card-content {
min-height: 150px;
}
button {
background-color: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.loading {
opacity: 0.5;
}
img {
max-width: 100%;
height: auto;
border-radius: 4px;
}
.pokemon-info {
text-align: center;
}
.pokemon-types {
display: flex;
gap: 8px;
justify-content: center;
margin-top: 8px;
}
.type-badge {
background: #e0e0e0;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.9em;
}
.error {
color: red;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Dashboard de APIs</h1>
<button id="refreshAll">Actualizar Todo</button>
</div>
<div class="grid">
<!-- Chuck Norris Card -->
<div class="card">
<h2 class="card-title">Chuck Norris Joke</h2>
<div class="card-content" id="chuckContent"></div>
<button onclick="fetchChuckNorrisJoke()">Nueva Broma</button>
</div>
<!-- Cocktail Card -->
<div class="card">
<h2 class="card-title">Cocktail Aleatorio</h2>
<div class="card-content" id="cocktailContent"></div>
<button onclick="fetchRandomCocktail()">Otro Cocktail</button>
</div>
<!-- Pokemon Card -->
<div class="card">
<h2 class="card-title">Pokémon Aleatorio</h2>
<div class="card-content" id="pokemonContent"></div>
<button onclick="fetchRandomPokemon()">Otro Pokémon</button>
</div>
</div>
</div>
<script>
// Elementos del DOM
const chuckContent = document.getElementById('chuckContent');
const cocktailContent = document.getElementById('cocktailContent');
const pokemonContent = document.getElementById('pokemonContent');
const refreshAllButton = document.getElementById('refreshAll');
// Función para manejar errores
function handleError(element, error) {
console.error(error);
element.innerHTML = `<p class="error">Error: No se pudieron cargar los datos. Por favor, intenta de nuevo.</p>`;
}
// Chuck Norris API
async function fetchChuckNorrisJoke() {
try {
chuckContent.classList.add('loading');
const response = await fetch('https://api.chucknorris.io/jokes/random');
const data = await response.json();
chuckContent.innerHTML = `<p>${data.value}</p>`;
} catch (error) {
handleError(chuckContent, error);
} finally {
chuckContent.classList.remove('loading');
}
}
// Cocktail API
async function fetchRandomCocktail() {
try {
cocktailContent.classList.add('loading');
const response = await fetch('https://www.thecocktaildb.com/api/json/v1/1/random.php');
const data = await response.json();
const drink = data.drinks[0];
cocktailContent.innerHTML = `
<img src="${drink.strDrinkThumb}" alt="${drink.strDrink}" style="max-height: 200px; object-fit: cover;">
<h3 style="margin: 10px 0">${drink.strDrink}</h3>
<p>Categoría: ${drink.strCategory}</p>
`;
} catch (error) {
handleError(cocktailContent, error);
} finally {
cocktailContent.classList.remove('loading');
}
}
// Pokemon API
async function fetchRandomPokemon() {
try {
pokemonContent.classList.add('loading');
const randomId = Math.floor(Math.random() * 151) + 1;
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${randomId}`);
const pokemon = await response.json();
const types = pokemon.types
.map(type => `<span class="type-badge">${type.type.name}</span>`)
.join('');
pokemonContent.innerHTML = `
<div class="pokemon-info">
<img src="${pokemon.sprites.front_default}" alt="${pokemon.name}" style="height: 120px;">
<h3 style="margin: 10px 0; text-transform: capitalize;">${pokemon.name}</h3>
<div class="pokemon-types">${types}</div>
</div>
`;
} catch (error) {
handleError(pokemonContent, error);
} finally {
pokemonContent.classList.remove('loading');
}
}
// Función para actualizar todo
async function refreshAll() {
refreshAllButton.disabled = true;
refreshAllButton.textContent = 'Cargando...';
await Promise.all([
fetchChuckNorrisJoke(),
fetchRandomCocktail(),
fetchRandomPokemon()
]);
refreshAllButton.disabled = false;
refreshAllButton.textContent = 'Actualizar Todo';
}
// Event Listeners
refreshAllButton.addEventListener('click', refreshAll);
// Cargar datos iniciales
refreshAll();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment