Definir la navegación con navigation.json
Ordena páginas, colecciones, enlaces externos y managers en el panel de navegación del editor.
9 min de lectura
Estado del contrato
navigation.json es el contrato vigente para ordenar la navegación que ve el editor, pero todavía es una superficie incompleta de CMS 1.0. Actualmente el JSON solo expresa jerarquía, ids y tipos; labels, rutas y entradas se resuelven desde definiciones code-first.
Crear navigation.json
Las claves son ids estables. El orden del objeto es el orden editorial. Un valor string referencia un tipo conocido; un objeto crea un grupo anidado.
{
"home": "page",
"platform": {
"crm": "external",
"finance": "external"
},
"solutions": "collection",
"blog": "manager"
}Los ids aceptan minúsculas, números y guiones. Los tipos actuales son:
| Tipo | Uso actual |
|---|---|
page | Página declarada con cms.page() y una entrada navigation. |
collection | Índice más entradas dinámicas resueltas por una función server-side. |
external | Destino que no corresponde a un documento del proyecto. |
manager | Superficie editorial nativa. En la versión actual solo blog está reconocido. |
Definir cada referencia
Co-localiza la metadata con su dueño. Una página declara su navegación en cms.page():
export const HomeCmsPage = cms.page({
key: 'website:home',
path: '/',
navigation: {
id: 'home',
label: { es: 'Inicio', en: 'Home' },
},
sections: <HomeHeroCms instanceId="hero" />,
});Un enlace externo debe vivir junto a la configuración que define su destino:
cms.external({
id: 'crm',
label: 'CRM',
href: cmsGlobal('links', 'crm'),
});Una colección de navegación resuelve su índice y entradas desde la colección real:
cms.navigationCollection({
id: 'solutions',
label: { es: 'Soluciones', en: 'Solutions' },
indexPath: '/solutions',
async entries(locale) {
return (await solutions.entries(locale)).map((entry) => ({
id: entry.id,
label: entry.title,
path: solutions.path(entry.slug),
}));
},
});No crees una definición falsa para el grupo platform: en el contrato actual, un objeto del JSON ya representa el grupo. La falta de un label localizado propio para grupos es una limitación conocida, no una razón para registrar el grupo como external.
Conectar el árbol al sitio
Importa el JSON en el módulo server-only del sitio y pásalo a createCmsSite:
import type { CmsNavigationTree } from '@veetcuna/cms-next';
import navigation from './navigation.json';
cmsSite = createCmsSite({
projectSlug: '@tenant/website',
generated: cmsGenerated,
navigation: navigation as CmsNavigationTree,
// site, locales, globals y editor…
});El generador descubre módulos que exportan cms.page(), cms.collection(), cms.external() o cms.navigationCollection(). Al abrir un preview de una página, el SDK resuelve el árbol con el locale y los globales publicados, y lo entrega al panel de navegación del editor.
Limitaciones actuales
- Los grupos no declaran todavía label localizado, href o metadata en el propio JSON.
managersolo reconoceblog.- La estructura describe navegación editorial del CMS; no genera automáticamente el header público del website.
- Cada id debe existir con el mismo tipo en sus definiciones runtime, salvo grupos y managers nativos.
- Cambiar un id rompe la asociación; para reordenar, mueve la propiedad sin renombrarla.
Cuando evolucione el contrato, migra navigation.json de forma explícita y conserva compatibilidad con los documentos publicados durante el rollout.