Saltearse al contenido

Theming — 3. Integración con Astro

00:00 / 00:00

Integración del tema

Vamos a ver cómo integrar un tema dinámico en nuestro sitio web, para el ejemplo hemos elegido Astro como tecnología, pero este enfoque puede adaptarse fácilmente a cualquier framework o librería de frontend.

En este proyecto de blog, ya tenemos Content Island 🏝️ integrado, así que el siguiente paso será cargar el objeto de tema actual a través de una llamada a la API.

1. Crear el endpoint para obtener el tema

Primero definimos las interfaces TypeScript que modelarán la estructura de datos que recibiremos desde Content Island.

💡 Tip: Content Island proporciona un botón "TS" que genera automáticamente las interfaces TypeScript basadas en el esquema de tu contenido. Puedes copiar estos modelos como punto de partida.

Para nuestro caso, necesitamos hacer algunos ajustes para crear una estructura que combine tanto el tema principal como las fuentes relacionadas en un objeto Theme unificado:

layout/theme.model.ts

export interface Font {
  id: string;
  name: string;
  url: string;
}

export interface ThemeResponse {
  id: string;
  color: string;
  fontTitle: string;
  fontBody: string;
}

export interface Theme {
  id: string;
  color: string;
  fontTitle: Font;
  fontBody: Font;
}

Creamos una función getTheme que se encarga de obtener los valores del tema desde Content Island, incluyendo las fuentes asociadas:

layout/theme.api.ts

import client from "../lib/client";
import type { Font, Theme, ThemeResponse } from "./theme.model";

export const getTheme = async (): Promise<Theme> => {
  const themeContent = await client.getContent<ThemeResponse>({
    id: "688a417b4e051d2bea7eaf19",
  });

  const fontTitle = await client.getContent<Font>({
    id: themeContent.fontTitle,
  });

  const fontBody = await client.getContent<Font>({
    id: themeContent.fontBody,
  });

  return {
    id: themeContent.id,
    color: themeContent.color,
    fontTitle: fontTitle,
    fontBody: fontBody,
  };
};

2. Aplicar el tema en el layout

En el layout principal de Astro, vamos a:

  • Cargar el tema dinámicamente.

  • Generar variables CSS con los valores obtenidos.

  • Definir fuentes de fallback por si el CMS no tiene datos definidos aún.

Vamos paso por paso:

./src/layouts/Layout.astro

---
import '../styles/global.css';
import Footer from '../components/Footer.astro';
import Header from '../components/Header.astro';
+ import { getTheme } from './theme.api';

+ const theme = await getTheme();

Siguiente paso, vamos a crear las variables CSS que usaremos en el HTML:

const themeVariables = `
  --primary-color: ${theme.color};
  --font-name-body: ${theme.fontBody.name};
  --font-name-title: ${theme.fontTitle.name};
`;

De momento las tenemos como un string, después las aplicaremos al HTML.

Y ahora vamos a definir las URLs de las fuentes. Si el tema no tiene una URL definida, usaremos una fuente por defecto de Google Fonts:

const fontTitleLink = theme.fontTitle.url
  ? theme.fontTitle.url
  : 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap';

const fontBodyLink = theme.fontBody.url
  ? theme.fontBody.url
  : 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap';
---

3. Pasar las variables al HTML

Ahora modificamos el para aplicar las variables CSS directamente desde el atributo style. Esto nos permite sobreescribir los valores definidos por defecto en global.css.

<!doctype html>
- <html lang="en">
+ <html lang="en" style={themeVariables}>
  <head>

Y oye se ha aplicado el cambio con el color primario.

Pero las fuentes no, nos falta un pasito más ya que en el CSS tenemos otro nombre de variable:

En las fuentes hemos definido un paso intermedio, en el global.css, haríamos:

./styles/global.css

:root {
  --primary-color: #1d3353;
  --pure-white: #fff;
+  --font-name-body: 'IBM Plex Sans';
+  --font-name-title: 'IBM Plex Sans Condensed';

  /*text colors*/
  --text-color: #333;
  --text-color-light: var(--pure-white);

  /*hover colors*/
  --title-hover-color: hsl(from var(--primary-color) h calc(s + 20) calc(l + 10));
  --menu-hover-color: hsl(from var(--primary-color) h calc(s + 20) calc(l + 63));

  /*border colors*/
  --border-color: #333;

  /*font family*/
-  --ff-title: 'IBM Plex Sans Condensed', sans-serif;
-  --ff-body: 'IBM Plex Sans', sans-serif;
+  --ff-title: var(--font-name-title), sans-serif;
+  --ff-body: var(--font-name-body), sans-serif;

4. Incluir las fuentes dinámicamente

También añadimos las URLs de las fuentes en el , para que se carguen según la configuración del tema:

<!doctype html>
<html lang="en" style={themeVariables}>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="generator" content={Astro.generator} />
    <title>Astro Basics</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+    <link href={fontTitleLink} rel="stylesheet" />
+    <link href={fontBodyLink} rel="stylesheet" />

5. Sobrescribiendo estilos globales

Ya hemos visto que funciona, pero igual estás pensando ¿Y como funciona esta magia?

Si abrimos global.css, veremos que ya usamos variables como --primary-color, --font-name-body y --font-name-title.

styles/global.css

:root {
  /*theme variables*/
  --primary-color: #1d3353;
  --font-name-body: 'IBM Plex Sans';
  --font-name-title: 'IBM Plex Sans Condensed';

  /*font family*/
  --ff-title: var(--font-name-title), sans-serif;
  --ff-body: var(--font-name-body), sans-serif;

  /*color palette*/
  --pure-white: #fff;
  --grey-700: #333;
  --primary-light-color: hsl(from var(--primary-color) h calc(s + 20) calc(l + 10));

  /*text colors*/
  --text-color: var(--grey-700);
  --text-color-light: var(--pure-white);

  /*background colors*/
  --background-footer-color: var(--grey-700);

  /*hover colors*/
  --title-hover-color: hsl(from var(--primary-color) h calc(s + 20) calc(l + 10));
  --menu-hover-color: hsl(from var(--primary-color) h calc(s + 20) calc(l + 63));

  /*border colors*/
  --border-color: var(--grey-700);

Al pasar nuevas variables en la etiqueta , las estamos sobrescribiendo sin modificar directamente el CSS.

6. Resultado

Ahora podemos ver cómo se aplican los cambios de tema en tiempo real.

Combinación 1

#771228 QuickSand Montserrat

Combinación 2 #205D0A Orbitron Inter

Combinación 3 #73205E DM Serif Text Manrope

Y podemos tener Content Island a un lado, cambiar el color primario o las fuentes, y ver cómo se actualiza el sitio al instante.

⚠️ Nota: Esto funciona en tiempo real porque estamos en modo desarrollo. En producción, al ser un sitio generado estáticamente (SSG), necesitaríamos lanzar un nuevo build para aplicar los cambios, esto lo podemos automatizar con un webhook que dispare un nuevo build al actualizar el tema en Content Island.

Cómo hemos visto, con muy poco trabajo, hemos podido integrar un sistema de temas dinámicos en nuestro sitio web, permitiendonos personalizar la imagen corporativa directamente desde Content Island 🏝️, y es más este tema lo podríamos usar en otro tipo de aplicaciones.