Reto 1
Oficial · lista de cotejo
Agregar una sección semántica nueva ("Testimonios")
📋 Problema: el docente te pide agregar una sección nueva llamada "Testimonios", enlazada desde el nav, con al menos un testimonio dentro.
Código a escribir
<!-- li + a: quinto enlace del nav, mismo patrón de clase que los otros cuatro -->
<li><a class="hover:text-emerald-400" href="#testimonios">Testimonios</a></li>
<!-- section nueva: id="testimonios" debe ser IGUAL al href de arriba -->
<section id="testimonios" class="max-w-5xl mx-auto px-6 py-14">
<!-- h2: título de la sección, mismo estilo que las demás -->
<h2 class="text-2xl font-bold mb-6">Testimonios</h2>
<!-- grid-cols-1 md:grid-cols-2: una columna en celular, dos desde 768px -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- article: el testimonio se entiende leído solo, por eso NO es un div -->
<article class="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm">
<!-- p: la cita del testimonio -->
<p class="text-slate-600 text-sm mb-3">"Excelente predisposición para aprender."</p>
<!-- p: autor de la cita, más chico y en negrita -->
<p class="font-semibold text-sm">— Docente, UTH</p>
</article>
</div>
</section>
🔧 Paso a paso
- Agregas el
<li><a> en el nav como quinto enlace, con href="#testimonios" y la misma clase hover que los demás.
- Creas un
<section id="testimonios"> — el id debe ser idéntico al href del paso 1 para que el enlace funcione.
- Le pones un
<h2> con el título, mismo estilo (text-2xl font-bold mb-6) que las otras secciones.
- Armas el contenedor con
grid grid-cols-1 md:grid-cols-2 gap-6: una columna en celular, dos desde tablet en adelante.
- Cada testimonio va en un
<article>, no en un <div>, porque el contenido se entiende leído solo, fuera de contexto.
- Dentro pones un
<p> con la cita entre comillas y otro <p> más chico y en negrita con el autor.
- Cierras
article, div y section en orden.
🗣️ Dices mientras lo haces: "agrego la sección con su id, la enlazo desde el nav, y uso <article> porque el testimonio se lee solo, fuera de contexto."
Reto 2
Convertir las "Cajas" sueltas en una sección semántica
📋 Problema: hay un bloque de "Cajas" fuera de cualquier <section>, sin id navegable. Te piden convertirlo en una sección semántica correcta.
Antes
<!-- ANTES: div suelto, sin id, sin section que lo contenga -->
<div class="flex flex-col md:flex-row gap-4">
<div class="bg-sky-500 p-4">Caja 1</div>
<div class="bg-emerald-300 p-4">Caja 2</div>
</div>
Después
<!-- DESPUÉS: envuelto en section semántica con id navegable -->
<section id="destacados">
<!-- div contenedor: flex flex-col apila en celular, md:flex-row en fila -->
<div class="flex flex-col md:flex-row gap-4">
<!-- primera caja: fondo celeste, esquinas redondeadas -->
<div class="bg-sky-500 p-4 rounded-lg text-white">Caja 1</div>
<!-- segunda caja: mismo patrón, otro color -->
<div class="bg-emerald-300 p-4 rounded-lg">Caja 2</div>
</div>
</section>
🔧 Paso a paso
- Detectas que las cajas están en un
<div> suelto, sin id y sin ninguna <section> que las contenga.
- Envuelves todo el bloque en
<section id="destacados"> para que sea una región con nombre, navegable por ancla.
- Dejas el div contenedor con
flex flex-col md:flex-row gap-4: en celular las cajas se apilan, desde md: van en fila.
- A cada caja le agregas
rounded-lg (y a la primera text-white) para que se vean como tarjetas, no como bloques de color planos.
- Cierras la
section.
🗣️ Dices mientras lo haces: "envuelvo las cajas en un <section> con id, así quedan navegables y dejan de ser un div suelto sin significado."
Reto 3
Completar el <p> vacío de "Sobre mí"
📋 Problema: en la sección "Sobre mí" quedó un <p> vacío de relleno. Te piden completarlo con contenido real.
Antes → Después
<!-- ANTES: quedó vacío de relleno -->
<p class="text-slate-500 text-sm"></p>
<!-- DESPUÉS: italic le da tono de cita destacada -->
<p class="text-slate-500 text-sm italic">"Aprender haciendo, un commit a la vez."</p>
🔧 Paso a paso
- Ubicas el
<p> vacío dentro de "Sobre mí" — no tiene texto ni cumple ninguna función así.
- Escribes una frase real entre comillas, a modo de cita personal.
- Le agregas la clase
italic para que se lea como una cita destacada, no como texto de relleno.
🗣️ Dices mientras lo haces: "relleno el <p> vacío con una frase real; uso italic porque es una cita destacada, no texto de relleno."
Reto 4
Corregir el alt de la foto de perfil
📋 Problema: el atributo alt de la foto describe el estilo CSS ("Rounded corners") en vez de la imagen. Te piden corregirlo.
Antes → Después
<!-- ANTES: describe el estilo CSS, no la foto -->
<img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="Rounded corners">
<!-- DESPUÉS: alt describe QUÉ muestra la imagen -->
<img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="Foto de perfil de Prado Diaz Bernardo">
🔧 Paso a paso
- Ubicas el
<img> de la foto de perfil y miras su atributo alt.
- Ves que dice "Rounded corners" — describe una clase CSS (
rounded-lg), no la foto.
- Lo reemplazas por una descripción real de la imagen: "Foto de perfil de Prado Diaz Bernardo".
- Dejas el resto de atributos (
src, class) exactamente igual, porque el problema era solo el alt.
🗣️ Dices mientras lo haces: "cambio el alt para que describa la foto en sí, no la clase CSS que le aplico."
Reto 5
Agregar una quinta tarjeta a la grilla de Skills
📋 Problema: te piden agregar una quinta skill a la grilla, manteniendo exactamente el mismo patrón de clases que las otras cuatro.
Código a escribir
<!-- misma clase exacta que las otras cuatro, solo cambia el contenido -->
<article class="bg-white rounded-xl border border-slate-200 p-5
shadow-sm hover:shadow-md transition">
<!-- h3: nombre de la skill, mismo estilo que las demás -->
<h3 class="font-semibold mb-1">Django</h3>
<!-- p: descripción breve, mismo estilo que las demás -->
<p class="text-sm text-slate-500">Framework web en Python, patrón MTV.</p>
</article>
🔧 Paso a paso
- Copias la clase exacta de una tarjeta de Skills existente (
bg-white rounded-xl border border-slate-200 p-5 shadow-sm hover:shadow-md transition) para no romper la consistencia visual.
- Dentro pones un
<h3> con el nombre de la nueva skill (Django).
- Debajo, un
<p> con una descripción breve, mismo tamaño y color que las demás (text-sm text-slate-500).
- Pegas esta quinta tarjeta dentro de la misma grilla que las otras cuatro.
🗣️ Dices mientras lo haces: "copio la clase exacta de una tarjeta existente para mantener consistencia, y solo cambio el h3 y el p."
Reto 6
Oficial · lista de cotejo
Cambiar el breakpoint de Skills de md: a lg:
📋 Problema: la grilla de Skills pasa a 3 columnas desde 768px (tablet). Te piden que pase a 3 columnas recién desde 1024px (escritorio).
Antes → Después
<!-- ANTES: 3 columnas ya desde 768px (tablet) -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5">
<!-- DESPUÉS: 3 columnas recién desde 1024px (escritorio) -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
🔧 Paso a paso
- Ubicas el
<div> de la grilla de Skills y localizas la clase md:grid-cols-3.
- Entiendes que
md: activa esa regla desde 768px — o sea, ya en tablet.
- La reemplazas por
lg:grid-cols-3, que recién activa la regla desde 1024px.
- Dejas
grid-cols-1 y sm:grid-cols-2 sin tocar, porque el enunciado solo pide mover el breakpoint de 3 columnas.
🗣️ Dices mientras lo haces: "cambio el prefijo md: por lg: para que las 3 columnas aparezcan recién en escritorio, no en tablet."
Reto 7
Agregar una segunda tarjeta a "Proyectos"
📋 Problema: la sección "Proyectos" solo tiene una tarjeta. Te piden agregar una segunda, con el mismo patrón visual.
Código a escribir
<!-- mismas clases que la primera, incluido el hover -->
<article class="bg-white rounded-2xl border border-slate-200 p-6
shadow-sm hover:shadow-lg hover:-translate-y-1 transition">
<!-- h3: nombre del proyecto -->
<h3 class="text-lg font-bold mb-2">Portafolio Personal</h3>
<!-- p: descripción breve -->
<p class="text-slate-600 text-sm mb-4">Sitio web propio con HTML5 semántico y Tailwind CSS.</p>
<!-- a: enlace verde con subrayado al pasar el mouse -->
<a href="#" class="text-emerald-700 font-semibold text-sm hover:underline">Ver repositorio →</a>
</article>
🔧 Paso a paso
- Ubicas la tarjeta de "Proyectos" ya existente y copias su
<article> completo, con las mismas clases (incluido hover:shadow-lg hover:-translate-y-1).
- Pegas la copia justo después de la original, dentro del mismo contenedor.
- Cambias el
<h3> por el nombre del nuevo proyecto.
- Cambias el
<p> por su descripción.
- Dejas el
<a> "Ver repositorio →" con el mismo estilo, solo actualizando el href si corresponde.
🗣️ Dices mientras lo haces: "duplico la tarjeta existente con las mismas clases, incluido el hover, y cambio solo el contenido."
Reto 8
Ordenar la tarjeta de perfil "flotante" del final del archivo
📋 Problema: al final del archivo quedó un bloque de perfil suelto, fuera de cualquier section, en inglés y con un alt genérico. Te piden integrarlo dentro de "Sobre mí", traducido y con datos reales.
Antes
<!-- ANTES: bloque suelto al final del body, sin section, textos en inglés -->
<div class="flex items-center space-x-4 p-4 bg-white rounded-xl shadow-md max-w-sm">
<img class="w-16 h-16 rounded-full object-cover border-2 border-indigo-500 shadow-sm"
src="img/foto1.png" alt="Student profile photo" />
<div>
<h3 class="text-lg font-semibold text-gray-900">Prado Diaz Bernardo</h3>
<p class="text-sm font-medium text-indigo-600">Computer Science Engineer</p>
<p class="text-xs text-gray-500">ID: #84920</p>
</div>
</div>
Después
<!-- DESPUÉS: integrada dentro de "sobre-mi", en español, con alt real -->
<div class="flex items-center space-x-4 p-4 bg-white rounded-xl shadow-md max-w-sm mt-6">
<!-- img: alt describe la foto, no el rol -->
<img class="w-16 h-16 rounded-full object-cover border-2 border-indigo-500 shadow-sm"
src="img/foto1.png" alt="Foto de perfil de Prado Diaz Bernardo" />
<!-- div: agrupa nombre, rol y dato adicional, todo en español -->
<div>
<h3 class="text-lg font-semibold text-gray-900">Prado Diaz Bernardo</h3>
<p class="text-sm font-medium text-indigo-600">Estudiante de Desarrollo Web</p>
<p class="text-xs text-gray-500">UTH · APLICAWEB 4to</p>
</div>
</div>
🔧 Paso a paso
- Buscas el bloque de perfil suelto al final del
body — está fuera de cualquier <section>.
- Ves que su
alt dice "Student profile photo" y los textos están en inglés.
- Cortas el bloque y lo pegas dentro de la sección "sobre-mi", como contenido adicional (le agregas
mt-6 para separarlo).
- Traduces "Computer Science Engineer" a "Estudiante de Desarrollo Web" y "ID: #84920" a algo real como "UTH · APLICAWEB 4to".
- Corriges el
alt de la imagen para que describa la foto, no el rol de la persona.
🗣️ Dices mientras lo haces: "muevo el bloque suelto dentro de sobre-mi, traduzco los textos al español y corrijo el alt para que describa la foto, no el rol."
Reto 9
Agregar un botón "Cancelar" con sus propios estados
📋 Problema: el formulario solo tiene el botón "Enviar". Te piden agregar un botón "Cancelar" con sus propios estados, sin que dispare el envío.
Código a escribir
<!-- div: agrupa ambos botones en fila -->
<div class="flex gap-3">
<!-- botón Enviar: el que ya tenías, sin cambios -->
<button type="submit" class="bg-emerald-600 hover:bg-emerald-700 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-400">Enviar</button>
<!-- botón Cancelar: type="button" para que NO dispare el envío del form -->
<button type="button" class="bg-transparent border border-slate-600 hover:bg-slate-800 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:outline-none focus:ring-2 focus:ring-slate-400">Cancelar</button>
</div>
🔧 Paso a paso
- Ubicas el botón "Enviar" del formulario y ves que no tiene un botón "Cancelar" al lado.
- Envuelves ambos botones en un
<div class="flex gap-3"> para que queden en fila con espacio entre ellos.
- Agregas el nuevo
<button type="button">: el type="button" es la parte crítica, porque evita que dispare el submit del formulario.
- Le das sus propios colores (
bg-transparent border) y sus propios estados hover:bg-slate-800 y focus:ring-2 focus:ring-slate-400, distintos a los del botón Enviar.
🗣️ Dices mientras lo haces: "agrego el botón con type="button" para que no dispare el envío del formulario, y le doy sus propios estados de hover y focus."
Reto 10
Volver el header sticky
📋 Problema: te piden que el header quede fijo en la parte superior al hacer scroll.
Código a escribir
<!-- sticky top-0: se pega arriba al hacer scroll · z-10: queda por encima del resto -->
<header class="bg-slate-900 text-white flex flex-col gap-4 md:flex-row md:items-center md:justify-between px-6 py-6 md:px-10 sticky top-0 z-10">
🔧 Paso a paso
- Ubicas la etiqueta
<header> y revisas sus clases actuales.
- Agregas
sticky, que hace que el elemento se comporte como estático hasta que llega al top del viewport, y ahí se "pega".
- Agregas
top-0, que define en qué punto exacto se pega (el borde superior).
- Agregas
z-10 para que el header quede por encima del contenido que sigue scrolleando debajo.
🗣️ Dices mientras lo haces: "agrego sticky top-0 z-10 para que el header quede pegado arriba al hacer scroll, por encima del resto del contenido."
Reto 11
Centrar la sección "Destacados" con contenedor
📋 Problema: la sección "Destacados" no tiene el mismo ancho y centrado que las demás secciones. Te piden unificarlo.
Código a escribir
<!-- max-w-5xl: mismo ancho máximo que las demás secciones · mx-auto: la centra · px-6: mismo relleno -->
<section id="destacados" class="max-w-5xl mx-auto px-6 py-10">
🔧 Paso a paso
- Ubicas la
<section id="destacados"> y ves que no tiene clases de ancho ni centrado, a diferencia de las demás secciones.
- Le agregas
max-w-5xl, el mismo ancho máximo que usan las otras secciones del sitio.
- Le agregas
mx-auto para centrar ese ancho máximo horizontalmente en la pantalla.
- Le agregas
px-6 para que tenga el mismo relleno lateral que las demás, y no toque los bordes en celular.
🗣️ Dices mientras lo haces: "agrego max-w-5xl mx-auto px-6 para que la sección use el mismo ancho y centrado que las demás."
Reto 12
Cambiar la paleta de acento de emerald a indigo
📋 Problema: te piden cambiar el color de acento del sitio de emerald a indigo, en el nav y en el botón principal.
Código a escribir
<!-- nav: emerald-400 → indigo-400 -->
<li><a class="hover:text-indigo-400" href="#sobre-mi">Sobre mí</a></li>
<!-- botón enviar: emerald-600/700/400 → indigo-600/700/400 -->
<button type="submit" class="bg-indigo-600 hover:bg-indigo-700 transition text-white font-semibold px-6 py-2.5 rounded-lg focus:ring-2 focus:ring-indigo-400">Enviar</button>
🔧 Paso a paso
- Ubicas cada lugar donde aparece la palabra
emerald: el hover del nav y el botón "Enviar".
- En el
<a> del nav, cambias hover:text-emerald-400 por hover:text-indigo-400.
- En el
<button>, cambias bg-emerald-600 hover:bg-emerald-700 por bg-indigo-600 hover:bg-indigo-700.
- Cambias también
focus:ring-emerald-400 por focus:ring-indigo-400, para que el foco del teclado use el mismo color nuevo.
- Mantienes los mismos números de intensidad (400, 600, 700) en cada caso — solo cambia el nombre del color.
🗣️ Dices mientras lo haces: "reemplazo cada clase emerald por indigo en el nav y en el botón, manteniendo los mismos números de intensidad (400/600/700)."
Reto 13
Agregar transición suave al hover del nav
📋 Problema: el cambio de color al pasar el mouse por el nav es instantáneo. Te piden que sea una transición suave.
Antes → Después
<!-- ANTES: el cambio de color es instantáneo -->
<li><a class="hover:text-emerald-400" href="#sobre-mi">Sobre mí</a></li>
<!-- DESPUÉS: transition-colors anima el cambio -->
<li><a class="hover:text-emerald-400 transition-colors" href="#sobre-mi">Sobre mí</a></li>
🔧 Paso a paso
- Ubicas cualquier
<a> del nav y ves que solo tiene hover:text-emerald-400.
- Le agregas la clase
transition-colors al mismo elemento.
- Con eso el navegador anima el cambio de color en vez de aplicarlo de golpe, sin tocar nada de CSS aparte.
🗣️ Dices mientras lo haces: "agrego transition-colors para que el cambio de color al pasar el mouse sea suave, no instantáneo."
Reto 14
Explicación, no código
Explicar por qué el formulario SÍ está bien vinculado
📋 Problema: el docente señala el label y el input del campo Correo y te pide explicar, sin tocar código, por qué ya están bien vinculados.
Código que te señala
<!-- for="correo" es IGUAL al id de abajo: así el label queda vinculado al input -->
<label for="correo" class="block text-sm font-semibold mb-1">Correo</label>
<input type="email" id="correo" name="correo" required placeholder="tu@correo.com" ...>
🔧 Paso a paso (cómo lo defiendes en voz alta)
- Señalas el atributo
for="correo" del <label> y lo comparas con el id="correo" del <input>: son idénticos, letra por letra.
- Explicas que esa coincidencia es lo que "vincula" ambos elementos en el DOM.
- Mencionas el primer beneficio: al enfocar el input con el teclado, el lector de pantalla anuncia también el texto del label.
- Mencionas el segundo beneficio: hacer clic en el texto "Correo" también activa/enfoca el input, aunque el clic no caiga justo sobre el campo.
🗣️ Qué defender: "al enfocar el input se anuncia también su label (lector de pantalla), y hacer clic en el texto 'Correo' también activa el campo."
Reto 15
Foto de perfil responsiva (mobile-first)
📋 Problema: la foto de perfil tiene un tamaño fijo (w-64 h-64) incluso en celular. Te piden hacerla responsiva, mobile-first.
Antes → Después
<!-- ANTES: 64 unidades fijas siempre, incluso en celular -->
<img src="img/foto1.png" class="rounded-lg w-64 h-64 object-cover" alt="...">
<!-- DESPUÉS: w-full por defecto (celular), tamaño fijo recién desde sm: -->
<img src="img/foto1.png" class="rounded-lg w-full max-w-xs h-64 object-cover sm:w-64" alt="...">
🔧 Paso a paso
- Ubicas el
<img> de la foto de perfil y ves w-64 h-64 fijos, incluso en celular.
- Reemplazas
w-64 por w-full, que es la base sin prefijo — se aplica primero, en cualquier ancho, incluido celular.
- Agregas
max-w-xs para que en pantallas grandes esa "base" no crezca de más antes de llegar al breakpoint.
- Agregas
sm:w-64 al final: recién desde 640px el ancho vuelve a ser fijo — ese es el orden mobile-first.
🗣️ Dices mientras lo haces: "cambio el ancho fijo por w-full max-w-xs como base para celular, y reservo sm:w-64 para pantallas más grandes — eso es mobile-first."
Reto 16
De grid a flex en Skills
📋 Problema: te piden cambiar el layout de Skills de grid de columnas fijas a flex-wrap.
Antes → Después
<!-- ANTES: columnas iguales por breakpoint -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5">
<!-- DESPUÉS: flex-wrap acomoda tarjetas según el espacio disponible -->
<div class="flex flex-wrap gap-5">
🔧 Paso a paso
- Ubicas el div de la grilla de Skills con
grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3.
- Borras las tres clases de
grid-cols y grid.
- Escribes
flex flex-wrap en su lugar.
- Entiendes la diferencia: ahora las tarjetas fluyen una al lado de la otra y saltan de línea solas cuando no entran, en vez de forzar un número fijo de columnas por breakpoint.
🗣️ Dices mientras lo haces: "cambio grid por flex flex-wrap para que las tarjetas se acomoden según el espacio disponible en vez de columnas fijas."
Reto 17
Versionar el cambio con Git y verificar el redeploy
📋 Problema: hiciste un cambio en el código. Te piden versionarlo con Git y verificar que Render lo despliega solo.
Comandos a correr
# git add .: agrega TODOS los archivos modificados al área de preparación
git add .
# git commit -m: guarda una fotografía del proyecto con mensaje descriptivo
git commit -m "Corregir alt de la foto y agregar seccion Testimonios"
# git push: sube el commit a GitHub y dispara el redeploy automático en Render
git push
🔧 Paso a paso
- Abres la terminal integrada de VS Code, parado en la carpeta del proyecto.
- Corres
git add . para mandar todos los archivos modificados al área de preparación (staging).
- Corres
git commit -m "..." con un mensaje que describe qué cambiaste, para guardar esa fotografía del proyecto.
- Corres
git push para subir el commit a GitHub.
- Ese push dispara automáticamente el webhook que hace que Render redespliegue el sitio, sin que hagas nada manual ahí.
🗣️ Dices mientras lo haces: "hago add, commit con un mensaje descriptivo y push; eso dispara el redeploy automático en Render sin tocar nada manualmente."
Reto 18
Corregir un problema de contraste (Lighthouse)
📋 Problema: Lighthouse marca un problema de contraste de color insuficiente en un texto. Te piden corregirlo.
Antes → Después
<!-- ANTES: gris muy claro sobre fondo blanco, contraste insuficiente -->
<p class="text-slate-400">Estudiante de Desarrollo Web · UTH</p>
<!-- DESPUÉS: slate-600 cumple el contraste mínimo AA de WCAG -->
<p class="text-slate-600">Estudiante de Desarrollo Web · UTH</p>
🔧 Paso a paso
- Corres Lighthouse (o miras el reporte) y ves que marca contraste insuficiente en un texto.
- Ubicas el
<p> señalado y ves que usa text-slate-400, un gris muy claro sobre fondo blanco.
- Lo cambias por
text-slate-600, un gris más oscuro.
- Verificas que ese tono sí cumple la relación de contraste mínima 4.5:1 que pide el nivel AA de WCAG.
🗣️ Dices mientras lo haces: "cambio slate-400 por slate-600 porque el gris claro no cumple el contraste mínimo AA sobre fondo blanco."
Reto 19
Agregar maxlength al campo "Nombre"
📋 Problema: el campo "Nombre" del formulario solo tiene minlength. Te piden agregarle también un maxlength razonable.
Antes → Después
<!-- ANTES: solo tiene minlength -->
<input type="text" id="nombre" name="nombre" minlength="2" placeholder="Tu nombre" ...>
<!-- DESPUÉS: maxlength evita que se escriba de más -->
<input type="text" id="nombre" name="nombre" required minlength="2" maxlength="60" placeholder="Tu nombre" ...>
🔧 Paso a paso
- Ubicas el
<input> del campo "Nombre" y ves que solo tiene minlength="2".
- Entiendes que
minlength pone un piso (mínimo de caracteres) pero no un techo.
- Agregas
maxlength="60" al mismo input, como límite superior razonable para un nombre.
- Dejas
required y minlength="2" intactos — solo sumas la restricción que faltaba.
🗣️ Dices mientras lo haces: "agrego maxlength="60" junto al minlength que ya tenía, para poner un tope razonable al campo."
Reto 20
Integrador · guion oficial
Ejercicio integrador — el ejemplo oficial del guion de defensa oral
📋
Problema: el ejemplo oficial del guion: agregar una tarjeta de proyecto nueva reutilizando las clases existentes, y versionarla con Git. Tal como figura en
guion-defensa-oral.html para Unidad 1.
Código a escribir
<!-- article nuevo dentro de #proyectos, mismas clases que el ya existente -->
<article class="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm hover:shadow-lg hover:-translate-y-1 transition">
<h3 class="text-lg font-bold mb-2">Portafolio Personal</h3>
<p class="text-slate-600 text-sm mb-4">Sitio web propio con HTML5 semántico y Tailwind CSS.</p>
<a href="#" class="text-emerald-700 font-semibold text-sm hover:underline">Ver repositorio →</a>
</article>
🔧 Paso a paso
- Ubicas la sección
#proyectos y copias el <article> existente completo, con todas sus clases (incluido hover:-translate-y-1).
- Pegas la copia como segunda tarjeta, dentro del mismo contenedor.
- Cambias el
<h3>, el <p> y el href del <a> por los datos del nuevo proyecto ("Portafolio Personal").
- Guardas, y en la terminal corres
git add ., git commit -m "..." y git push.
- Abres la URL de Render y refrescas para mostrar que el redeploy ya se aplicó solo.
🗣️ Guion: "agrego la tarjeta reutilizando las mismas clases para mantener consistencia visual, hago git add, commit y push, y muestro que Render redesplegó solo."