Saltar al contenido

post.md

23 oct 2026 · 4 min de lectura
Arte ASCII animado de un catamarán Nacra 17 navegando por el océano al atardecer

Cómo está construido este sitio

Un recorrido breve por la arquitectura de cmkrw.com, desde el diseño de terminal hasta Markdown, gráficos e informes de errores.

  • nextjs
  • design
Contenido

Este sitio es pequeño a propósito: una página, un blog y el mínimo de JavaScript posible. Así encajan las piezas, por si quieres construir algo parecido.

La terminal es el diseño

El sitio está organizado como una aplicación de terminal. Una barra de pestañas recorre la parte superior, una línea de estado ocupa la inferior y todo lo que hay en medio es un panel: una caja con borde y su título integrado en el borde superior. Un pequeño componente, Pane, dibuja todos.

El diseño del blog: una lista de entradas a la izquierda y la entrada abierta a la derechaEl blog como vista maestro-detalle: la lista permanece fija mientras cambia la entrada.

La navegación sigue la misma idea. En el blog, la lista de entradas permanece a la izquierda mientras la entrada se abre a la derecha, así que moverse entre entradas nunca necesita un enlace de volver. Los atajos funcionan como en una terminal, y puedes ordenar esta tabla haciendo clic en el encabezado de una columna:

atajos de teclado
1Abrir inicioglobal
2Abrir blogglobal
jBajarglobal
kSubirglobal
g gIr al inicioglobal
GIr al finalglobal
nEntrada más antiguablog
pEntrada más recienteblog
dCambiar temaglobal
?Mostrar atajosglobal

El movimiento es sobre todo CSS. El comando del encabezado se escribe con una animación steps(), los paneles aparecen al desplazarse a la vista, y tanto la línea bajo la barra de pestañas como el porcentaje de la barra de estado siguen la posición de desplazamiento. Todo se desactiva con prefers-reduced-motion.

Escribir entradas

Las entradas son archivos Markdown en content/blog/<slug>/<locale>.md, renderizados con TanStack Markdown. Si falta una traducción, se usa el archivo en inglés, y draft: true deja una entrada fuera de las compilaciones de producción.

Tres piezas de TanStack hacen el resto:

  • Markdown analiza y renderiza la entrada como elementos de React, sin una cadena HTML de por medio.
  • Highlight colorea los bloques de código. Solo se incluyen los lenguajes que registro, y los colores salen de las mismas variables CSS que el resto del tema.
  • Charts y Table se incrustan con un comentario de una línea que nombra un archivo JSON junto a la entrada.

Los bloques de código pueden llevar un título de archivo:

src/features/blog/embeds/index.tsx
export function createEmbeds(slug: string, locale: string) {
  return {
    chart: ({ data = "", kind = "bar", x = "x", y = "y", title = "Chart" }) => (
      <TuiChart
        rows={getPostDataset(slug, data, locale)}
        kind={kind}
        x={x}
        y={y}
        label={title}
      />
    ),
  }
}

Las tablas de Markdown normales también funcionan y adoptan el mismo estilo:

CapaCarpetaResponsabilidad
Rutasapp/Páginas, metadatos, iconos e imágenes
Interfazcomponents/tui/Paneles, barra superior, barra de estado, atajos
Funcionesfeatures/Secciones de inicio y el blog
Utilidadeslib/, hooks/Metadatos, observabilidad, entrada de teclas

Este es el número de archivos fuente de cada carpeta en el momento de escribir:

Archivos fuente por carpeta
Ver datos
folderfiles
app17
components16
lib16
features15
i18n4
hooks3
types1

Iconos y tarjetas sociales generados

Next.js 16 genera imágenes de metadatos a partir de archivos del directorio app/:

  • icon.tsx y apple-icon.tsx generan el favicon y el icono de iOS a partir de un único SVG, assets/logo-icon.svg.
  • opengraph-image.tsx genera la tarjeta social de la página de inicio, y otra genera una tarjeta para cada entrada.

No existe favicon.tsx. La documentación es explícita: un favicon no se puede generar, así que icon.tsx hace ese trabajo. Todo esto comparte un pequeño conjunto de primitivas, de modo que cambiar la marca cambia el favicon y todas las tarjetas sociales a la vez.

Instrumentación

Dos archivos se encargan de la observabilidad. instrumentation.ts se ejecuta en el servidor e informa de los errores de las peticiones. instrumentation-client.ts se ejecuta antes de la hidratación y registra errores del cliente, métricas web y cambios de ruta. Ambos pasan los eventos a un reportero que los reparte entre varios destinos:

src/lib/observability/server.ts
export const serverReporter = createReporter([
  consoleSink,
  ...(endpoint ? [endpointSink(endpoint)] : []),
])

Los eventos del cliente se envían a /api/observability, que los registra. Apuntar el reportero a un colector real más adelante significa añadir un destino, sin tocar ninguno de los dos archivos de entrada.

Traducciones

El sitio está disponible en diez idiomas, incluidos el árabe y el hebreo, que se leen de derecha a izquierda. Cada texto vive en un archivo de mensajes por idioma; si alguna vez falta una clave, se mezclan por debajo los mensajes del idioma predeterminado, así que una página nunca se queda en blanco. Las entradas funcionan igual: cada idioma tiene su propio archivo y, si falta, se usa el inglés.

NORMAL~/blog/how-this-site-is-built
0%

Atajos de teclado

12
Principal
jk
Desplazar abajo / arriba
g gG
Ir al inicio / al final
np
Entrada más reciente / más antigua
d
Cambiar tema
:
Abrir la paleta de comandos
?
Mostrar u ocultar esta ayuda
esc