Templates

Écrire un template de page, les propriétés qu'il reçoit et les deux façons de l'enregistrer.

Le module ne fournit aucune mise en page. Il résout le template déclaré sur la page et lui délègue le rendu. Les templates appartiennent donc au projet, pas au module, ce qui permet de garder son branding sans forker quoi que ce soit.

Le registre de templates vit dans le core, dans core/templates, et il est partagé par tous les modules de contenu. Les templates de pages sont ceux de kind: 'page'.

Écrire un template

Déposer un fichier dans components/lrvo/templates/ du projet hôte :

// components/lrvo/templates/landing.js
import Content from './content.js';

export const meta = {
  id: 'landing',
  label: 'Landing page',
  kind: 'page',
};

export default function LandingTemplate({ page, blocks, url, breadcrumb }) {
  return (
    <main>
      <h1>{page.title}</h1>
      <Content blocks={blocks} />
    </main>
  );
}

npx lrvo-modules sync scanne ce dossier et génère les manifestes app/.lrvo/templates.server.js et app/.lrvo/templates.client.js, qui enregistrent les templates au boot. Le formulaire d'édition liste alors automatiquement tous les templates de kind: 'page' dans son sélecteur.

Le champ kind est ce qui sépare les templates de pages de ceux de posts. Un template de kind: 'post' n'apparaîtra jamais dans le sélecteur d'une page.

Propriétés reçues

PropriétéTypeContenu
pageobjetLa ligne complète : id, parent_id, slug, title, template, blocks, seo, visibility, created_at, updated_at.
blockstableauLes blocs de la page, déjà enrichis de leurs métadonnées médias.
urlchaîneChemin canonique de la page, segments joints par /.
breadcrumbtableau{ id, slug, title, url } de la racine à la page courante incluse.

blocks est passé séparément de page.blocks par commodité : c'est la même donnée. Aucun children n'est injecté, le template décide seul de sa structure.

Rendre les blocs

Deux options :

  • Le composant Content du projet, dans components/lrvo/templates/content.js, qui applique la typographie du site.
  • BlockListRenderer du core, en repli neutre.
import BlockListRenderer from '@lrvo/core/blocks-registry/render';

<BlockListRenderer blocks={blocks} />

Voir Blocs personnalisés pour ajouter ses propres types de blocs.

Fil d'Ariane

breadcrumb a exactement la même forme côté pages et côté posts. Un même composant de fil d'Ariane sert donc aux deux :

export default function PageTemplate({ page, blocks, breadcrumb }) {
  return (
    <main>
      <nav>
        {breadcrumb.map((crumb) => (
          <a key={crumb.id} href={crumb.url}>{crumb.title}</a>
        ))}
      </nav>
      <h1>{page.title}</h1>
    </main>
  );
}

Le dernier élément de breadcrumb est la page courante, pas son parent.

Enregistrement impératif

Quand le template dépend d'une condition connue seulement à l'exécution, l'API impérative reste disponible côté client :

import { registerPageTemplate } from '@lrvo/module-pages/client';

registerPageTemplate({
  id: 'landing',
  label: 'Landing page',
  Component: LandingTemplate,
});

C'est un alias de registerTemplate du core avec kind: 'page' déjà positionné. La voie déclarative par fichier reste préférable : elle est visible au sync, donc au build.

Résolution

Au rendu, le module cherche le template dont l'identifiant vaut page.template. S'il ne le trouve pas, il retombe sur l'identifiant default. Si default n'existe pas non plus, il rend les blocs bruts avec BlockListRenderer, sans mise en page.

Un template supprimé du projet ne casse donc pas les pages qui l'utilisaient : elles retombent sur default jusqu'à ce que leur champ soit changé.

L'éditeur, lui, ne se comporte pas pareil. Face à un template inconnu, son sélecteur se réaligne sur le premier template de la liste, et l'enregistrement suivant écrit cette valeur en base. Renommer l'identifiant d'un template déjà utilisé demande donc de repasser sur les pages concernées, sous peine de les voir migrer une à une vers un template arbitraire. Voir Administration.

Notes

  • Le registre vit sur globalThis via Symbol.for. Il est partagé entre serveur et client et survit au rechargement à chaud.
  • Le template default n'est pas fourni par le module. Il vient du projet hôte, et le start template en installe un.
  • meta.label est ce que voit l'éditeur dans le sélecteur. Le garder lisible et distinct.

Sur cette page