Taller de HTML, CSS, Bootstrap y TypeScript: galería dinámica desde un Gist
- Modalidad: Mixta: durante la clase y por fuera de clase.
- Formato: Individual.
- Entregable: Repositorio individual suministrado por el equipo docente (a través de Classroom 50) con la página funcionando y el enlace al Gist en el
README.md.
Objetivos de aprendizaje
Sección titulada «Objetivos de aprendizaje»Al finalizar este taller, cada estudiante debe ser capaz de:
- Configurar un proyecto de TypeScript con
tsc --inity reconocer, a grandes rasgos, para qué sirve eltsconfig.json. - Publicar un conjunto de datos como JSON en un Gist de GitHub y consumirlo desde el navegador con
fetch. - Describir la forma de esos datos con una
interfacede TypeScript y usarla para tipar la respuesta. - Seleccionar un elemento raíz del documento, modificarlo y renderizar contenido dentro de él usando el API del DOM.
- Maquetar una galería de tarjetas responsive con la grilla de Bootstrap, definiendo cuántas columnas se ven en cada breakpoint.
- Compilar el proyecto con
tscy verificar el resultado en el navegador con Live Server.
Parte 1: Marco teórico
Sección titulada «Parte 1: Marco teórico»Qué van a construir
Sección titulada «Qué van a construir»Van a hacer una página que no tiene sus datos escritos en el HTML. El HTML solo aporta un contenedor vacío; los datos viven en un Gist de GitHub (un archivo JSON publicado en internet), y un archivo de TypeScript se encarga de traerlos, recorrerlos y pintar una tarjeta por cada elemento.
flowchart LR
A["Gist en GitHub<br/>(datos.json)"] -->|"fetch()"| B["script.ts<br/>(compilado a script.js)"]
B -->|"API del DOM"| C["index.html<br/>(elemento raíz #app)"]
C -->|"Live Server"| D["Navegador<br/>(galería de tarjetas)"]
La idea de fondo es la separación entre datos y presentación: si mañana cambian los datos del Gist, la página muestra información distinta sin tocar una sola línea de HTML ni de TypeScript.
El compilador de TypeScript y el tsconfig.json
Sección titulada «El compilador de TypeScript y el tsconfig.json»El navegador no entiende TypeScript: solo entiende JavaScript. Por eso el flujo siempre es el mismo: ustedes escriben su código en typescript script.ts, ejecutan el compilador tsc, y este genera un archivo de javascript script.js que es el que finalmente se carga en el index.html.
El archivo tsconfig.json es el que le dice a tsc cómo debe compilar: qué versión de JavaScript generar, qué tipos existen dentro del proyecto, qué tan estricto es el chequeo de tipos, y dónde y con qué archivos deja el resultado. Se crea con tsc --init y, en el Paso 3, les damos el comando con los valores que necesita este taller.
A continuación, se explican las dos configuraciones más importantes que deben estar en el tsconfig.json para este taller:
- La lista de tipos disponibles (opción
lib) debe incluir"dom". Esa es la que hace que en TypeScript existandocument,HTMLElement,fetchy otros elementos que usa el navegador; sin ella,document.getElementById(...)ni siquiera compila. - El formato del archivo generado: TypeScript puede producir el
.jsen varios formatos distintos, y no todos los entiende el navegador por sí solo. La configuración de este taller hace quetscgenere un archivo sencillo, que se puede cargar directamente con una etiqueta<script src="script.js">en elindex.htmly cuyo código se ejecuta apenas el navegador lo lee. Los otros formatos son pensados para proyectos que reparten el código entre muchos archivos. Por ejemplo, en frameworks como Angular que veremos más adelante.
También conviene saber que el .js se genera junto al .ts, es decir, en la misma carpeta del index.html, que es donde este lo va a buscar.
Publicar datos en un Gist de GitHub
Sección titulada «Publicar datos en un Gist de GitHub»Un Gist es un mini repositorio de GitHub pensado para compartir uno o pocos archivos sueltos. Cada Gist público expone sus archivos en una URL “cruda” (raw) con esta forma:
https://gist.githubusercontent.com/<usuario>/<id-del-gist>/raw/<nombre-del-archivo>Esa URL devuelve el contenido del archivo tal cual, sin la interfaz de GitHub alrededor, y con los permisos necesarios para que el navegador pueda leerla desde otra página. Para el ejercicio, eso lo convierte en un servidor de datos gratuito: es la forma más simple de tener un JSON publicado en internet sin montar un backend.
De JSON a objetos tipados: fetch, await e interface
Sección titulada «De JSON a objetos tipados: fetch, await e interface»fetch(url) hace una petición HTTP y retorna una promesa: un objeto que representa un resultado que todavía no ha llegado. Con await le decimos a JavaScript “espera a que esa promesa se resuelva antes de seguir”. Como await solo puede usarse dentro de una función marcada como async, el patrón queda así:
async function obtenerDatos(): Promise<Producto[]> { const respuesta = await fetch(URL_DATOS); // espera la respuesta HTTP const datos = await respuesta.json(); // espera a convertir el cuerpo en objetos return datos;}El problema es que respuesta.json() retorna any: TypeScript no tiene forma de saber qué trae ese JSON. Ahí entra la interface, que es la manera de describir la forma de un objeto en TypeScript:
interface Producto { id: number; nombre: string; precio: number;}Con la interface definida, se usa el operador as para afirmarle al compilador de qué tipo son los datos recibidos:
const datos = (await respuesta.json()) as Producto[];A partir de ese momento el editor les autocompleta datos[0].nombre y les marca un error si escriben datos[0].nombrre. Por eso la interface debe tener exactamente los mismos atributos, con los mismos nombres y tipos, que los objetos del Gist: es el contrato entre los datos publicados y el código que los consume.
Manipular el DOM: elemento raíz, selección y renderizado
Sección titulada «Manipular el DOM: elemento raíz, selección y renderizado»Toda la teoría del DOM está en Manipular el HTML desde TS. Aquí solo recordamos lo que van a usar y cómo se articula.
El patrón del elemento raíz
Sección titulada «El patrón del elemento raíz»En vez de escribir las tarjetas a mano en el HTML, se deja un solo contenedor vacío identificado con un id:
<div id="app"></div>Ese div es el elemento raíz de la aplicación: el punto del árbol DOM del que cuelga todo lo que se pinta desde TypeScript. Es exactamente el mismo patrón que usan frameworks como Angular o React. Trabajar así tiene dos ventajas: el HTML queda estable y mínimo, y todo el contenido variable se genera en un solo lugar del código.
Seleccionar el elemento
Sección titulada «Seleccionar el elemento»Para obtener una referencia a ese elemento se usa el API del DOM sobre la variable global document:
| Función | Qué recibe | Qué retorna |
|---|---|---|
document.getElementById("app") |
El valor del atributo id, sin # |
El elemento con ese id, o null |
document.querySelector("#app") |
Un selector de CSS (#app, .card, h1) |
El primer elemento que coincide, o null |
document.querySelectorAll(".card") |
Un selector de CSS | Una lista con todos los elementos que coinciden |
Los selectores son los mismos que ya usaron en CSS (# para id, . para clase, el nombre solo para la etiqueta); pueden repasarlos en Aplicar los estilos, Selectores.
Como ambas funciones pueden retornar null (si no existe ningún elemento con ese id), en modo estricto TypeScript no deja usar el resultado directamente. La forma más corta de resolverlo es el operador ! al final de la llamada, que le afirma al compilador que ahí sí va a haber un elemento:
const raiz: HTMLElement = document.getElementById("app")!;Modificar y llenar el elemento
Sección titulada «Modificar y llenar el elemento»Con la referencia en la mano, estas son las propiedades que van a usar:
| Propiedad | Qué hace |
|---|---|
raiz.innerText = "..." |
Cambia el texto del elemento. Lo que se asigna se muestra tal cual, aunque contenga etiquetas. |
raiz.innerHTML = "<p>Hola</p>" |
Reemplaza todo el contenido del elemento interpretando el texto como HTML. Es lo que permite crear varios elementos de una sola vez. |
raiz.className = "row g-4" |
Reemplaza la lista de clases CSS del elemento (aquí es como se le aplican las clases de la grilla de Bootstrap desde el código). |
raiz.classList.add("...") |
Agrega una clase sin borrar las demás. |
Para construir el HTML de cada tarjeta se usan los template literals de TypeScript: cadenas delimitadas por comillas invertidas (`) que pueden ocupar varias líneas e insertar valores con ${...}.
const html = `<h5 class="card-title">${producto.nombre}</h5>`;Y para pasar de un arreglo de datos a una sola cadena de HTML, se combinan map (convierte cada objeto en un pedazo de HTML) y join (pega todos esos pedazos en un solo texto):
raiz.innerHTML = datos.map(crearTarjeta).join("");La grilla de Bootstrap: tarjetas responsive
Sección titulada «La grilla de Bootstrap: tarjetas responsive»Una página responsive es la que reacomoda su contenido según el ancho de la pantalla. Bootstrap resuelve esto con breakpoints: puntos de corte de ancho a partir de los cuales se aplica un conjunto distinto de clases. Repasen la grilla de Bootstrap para el detalle.
Para una galería de tarjetas iguales, la forma más directa son las clases row-cols-*, que se ponen en el contenedor (la fila) e indican cuántas columnas caben por fila en cada breakpoint. En este taller la galería debe verse así:
| Breakpoint | Ancho de pantalla | Tarjetas por fila | Clase |
|---|---|---|---|
| xs (celular) | < 576 px | 1 | row-cols-1 |
| sm | ≥ 576 px | 2 | row-cols-sm-2 |
| md | ≥ 768 px | 2 | (hereda de sm) |
| lg | ≥ 992 px | 3 | row-cols-lg-3 |
| xl y xxl | ≥ 1200 px | 4 | row-cols-xl-4 |
Es decir, el contenedor raíz debe terminar con exactamente estas clases:
row row-cols-1 row-cols-sm-2 row-cols-lg-3 row-cols-xl-4 g-4Donde row marca el elemento como fila de la grilla y g-4 define el espacio (gutter) entre tarjetas. Un breakpoint que no se declara hereda el valor del breakpoint anterior: por eso md muestra 2 tarjetas sin necesidad de escribir row-cols-md-2.
Cada elemento del arreglo se envuelve entonces en un <div class="col">, y adentro va la tarjeta:
<div class="col"> <div class="card h-100"> <img src="..." class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">Título</h5> <p class="card-text">Descripción</p> </div> </div></div>Parte 2: Formato de trabajo
Sección titulada «Parte 2: Formato de trabajo»- El taller es individual: cada estudiante crea su propio repositorio desde Classroom 50 y hace su propia entrega.
- El tema de los datos es libre (películas, canciones, recetas, videojuegos, cafés, plantas, lo que quieran), pero debe cumplir los mínimos de la sección Paso 1.
- Los datos no pueden estar escritos en el
index.htmlni en elscript.ts. Deben venir del Gist a través defetch. Elindex.htmlque entreguen no debe contener ninguna tarjeta escrita a mano. - No editen
script.jsdirectamente. Ese archivo lo genera el compilador; cualquier cambio que le hagan a mano se pierde en la siguiente compilación. El código se escribe siempre enscript.ts. - Hagan commits pequeños y con mensajes descriptivos a medida que avanzan, no un único commit al final.
Parte 3: Instrucciones paso a paso
Sección titulada «Parte 3: Instrucciones paso a paso»Paso 0: Preparación
Sección titulada «Paso 0: Preparación»-
Verifiquen que tienen Node.js instalado (se asume que ya lo instalaron siguiendo el tutorial de configuración del ambiente):
Ventana de terminal node --version -
Instalen el compilador de TypeScript de forma global y verifiquen la instalación:
Ventana de terminal npm install -g typescripttsc --version -
Instalen la extensión Live Server en VSCode: abran el panel de extensiones (
Ctrl + Shift + Xen Windows y Linux,Cmd + Shift + Xen macOS), busquen Live Server (de Ritwick Dey) e instálenla.
-
Creen el repositorio individual del taller desde Classroom 50:
-
Inicien sesión en classroom50.org con su cuenta de GitHub. En Classroom 50 organizations, busquen la organización del curso (Ing. Software Moderna - ISIS2211) y hagan clic en Open.
-
En My classrooms, ubiquen su sección y entren con View assignments.
-
En la lista Assignments, busquen la tarea de este taller. A diferencia del taller de Git, esta tarea es individual, así que no aparece marcada como Group ni pide seleccionar equipo. Hagan clic en Accept assignment.
-
Revisen que estén registrados con su usuario correcto y que el repositorio se vaya a crear con el nombre esperado (algo como
ISIS2211/...-taller-ts-<su-usuario>). Confirmen con Accept assignment. -
Cuando aparezca Assignment accepted, abran el repositorio con Open repository. Como el taller es individual, no deben agregar colaboradores.

-
-
Clonen el repositorio en su máquina y ábranlo en VSCode:
Ventana de terminal git clone <url-del-repo>Trabajen directamente sobre
main: en este taller no hace falta crear una rama.
Paso 1: Elegir el tema y diseñar la estructura de los datos
Sección titulada «Paso 1: Elegir el tema y diseñar la estructura de los datos»Piensen en un tema que les guste y del que puedan listar varios elementos comparables entre sí: películas favoritas, canciones, recetas, videojuegos, equipos de fútbol, cafeterías del campus, plantas, razas de perros, etc.
Sobre ese tema deben definir un arreglo de objetos que cumpla estos mínimos:
-
Mínimo 6 objetos en el arreglo.
-
Mínimo 5 atributos por objeto, y todos los objetos deben tener exactamente los mismos atributos:
Atributo Tipo Requisito idnumberIdentificador único de cada elemento (1, 2, 3, …). (un título) stringTexto corto: el nombre del elemento. Ustedes eligen el nombre del atributo ( nombre,titulo, …).(una descripción) stringTexto más largo, de una o dos frases. (un valor numérico) numberPrecio, año, duración, puntaje, calorías… lo que aplique al tema. imagenstringURL de una imagen (ver abajo). -
Pueden agregar más atributos si quieren (por ejemplo, un
booleancomodisponible, o una categoría de tipostring).
Para las imágenes usen Picsum, un servicio que entrega fotos de ejemplo del tamaño que se le pida. Basta con armar la URL así:
https://picsum.photos/seed/cafe1/400/250seed/cafe1: la “semilla” de la imagen. Mientras la semilla no cambie, Picsum devuelve siempre la misma foto, así que usen una semilla distinta por cada elemento del arreglo (cafe1,cafe2, …). Si omiten la semilla, la foto cambia en cada recarga.400/250: ancho y alto en píxeles.
Paso 2: Publicar los datos en un Gist
Sección titulada «Paso 2: Publicar los datos en un Gist»-
Entren a gist.github.com con su cuenta de GitHub.
-
Escriban una descripción para el Gist y nombren el archivo
datos.json. La extensión importa: es la que activa el resaltado de sintaxis y les ayuda a detectar errores de formato.
-
Peguen su arreglo en formato JSON. Este es un ejemplo con el tema “cafés”; ustedes deben reemplazarlo por su propio tema y sus propios atributos:
[{"id": 1,"nombre": "Espresso","descripcion": "Café concentrado servido en taza pequeña, base de casi todas las demás preparaciones.","precio": 4500,"imagen": "https://picsum.photos/seed/cafe1/400/250"},{"id": 2,"nombre": "Cappuccino","descripcion": "Partes iguales de espresso, leche vaporizada y espuma de leche.","precio": 7000,"imagen": "https://picsum.photos/seed/cafe2/400/250"},{"id": 3,"nombre": "Latte","descripcion": "Espresso con bastante leche vaporizada y una capa delgada de espuma.","precio": 7500,"imagen": "https://picsum.photos/seed/cafe3/400/250"},{"id": 4,"nombre": "Americano","descripcion": "Espresso rebajado con agua caliente, de sabor más suave y mayor volumen.","precio": 5000,"imagen": "https://picsum.photos/seed/cafe4/400/250"},{"id": 5,"nombre": "Mocha","descripcion": "Combinación de espresso, chocolate y leche vaporizada.","precio": 8500,"imagen": "https://picsum.photos/seed/cafe5/400/250"},{"id": 6,"nombre": "Cold brew","descripcion": "Café extraído en frío durante varias horas, menos ácido y más dulce.","precio": 9000,"imagen": "https://picsum.photos/seed/cafe6/400/250"}] -
Hagan clic en Create public gist. Debe ser público, no secret.
-
Ya creado el Gist, hagan clic en el botón Raw que aparece sobre el archivo y copien la URL de la barra de direcciones. Esa es la URL que van a usar en el código; debe verse parecida a:
https://gist.githubusercontent.com/su-usuario/a1b2c3d4e5f6/raw/datos.json
-
Peguen el enlace del Gist en el
README.mddel repositorio: hace parte del entregable.
Paso 3: Inicializar el proyecto de TypeScript
Sección titulada «Paso 3: Inicializar el proyecto de TypeScript»Al terminar el taller, el repositorio debe tener esta estructura:
Directoriomi-repo-del-taller/
- index.html
- script.ts
- script.js (generado por
tsc, no se edita a mano) - tsconfig.json
- README.md
Desde la terminal, dentro de la carpeta del repositorio clonado, ejecuten:
tsc --init --target es2020 --lib es2020,dom --strict --module commonjs --moduleDetection auto --declaration false --declarationMap false --sourceMap falseEsto crea el tsconfig.json ya configurado para el taller. Ábranlo y confirmen que contiene, al menos, estas líneas:
{ "compilerOptions": { "target": "es2020", "lib": ["es2020", "dom"], "strict": true, "moduleDetection": "auto", "declaration": false, "declarationMap": false, "sourceMap": false }}Paso 4: Crear el index.html
Sección titulada «Paso 4: Crear el index.html»Creen el archivo index.html y copien este contenido. Trae Bootstrap desde su CDN, un título, y el elemento raíz vacío (<div id="app">) donde se van a pintar las tarjetas:
<!DOCTYPE html><html lang="es"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"> <title>Título página</title></head><body> <div class="container py-4"> <h1 id="titulo" class="mb-4">Cargando...</h1> <div id="app"></div> </div> <script src="script.js"></script></body></html>Sobre este HTML:
- Cambien el contenido de
<title>por el nombre de su tema. container py-4centra el contenido y le da margen vertical.<h1 id="titulo">arranca con un texto provisional porque su contenido también se va a modificar desde TypeScript.<div id="app"></div>es el elemento raíz. Está vacío a propósito: ni sus clases de grilla ni las tarjetas se escriben aquí, todo se asigna desde el código.- La etiqueta
<script src="script.js">va al final delbody, después deldiv, para que cuando el script se ejecute el elemento raíz ya exista en el DOM. Si la pusieran en el<head>,getElementById("app")retornaríanull.
Paso 5: Escribir el script.ts
Sección titulada «Paso 5: Escribir el script.ts»Creen el archivo script.ts y ármenlo en este orden.
-
Definan la interface con el mismo esquema del Gist. Este es el paso que conecta los datos con el código: la interface debe tener exactamente los mismos atributos, con los mismos nombres y los mismos tipos que los objetos que publicaron en
datos.json. Si en el Gist el atributo se llamaprecioy es un número, aquí debe serprecio: number. Adapten los nombres a su tema:interface Cafe {id: number;nombre: string;descripcion: string;precio: number;imagen: string;} -
Guarden la URL del Gist en una constante y escriban la función que trae los datos. El tipo de retorno
Promise<Cafe[]>dice “esta función entrega, en el futuro, un arreglo deCafe”:const URL_DATOS = "https://gist.githubusercontent.com/su-usuario/a1b2c3d4e5f6/raw/datos.json";async function obtenerDatos(): Promise<Cafe[]> {const respuesta = await fetch(URL_DATOS);if (!respuesta.ok) {throw new Error(`No se pudieron cargar los datos (HTTP ${respuesta.status})`);}return (await respuesta.json()) as Cafe[];}La verificación de
respuesta.okes importante: si el Gist está mal escrito o es secreto, GitHub responde un 404 yfetchno lanza error por sí solo. Sin esa validación, el error aparecería mucho más adelante y sería más difícil de rastrear. -
Escriban la función que convierte un objeto en el HTML de una tarjeta. Recibe un elemento del arreglo y retorna un
stringcon la columna y la tarjeta de Bootstrap:function crearTarjeta(cafe: Cafe): string {return `<div class="col"><div class="card h-100"><img src="${cafe.imagen}" class="card-img-top" alt="${cafe.nombre}"><div class="card-body"><h5 class="card-title">${cafe.nombre}</h5><p class="card-text">${cafe.descripcion}</p><span class="badge text-bg-primary">$${cafe.precio}</span></div></div></div>`;}Noten que la tarjeta usa los cinco atributos de la interface. El
altde la imagen no es decorativo: es el texto que leen los lectores de pantalla y el que se muestra si la imagen no carga. -
Escriban la función principal, que es donde se manipula el DOM. Hace cuatro cosas: obtiene el elemento raíz, lo modifica asignándole las clases de la grilla, pide los datos, y los pinta:
async function pintarGaleria(): Promise<void> {const titulo: HTMLElement = document.getElementById("titulo")!;const raiz: HTMLElement = document.getElementById("app")!;titulo.innerText = "Mis cafés favoritos";raiz.className = "row row-cols-1 row-cols-sm-2 row-cols-lg-3 row-cols-xl-4 g-4";try {const datos = await obtenerDatos();raiz.innerHTML = datos.map(crearTarjeta).join("");} catch (error) {raiz.className = "";raiz.innerHTML = `<div class="alert alert-danger">${(error as Error).message}</div>`;}}El
try/catchhace que, si algo falla, el error se vea en la página y no solo en la consola. Es la diferencia entre una página en blanco sin explicación y un mensaje que dice qué pasó. -
Llamen a la función al final del archivo. Sin esta línea no pasa absolutamente nada: las funciones anteriores solo quedan definidas.
pintarGaleria();
Paso 6: Compilar y ver el resultado
Sección titulada «Paso 6: Compilar y ver el resultado»-
Compilen el proyecto desde la terminal, en la carpeta del repositorio:
Ventana de terminal tscSi no imprime nada, compiló bien y ya debe existir el archivo
script.jsal lado delscript.ts. Si imprime errores, arréglenlos antes de seguir: mientras haya errores de tipo, el.jspuede quedar desactualizado. -
Abran la página con Live Server: clic derecho sobre
index.html→ Open with Live Server. Se abre una pestaña del navegador en una dirección comohttp://127.0.0.1:5500/index.html.
-
Verifiquen que la galería sea responsive: abran las herramientas de desarrollo del navegador (
F12en Windows y Linux,Cmd + Option + Ien macOS), activen el modo de dispositivo (Ctrl + Shift + M, oCmd + Shift + Men macOS) y vayan cambiando el ancho. Deben ver 1 tarjeta por fila en pantallas angostas, 2 a partir de 576 px, 3 a partir de 992 px y 4 a partir de 1200 px.

-
Revisen la consola del navegador (pestaña Console de las mismas herramientas de desarrollo). No debe haber errores en rojo.
Paso 7: Subir el resultado y entregar
Sección titulada «Paso 7: Subir el resultado y entregar»-
Confirmen los cambios y súbanlos a
main:Ventana de terminal git add .git commit -m "Agrega galería dinámica con datos del Gist"git pushSí,
script.jsse sube al repositorio: aunque sea un archivo generado, es el que necesita elindex.htmlpara funcionar cuando alguien más abra la página. -
Entren al repositorio en GitHub y verifiquen que en
mainestén elindex.html, elscript.ts, elscript.js, eltsconfig.jsony elREADME.mdcon el enlace al Gist. Si algo falta, corríjanlo y vuelvan a hacerpushantes de seguir. -
La calificación solo se ejecuta cuando marcan la entrega con la etiqueta (tag)
entrega. Cuando estén seguros de quemainya tiene la versión final, ejecuten:Ventana de terminal git fetch origin main && git tag -f entrega origin/main && git push -f origin entregaPueden repetir ese comando las veces que quieran antes de la fecha límite: la opción
-fmueve la etiqueta al último estado demainy vuelve a lanzar la revisión. Cuenta la última ejecución antes del cierre. -
En GitHub, entren a la pestaña Actions del repositorio y confirmen que la ejecución disparada por la etiqueta haya terminado. También pueden revisar en classroom50.org que la entrega haya sido registrada.
Entregable final
Sección titulada «Entregable final»En el repositorio individual de Classroom 50, con todo el trabajo en la rama main y la etiqueta entrega apuntando al último commit:
README.mdcon su nombre, el tema elegido y el enlace al Gist público.tsconfig.jsongenerado con las opciones del Paso 3.index.htmlcon el elemento raíz<div id="app"></div>vacío y sin datos escritos a mano.script.tscon lainterfaceque refleja el esquema del Gist, la carga confetch, y la manipulación del DOM.script.jscompilado y actualizado (debe corresponder alscript.tsentregado).- La página, al abrirse con Live Server, muestra al menos 6 tarjetas con imagen, título, descripción y el valor numérico, distribuidas según los breakpoints definidos.
- La etiqueta
entregapublicada en GitHub apuntando al commit final demain(sin ella no se ejecuta la revisión y la entrega no cuenta).
Recomendaciones y errores frecuentes
Sección titulada «Recomendaciones y errores frecuentes»| Síntoma | Causa más probable |
|---|---|
La página queda en blanco y la consola dice Failed to fetch |
Abrieron el archivo con doble clic (file://) en vez de Live Server, o el Gist es secreto. |
Las tarjetas muestran undefined |
Los nombres de los atributos de la interface no coinciden con los del Gist. |
Los cambios del script.ts no se ven en el navegador |
Olvidaron ejecutar tsc, o el tsc falló con errores. |
exports is not defined en la consola |
Hay un import o un export en script.ts. Elimínenlo. |
Cannot find name 'document' al compilar |
Falta "dom" en la opción lib del tsconfig.json. |
Object is possibly 'null' al compilar |
Falta el operador ! al final de getElementById(...). |
| Las tarjetas quedan una debajo de otra, siempre | Falta la clase row o las clases row-cols-* en el elemento raíz. |
| Las tarjetas tienen alturas distintas y se ven desalineadas | Falta la clase h-100 en el div.card. |
Además:
- Trabajen de a un paso a la vez y verifiquen en el navegador antes de seguir. Es mucho más fácil encontrar un error acumulado en 10 líneas que en 60.
- Antes de escribir el código de las tarjetas, prueben que el
fetchfunciona con un simpleconsole.log(datos)dentro depintarGaleria. - Si cambian el contenido del Gist, recarguen la página forzando al navegador a pedir la versión nueva:
Ctrl + Shift + Ren Windows y Linux,Cmd + Shift + Ren macOS.