Guía de componentes
Esta página muestra cada componente funcionando, seguido del código que lo genera. Todos funcionan sin servidor: el portal es HTML estático.
Las clases se escriben en MDX (Markdown con componentes). Importa los componentes al inicio del archivo, después del frontmatter:
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';import Ejercicio from '~/components/Ejercicio.astro';import Pregunta from '~/components/Pregunta.astro';import Descarga from '~/components/Descarga.astro';import Sandbox from '~/components/Sandbox.astro';import Excalidraw from '~/components/Excalidraw.astro';Diagramas Mermaid
Sección titulada «Diagramas Mermaid»Escribe un bloque de código con el lenguaje mermaid. El diagrama se adapta al modo claro u oscuro, se puede ampliar y descargar como SVG. El atributo title es opcional y se usa como pie de figura y nombre del archivo.
flowchart LR
U([Usuario]) --> CDN[CDN / Proxy]
CDN --> FE[Frontend]
FE -->|HTTP/JSON| API[API]
API --> DB[(Base de datos)]
API -.->|eventos| Q[[Cola]]
Q -.-> W[Worker]```mermaid title="Arquitectura de una aplicación web típica"flowchart LR U([Usuario]) --> CDN[CDN / Proxy] CDN --> FE[Frontend] FE -->|HTTP/JSON| API[API] API --> DB[(Base de datos)]```Mermaid admite diagramas de secuencia, clases, estados, entidad-relación, Gantt y más: consulta la documentación de Mermaid. La librería solo se descarga en las páginas que contienen diagramas.
erDiagram
ESTUDIANTE ||--o{ INSCRIPCION : realiza
CURSO ||--o{ INSCRIPCION : recibe
ESTUDIANTE { int id string nombre }
CURSO { int id string titulo }
INSCRIPCION { date fecha float nota }Diagramas Excalidraw
Sección titulada «Diagramas Excalidraw»Para diagramas dibujados a mano: se muestra el SVG exportado y se ofrece la fuente .excalidraw, que cualquiera puede abrir y editar en excalidraw.com.
<Excalidraw svg="/diagramas/arquitectura-software/ciclo-adr.svg" fuente="/diagramas/arquitectura-software/ciclo-adr.excalidraw" alt="Descripción del diagrama para lectores de pantalla" titulo="Ciclo de vida de un ADR"/>Bloques de código
Sección titulada «Bloques de código»Resaltado de sintaxis, botón de copiar, título de archivo, líneas destacadas y diferencias (con Expressive Code):
export async function inscribir(estudianteId: string, cursoId: string) { const curso = await cursos.buscar(cursoId); if (curso.cupos === 0) { throw new Error('El curso no tiene cupos disponibles'); } await db.insert({ estudianteId, cursoId }); await db.insert({ estudianteId, cursoId, fecha: new Date() });}```ts title="src/servicios/inscripciones.ts" {3-4} ins={7} del={6}…```Pestañas por lenguaje
Sección titulada «Pestañas por lenguaje»Con syncKey, todas las pestañas de la página (y del sitio) recuerdan el lenguaje elegido.
const suma = (a, b) => a + b;def suma(a, b): return a + bint suma(int a, int b) { return a + b; }<Tabs syncKey="lenguaje"><TabItem label="JavaScript" icon="seti:javascript">
```jsconst suma = (a, b) => a + b;```
</TabItem><TabItem label="Python" icon="seti:python">…</TabItem></Tabs>Callouts
Sección titulada «Callouts»:::note[Concepto clave]Texto en **Markdown**.:::Los tipos son note, tip, caution y danger. El título entre corchetes es opcional.
Pasos y laboratorios
Sección titulada «Pasos y laboratorios»-
Instala las dependencias:
Ventana de terminal npm install -
Inicia el servidor de desarrollo.
-
Abre el navegador en
http://localhost:4321.
<Steps>
1. Instala las dependencias:
```bash npm install ```
2. Inicia el servidor de desarrollo.
</Steps>Para estructuras de proyecto, usa <FileTree>:
Directoriosrc/
Directoriocomponentes/
- Boton.tsx
- index.ts archivo destacado
- package.json
Ejercicios
Sección titulada «Ejercicios»Escribe una función invertir(texto) que devuelva el texto al revés, sin usar reverse().
Ver solución
function invertir(texto) { let resultado = ''; for (const caracter of texto) resultado = caracter + resultado; return resultado;}<Ejercicio titulo="Invierte una cadena" nivel="básico" duracion="10 min">
Enunciado en **Markdown**.
<Fragment slot="solucion">
Solución (opcional), plegada por defecto.
</Fragment></Ejercicio>Propiedades: titulo (obligatorio), nivel (básico, intermedio, avanzado), duracion y tipo (Ejercicio, Reto, Práctica).
Recursos descargables
Sección titulada «Recursos descargables»<Descarga href="/recursos/<materia>/archivo.pdf" titulo="Título visible" descripcion="Opcional" />El tipo y el tamaño se calculan solos. Si el archivo no existe en public/, la compilación falla: así no se publican enlaces rotos.
Ejemplos HTML interactivos
Sección titulada «Ejemplos HTML interactivos»Los ejemplos se ejecutan en un iframe aislado (sandbox): pueden usar JavaScript, pero no acceden a cookies, almacenamiento ni a la página del portal. Debajo se ofrece el código fuente.
Ver código fuente (anatomia-url.html)
<!doctype html><html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex, nofollow"><title>Anatomía de una URL</title><style> body { font: 15px/1.5 system-ui, sans-serif; margin: 0; padding: 1.25rem; color: #1b1d26; background: #fff; } label { font-weight: 600; display: block; margin-bottom: .35rem; } input { width: 100%; box-sizing: border-box; padding: .6rem .75rem; font: 14px ui-monospace, monospace; border: 1px solid #c7cad3; border-radius: .5rem; } input:focus { outline: 2px solid #3f47c6; border-color: transparent; } dl { display: grid; grid-template-columns: max-content 1fr; gap: .4rem 1rem; margin: 1.25rem 0 0; } dt { font-weight: 600; color: #3f47c6; } dd { margin: 0; font-family: ui-monospace, monospace; word-break: break-all; } .vacio { color: #8a8f9c; font-style: italic; font-family: system-ui, sans-serif; } .error { color: #c0392b; margin-top: 1rem; } .nota { font-size: 13px; color: #5d6270; margin-top: 1rem; }</style></head><body> <label for="url">Escribe una URL</label> <input id="url" value="https://ejemplo.edu:8443/cursos/web?unidad=2&tema=http#ejercicios" spellcheck="false" autocomplete="off"> <div id="salida" aria-live="polite"></div> <p class="nota">El análisis usa la API estándar <code>URL</code> del navegador.</p><script> const partes = [ ['Esquema', u => u.protocol.replace(':', '')], ['Host', u => u.hostname], ['Puerto', u => u.port || `(por defecto: ${u.protocol === 'https:' ? 443 : 80})`], ['Ruta', u => u.pathname], ['Consulta', u => [...u.searchParams].map(([k, v]) => `${k} = ${v}`).join('\n')], ['Fragmento', u => u.hash.slice(1) && `${u.hash.slice(1)} ← no se envía al servidor`], ]; const entrada = document.getElementById('url'); const salida = document.getElementById('salida'); function analizar() { try { const u = new URL(entrada.value); salida.innerHTML = '<dl>' + partes.map(([nombre, f]) => { const valor = f(u); const dd = document.createElement('dd'); if (valor) { dd.textContent = valor; dd.style.whiteSpace = 'pre-line'; } else { dd.textContent = '(vacío)'; dd.className = 'vacio'; } return `<dt>${nombre}</dt>${dd.outerHTML}`; }).join('') + '</dl>'; } catch { salida.innerHTML = '<p class="error">No es una URL válida. ¿Incluiste el esquema (https://)?</p>'; } } entrada.addEventListener('input', analizar); analizar();</script></body></html><Sandbox src="/ejemplos/<materia>/ejemplo.html" titulo="Título" alto={400} />Los archivos van en public/ejemplos/<materia>/. Usa codigo={false} para ocultar el código fuente.
Cuestionarios autocorregibles
Sección titulada «Cuestionarios autocorregibles»<Pregunta enunciado="¿Qué componente usarías para mostrar los pasos de un laboratorio?" opciones={['<Tabs>', '<Steps>', '<Descarga>', '<Sandbox>']} correcta={1} explicacion="Se muestra al acertar."/>correcta es la posición de la respuesta empezando en 0. La corrección ocurre en el navegador y no se guarda nada: es una herramienta de autoevaluación, no de calificación (la respuesta es visible en el código de la página).
Otros componentes de Starlight
Sección titulada «Otros componentes de Starlight»- Insignias: Nuevo Opcional Avanzado
- Tarjetas de enlace: