Files
agenticSystem/docs/08-layout-and-libraries.md
Jordan Diaz 6881d64a08 ajustes
2026-04-25 10:27:51 +00:00

7.8 KiB

Layout Global y Librerías Globales

Este documento explica cómo gestionar los 4 campos globales del proyecto (style CSS global, javascript JS global, header Twig del header del sitio, footer Twig del footer) y las librerías globales (CSS/JS/fonts inyectadas en <head> o antes de </body>). Cubre la regla crítica de NO editar nunca cms/lib/plugins/builder_saas/layout.json ni los .tpl de custom-header-twig / custom-footer-twig directamente, las tools get_layout_field / set_layout_field (única vía válida para editar header/footer/style/javascript) y las tools list_global_libraries / add_global_library / remove_global_library / set_global_libraries para gestionar las URLs de librerías. Léelo antes de tocar cualquier cosa relacionada con header, footer, CSS global o librerías externas (jQuery, Vue CDN, Google Fonts, etc.).

Layout global

Los 4 campos globales del proyecto viven en cms/lib/plugins/builder_saas/layout.json:

Campo Contenido
style CSS global del proyecto (se inyecta en todas las páginas)
javascript JS global del proyecto (se inyecta en todas las páginas)
header Twig del header del sitio (se renderiza arriba de cada página)
footer Twig del footer del sitio (se renderiza al final de cada página)

Los campos header y footer son Twig — se beneficias de filtros (| get, | translate, etc.) y atributos (c-if, c-for).

REGLA CRÍTICA — Nunca edites estos archivos directamente

Está prohibido usar acai-view, acai-line-replace, acai-write ni acai-delete sobre:

  • cms/lib/plugins/builder_saas/layout.json
  • template/estandar/modulos/custom-header-twig/*
  • template/estandar/modulos/custom-footer-twig/*
  • template/estandar/modulos/custom-header/*
  • template/estandar/modulos/custom-footer/*

Estos ficheros son artefactos generados a partir de layout.json. Editarlos directamente provoca:

  • Desincronización con layout.json.{header,footer}ModuleCustom.htmlParsed.
  • Sobrescritura de tus cambios cuando el usuario abre el builder visual y guarda.
  • Comportamiento inconsistente entre el render público y el builder.

El backend protege estas rutas — las tools de archivo devolverán error si intentas tocarlas.

Workflow correcto

Leer

get_layout_field({ field: "header" })       // Twig source del header
get_layout_field({ field: "footer" })       // Twig source del footer
get_layout_field({ field: "style" })         // CSS global
get_layout_field({ field: "javascript" })    // JS global

Escribir

set_layout_field({
  field: "footer",
  content: "<footer class='bg-gray-900 text-white py-10'>…nuevo HTML/Twig…</footer>"
})

set_layout_field ejecuta una pipeline atómica:

  1. Escribe el source en layout.json.{field}.
  2. Sincroniza layout.json.{field}ModuleCustom.htmlParsed.
  3. Regenera los .tpl de custom-{field}-twig/.
  4. Compila el Twig a PHP.

Es destructivo — sobrescribe el contenido completo. Pair con get_layout_field primero para leer el actual y modificarlo, no escribirlo desde cero.

Ejemplos de uso

// 1. Leer
get_layout_field({ field: "footer" })
// devuelve: <footer><p>© 2024 Mi Sitio</p>…</footer>

// 2. Modificar localmente y reescribir entero
set_layout_field({
  field: "footer",
  content: "<footer><p>© 2025 Mi Sitio. Todos los derechos reservados.</p>…</footer>"
})

Añadir un menú al header

// 1. Leer source actual
get_layout_field({ field: "header" })

// 2. Escribir nueva versión con el menú añadido
set_layout_field({
  field: "header",
  content: "<header>…<nav>{% for item in 'apartados' | get('parentNum=0 AND visible_en_el_menu=1', 'globalOrder ASC') %}<a href='{{ item.enlace }}'>{{ item.name }}</a>{% endfor %}</nav>…</header>"
})

Añadir CSS global

// 1. Leer
get_layout_field({ field: "style" })

// 2. Reescribir con la regla añadida
set_layout_field({
  field: "style",
  content: ":root { --main-color: #2563eb; }\n.btn-primary { … }\n…"
})

Librerías globales

layout.json["libraries"] define una lista de URLs (CSS, JS, fonts) que el CMS inyecta en cada página. Hay dos secciones:

Sección Posición Uso típico
top Dentro de <head> CSS, fonts (Google Fonts), JS crítico (preload)
bottom Antes de </body> La mayoría de JS (jQuery, Vue, sliders, etc.)

Tools

Listar — list_global_libraries

list_global_libraries()

Devuelve:

{
  "top": [
    { "num": 1, "url": "https://fonts.googleapis.com/css2?family=Inter" },
    { "num": 2, "url": "/css/extras.css" }
  ],
  "bottom": [
    { "num": 1, "url": "https://unpkg.com/vue@3/dist/vue.global.prod.js" },
    { "num": 2, "url": "/js/main.js" }
  ],
  "layoutExists": true
}

Llama a esta tool antes de añadir/quitar para no duplicar entradas.

Añadir — add_global_library

Idempotente: si la URL ya existe en esa sección, devuelve added: false.

add_global_library({
  section: "bottom",
  url: "https://unpkg.com/vue@3/dist/vue.global.prod.js"
})

add_global_library({
  section: "top",
  url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap"
})

// Rutas relativas al proyecto también valen
add_global_library({
  section: "bottom",
  url: "/js/custom.js"
})

Eliminar — remove_global_library

Idempotente: si la URL no existe, devuelve removed: false.

remove_global_library({
  section: "bottom",
  url: "https://unpkg.com/vue@3/dist/vue.global.prod.js"
})

Reemplazar entera — set_global_libraries

Destructivo — sobrescribe la lista completa de la sección. Úsalo solo para reordenar masivamente o reemplazar el conjunto. Para cambios incrementales prefiere add_global_library / remove_global_library.

set_global_libraries({
  section: "bottom",
  libraries: [
    { url: "/js/jquery.min.js" },
    { url: "/js/main.js" },
    { url: "https://unpkg.com/vue@3/dist/vue.global.prod.js" }
  ]
})

Convenciones

  • Para librerías populares, prefiere CDN oficial (unpkg.com, cdn.jsdelivr.net, cdnjs.cloudflare.com).
  • Para assets propios del proyecto, usa rutas relativas (/js/main.js, /css/extras.css).
  • Si añades una librería que ya tiene equivalente cargada (ej. dos versiones de jQuery), elimina la antigua antes de añadir la nueva.
  • El orden importa: las dependencias deben ir antes que sus consumidores. set_global_libraries permite reordenar.

Decisión: ¿layout global o módulo?

Caso Solución
Header/footer del sitio Layout global (set_layout_field con header/footer)
CSS aplicado a todo el sitio Layout global (set_layout_field con style) o librería global
JS aplicado a todo el sitio Layout global (set_layout_field con javascript) o librería global
Componente reutilizable en páginas Módulo en template/estandar/modulos/
Detalle de un registro Sección general custom-{tableName}
Bloque visual específico Módulo

Reglas críticas

  1. NUNCA edites directamente layout.json, custom-header-twig/*, custom-footer-twig/*, custom-header/*, custom-footer/*. Las tools de archivo te devolverán error si lo intentas.
  2. Para header/footer/style/javascript globales, única vía: get_layout_field + set_layout_field.
  3. set_layout_field es destructivo — siempre lee primero, modifica, escribe.
  4. Para librerías globales: list_global_librariesadd_global_library / remove_global_library. set_global_libraries solo para reordenar/reemplazar masivamente.
  5. Inyección automática: top va en <head>, bottom antes de </body>. Decide según el tipo de asset.
  6. El orden de las librerías importa para dependencias.