Ahora con creación de páginas por IA vía el servidor MCP

Layouts

Cabecera y pie son bloques de layout: se heredan por el árbol de páginas y se editan como cualquier otro bloque.

Una cabecera no es un componente que escribes a mano en app/layout.tsx. En cmssy es un bloque de layout: lo mismo que un hero o una tabla de precios, guardado en el CMS, editado en el constructor de páginas y renderizado por un componente de tu registro.

Es una decisión de diseño con una consecuencia. Si la cabecera fuera marcado, un editor no podría cambiar un enlace de navegación sin desplegar. Como es un bloque, puede.

Posiciones y herencia

Los bloques de layout viven en posiciones con nombre: header y footer. Una página o bien posee su layout o lo hereda de su padre, así que fijar la cabecera una vez en la página raíz se la da a todo el árbol.

Sobrescríbela solo donde una sección difiera de verdad: una landing sin navegación, un checkout con pie reducido. Todo lo demás hereda, lo que significa que una edición actualiza todas las páginas que no se salieron.

Dos layouts raíz, no uno

La ruta pública y la ruta de edición tienen cada una su propio layout raíz. Obtienen los mismos grupos de layout y los renderizan con componentes distintos: una cabecera renderizada en servidor no se puede editar, y una montada en cliente no se puede servir estática.

Los grupos los obtienes tú: una consulta de entrega que devuelve los bloques de layout de una página:

// services/layout.ts
export async function fetchChromeLayouts(
  pageSlug: string,
  previewSecret?: string,
): Promise<CmssyLayoutGroup[]> { /* consulta PublicPageLayouts */ }

El layout público

CmssyServerLayout de @cmssy/react renderiza los grupos en servidor. Necesita el registro de bloques, porque resuelve los tipos en el servidor:

// app/[[...path]]/layout.tsx
import { CmssyServerLayout } from "@cmssy/react";

const { isEnabled: draft } = await draftMode();
const [locales, groups] = await Promise.all([
  resolveSiteLocales(),
  fetchChromeLayouts("/", draft ? cmssy.draftSecret : undefined),
]);

const slot = (position: "header" | "footer") => (
  <CmssyServerLayout
    groups={groups}
    blocks={blocks}
    position={position}
    locale={locale}
    defaultLocale={locales.defaultLocale}
    enabledLocales={locales.locales}
  />
);

El secreto de borrador se pasa solo cuando el modo borrador está activo. Pásalo sin condición y tu sitio público empezará a servir cambios de cabecera sin publicar.

El layout de edición

La ruta de edición renderiza los mismos grupos a través de tu envoltorio cliente:

// app/cmssy-edit/[[...path]]/layout.tsx
const slot = (position: "header" | "footer") => (
  <EditableLayout
    groups={groups}
    position={position}
    locale={locale}
    defaultLocale={locales.defaultLocale}
    enabledLocales={locales.locales}
    edit={{ editorOrigin }}
  />
);

Fíjate en lo que falta: no hay prop blocks. El registro lo carga de forma perezosa en el cliente el propio envoltorio:

// cmssy/editable-layout.tsx
"use client";
import { CmssyLazyLayout, type CmssyLazyLayoutProps } from "@cmssy/react/client";

export function EditableLayout(props: Omit<CmssyLazyLayoutProps, "load">) {
  return <CmssyLazyLayout {...props} load={() => import("./blocks")} />;
}

La carga perezosa aquí no es una optimización, es una frontera. Los módulos de bloque pueden contener loaders de servidor que leen configuración y dependencias solo de servidor; importar el registro de forma ansiosa desde un componente cliente arrastraría todo eso al bundle del navegador.

Ambos layouts raíz deben fijar <html lang> desde el locale resuelto, incluido el de edición, porque la vista previa debe declarar el idioma que realmente está renderizando.

Por qué esta es la parte que se rompe en silencio

Omite editable y todo sigue pareciendo correcto. El sitio compila, los visitantes ven la cabecera correcta, tus pruebas pasan.

Pero en el editor la cabecera es ahora marcado renderizado en servidor. Se puede seleccionar y no tiene campos: el editor la resalta y no cambia nada. Sin error, sin aviso, sin build en rojo.

Esto es exactamente lo que comprueba checkCmssyEditMode, y por eso su condición de éxito se lee al revés: la ausencia de <header> en el HTML de servidor de una petición en modo edición es el estado correcto. Consulta pruebas.

Siguientes pasos