Comparte tus conocimientos sobre series de televisión y películas.
¿Tienes preguntas o sugerencias? Contáctanos.
!DOCTYPE html
html lang=es
head
meta charset=UTF-8
meta name=viewport content=width=device-width, initial-scale=1.0
titleCatálogo Interactivo de Películastitle
style
root {
--bg-color #141414;
--card-bg #181818;
--text-color #ffffff;
--accent-color #e50914;
}
body {
font-family 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background-color var(--bg-color);
color var(--text-color);
margin 0;
padding 20px;
}
h1 {
color var(--accent-color);
text-align center;
margin-bottom 30px;
}
.grid {
display grid;
grid-template-columns repeat(auto-fill, minmax(250px, 1fr));
gap 25px;
max-width 1200px;
margin 0 auto;
}
.card {
background-color var(--card-bg);
border-radius 8px;
overflow hidden;
box-shadow 0 4px 10px rgba(0,0,0,0.5);
transition transform 0.3s ease;
position relative;
}
.cardhover {
transform scale(1.03);
}
.card-img-container {
position relative;
width 100%;
height 350px;
}
.card img {
width 100%;
height 100%;
object-fit cover;
}
Indicador visual de visto superpuesto en la imagen
.viewed-badge {
position absolute;
top 10px;
right 10px;
background-color rgba(0, 200, 83, 0.9);
color white;
padding 5px 10px;
border-radius 20px;
font-size 12px;
font-weight bold;
display none;
}
.card.is-viewed .viewed-badge {
display block;
}
.card-content {
padding 15px;
}
.card-title {
margin 0 0 10px 0;
font-size 1.1rem;
}
.actions {
display flex;
justify-content space-between;
align-items center;
border-top 1px solid #333;
padding-top 12px;
}
.btn {
background none;
border none;
color #aaa;
cursor pointer;
font-size 1.3rem;
padding 5px;
transition color 0.2s, transform 0.1s;
border-radius 50px;
width 40px;
height 40px;
display flex;
align-items center;
justify-content center;
}
.btnhover {
transform scale(1.2);
background-color rgba(255,255,255,0.1);
}
Estados activos según la selección del usuario
.btn-view.active { color #00c853; } Verde
.btn-love.active { color #ff3d00; } Rojo fuego (Me encanta)
.btn-like.active { color #29b6f6; } Azul (MenosNormal)
.btn-dislike.active { color #757575; } Gris oscuro (No me gusta)
.feedback-status {
text-align center;
margin-top 30px;
font-size 0.9rem;
color #808080;
}
style
head
body
h1Mi Catálogo de Películash1
div class=grid id=catalog-griddiv
div class=feedback-status
Los cambios se guardan automáticamente en la base de datos local (LocalStorage) de tu navegador.
div
script
1. Datos simulados del servidor (Películas con imágenes de ejemplo)
const peliculasIniciales = [
{ id p1, titulo Aventura en el Espacio, img httpsunsplash.com },
{ id p2, titulo El Secreto del Bosque, img httpsunsplash.com },
{ id p3, titulo Neón y Asfalto 2049, img httpsunsplash.com },
{ id p4, titulo Mar de Tormentas, img httpsunsplash.com }
];
2. Base de Datos Local Inicializa el estado si es la primera vez que se abre la web
if (!localStorage.getItem('usuario_interacciones')) {
localStorage.setItem('usuario_interacciones', JSON.stringify({}));
}
Leer datos de nuestra base de datos
function obtenerBaseDatos() {
return JSON.parse(localStorage.getItem('usuario_interacciones'));
}
Guardar datos en nuestra base de datos
function guardarEnBaseDatos(id, campo, valor) {
const db = obtenerBaseDatos();
if (!db[id]) {
db[id] = { visto false, reaccion null };
}
db[id][campo] = valor;
localStorage.setItem('usuario_interacciones', JSON.stringify(db));
}
3. Renderizar la interfaz web dinámicamente
const grid = document.getElementById('catalog-grid');
const interaccionesUsuario = obtenerBaseDatos();
peliculasIniciales.forEach(pelicula = {
Recuperar el estado guardado para esta película específica
const estadoGuardado = interaccionesUsuario[pelicula.id] { visto false, reaccion null };
const card = document.createElement('div');
card.className = `card ${estadoGuardado.visto 'is-viewed' ''}`;
card.id = `card-${pelicula.id}`;
card.innerHTML = `
div class=card-img-container
span class=viewed-badge✓ Vistospan
img src=${pelicula.img} alt=${pelicula.titulo}
div
div class=card-content
h3 class=card-title${pelicula.titulo}h3
div class=actions
!-- Botón de Visto --
button class=btn btn-view ${estadoGuardado.visto 'active' ''}
onclick=toggleVisto('${pelicula.id}') title=Marcar como visto
👁
button
!-- Botones de Reacción (Me gusta mucho, regular, no me gusta) --
button class=btn btn-love ${estadoGuardado.reaccion === 'mucho' 'active' ''}
onclick=setReaccion('${pelicula.id}', 'mucho') title=Me gusta mucho
🔥
button
button class=btn btn-like ${estadoGuardado.reaccion === 'menos' 'active' ''}
onclick=setReaccion('${pelicula.id}', 'menos') title=Me gusta (pero menos)
👍
button
button class=btn btn-dislike ${estadoGuardado.reaccion === 'no' 'active' ''}
onclick=setReaccion('${pelicula.id}', 'no') title=No me gusta
👎
button
div
div
`;
grid.appendChild(card);
});
4. Lógica de Interacción del Usuario (Controladores de Eventos)
Cambiar estado de Visto
function toggleVisto(id) {
const cardElement = document.getElementById(`card-${id}`);
const btnView = cardElement.querySelector('.btn-view');
const db = obtenerBaseDatos();
const estadoActual = db[id].visto false;
const nuevoEstado = !estadoActual;
Guardar cambio en la Base de Datos
guardarEnBaseDatos(id, 'visto', nuevoEstado);
Actualizar la interfaz visual en tiempo real
if (nuevoEstado) {
cardElement.classList.add('is-viewed');
btnView.classList.add('active');
} else {
cardElement.classList.remove('is-viewed');
btnView.classList.remove('active');
}
}
Cambiar estado de las 3 reacciones de valoración
function setReaccion(id, tipoReaccion) {
const cardElement = document.getElementById(`card-${id}`);
const btnLove = cardElement.querySelector('.btn-love');
const btnLike = cardElement.querySelector('.btn-like');
const btnDislike = cardElement.querySelector('.btn-dislike');
const db = obtenerBaseDatos();
const reaccionActual = db[id].reaccion null;
Si hace clic en la misma reacción que ya estaba activa, se desmarca (vuelve a null)
const nuevaReaccion = (reaccionActual === tipoReaccion) null tipoReaccion;
Guardar cambio en la Base de Datos
guardarEnBaseDatos(id, 'reaccion', nuevaReaccion);
Limpiar todas las clases activas de los tres botones de reacción
btnLove.classList.remove('active');
btnLike.classList.remove('active');
btnDislike.classList.remove('active');
Activar únicamente el botón que corresponde a la nueva reacción
if (nuevaReaccion === 'mucho') btnLove.classList.add('active');
if (nuevaReaccion === 'menos') btnLike.classList.add('active');
if (nuevaReaccion === 'no') btnDislike.classList.add('active');
}
script
body
html