Personnaliser l'apparence

Changer la couleur de marque, les gris, les arrondis, la barre et la coquille de l'admin depuis un seul fichier, theme.js.

Un projet LRVO part en noir et blanc. Ce guide montre comment lui donner sa propre apparence, de la couleur d'un bouton jusqu'à la disposition de l'admin, en modifiant un seul fichier. Tout suit en même temps : l'admin, les pages publiques, les modules, les courriels et les PDF.

Le fichier theme.js

npx @lrvo/start génère theme.js à la racine du projet, avec les valeurs par défaut. instrumentation.js le passe à initializeLrvo, et <ThemeStyle /> l'applique dans le <head> du layout racine.

// theme.js
import { defineTheme } from '@lrvo/core/themes/define';

export default defineTheme({
  primary: '#2563eb',
  neutral: 'stone',
  radius: 'md',
  chrome: 'dark',
  shell: 'topbar',
  modes: ['light', 'dark'],
});

Redémarrer le serveur de développement après une modification : le thème est lu au boot, comme les modules.

Chaque option est un choix borné. Une valeur hors liste fait échouer le démarrage avec un message qui nomme les valeurs admises. C'est voulu : un thème libre permettrait de tout faire, y compris un admin illisible. Le détail des options est dans Thèmes.

Choisir une couleur de marque

primary prend une seule couleur hex. Le core en déduit le reste :

  • le survol du bouton principal ;
  • une version plus claire pour le mode sombre, où une marque foncée se perdrait sur le noir ;
  • le texte posé dessus, blanc ou noir, selon ce qui se lit le mieux ;
  • l'accent des liens et des cases cochées, assombri s'il le faut pour rester lisible sur fond blanc.

La couleur de marque va là où l'utilisateur agit : bouton principal, élément sélectionné, barre de progression, avatar. Le texte, les titres et les filets restent à l'encre. Une interface où tout prend la couleur de marque ne montre plus où cliquer.

Changer la disposition de l'admin

Deux options touchent à la structure, pas seulement aux couleurs.

chrome: 'dark' garde la barre du haut et la sidebar foncées, quel que soit le mode. Le contenu garde ses surfaces claires. Prévoir LRVO_LOGO_URL_DARK si le logo est foncé : c'est lui qui s'affiche sur une barre foncée.

shell: 'topbar' retire la sidebar et met la navigation dans la barre du haut. Elle convient à une application aux sections peu nombreuses, un portail client par exemple. Sur mobile, le bouton de menu ouvre le même tiroir que la coquille sidebar.

Un module peut poser un élément dans cette barre, une cloche de notifications par exemple, avec registerTopbarItem.

Exemple : un portail client

Un portail pour les clients d'une firme d'ingénierie : barre foncée, navigation en haut, bleu d'action, gris chauds, fond de page légèrement crème, uniquement en clair.

// theme.js
import { defineTheme } from '@lrvo/core/themes/define';

export default defineTheme({
  primary: '#1d6fd8',
  neutral: 'stone',
  chrome: 'dark',
  shell: 'topbar',
  modes: ['light'],
  overrides: {
    light: { canvas: '#f3f2ef' },
  },
});

modes: ['light'] impose le clair et masque toutes les bascules, dans l'admin comme sur les pages publiques. overrides fixe la valeur exacte d'un jeton quand le calcul par défaut ne convient pas. Les clés sont limitées aux jetons connus, listés dans Thèmes.

Les cartes de projet, les décisions en attente et le fil d'activité d'un tel portail ne relèvent pas du thème. Ce sont des widgets de tableau de bord, fournis par un module du projet. Voir Étendre l'admin.

Écrire un composant qui suit le thème

Un composant du projet, un bloc ou un gabarit public, écrit des jetons, jamais une nuance de palette :

// ✓ suit la marque, le clair et le sombre
<div className="rounded-card border border-line bg-surface p-5">
  <h2 className="text-fg font-semibold">Projets</h2>
  <p className="text-fg-muted text-sm">3 en cours</p>
  <a className="text-accent" href="/projets">Voir tout</a>
</div>

// ✗ reste noir et blanc, et oublie le sombre dès qu'une variante manque
<div className="rounded-xl border border-neutral-200 bg-white dark:bg-neutral-900">

Pour une valeur qui n'est pas une classe, un style inline ou un SVG, lire la variable CSS du jeton : var(--lrvo-fg-subtle). La liste des jetons et de leur rôle est dans le design system.

Courriels et PDF

Rien à faire côté projet. Les courriels écrivent les mêmes jetons, que BaseLayout résout en hex dans les valeurs du mode clair. Un PDF lit getThemeValues('light') au rendu. Voir Courriel.

Dernier recours : le CSS

Le thème couvre les couleurs, les gris, les arrondis, les polices et la disposition. Pour un besoin qu'il ne couvre pas, le globals.css du projet reste disponible, après l'import de @lrvo/core/styles/core.css.

Pour changer la valeur d'un jeton, passer par overrides plutôt que par le CSS. Les valeurs du thème sont injectées dans le <head>, et une redéfinition de --lrvo-* dans une feuille du projet n'est pas assurée de passer devant. Surtout, overrides est validé au démarrage, ce qu'aucune règle CSS ne sera.

Notes

Un projet créé avant le thème injecte encore THEME_INIT_SCRIPT et n'a pas de theme.js. lrvo-doctor le signale, et npx lrvo-doctor --fix fait la migration : il crée theme.js avec les valeurs par défaut, et corrige sur place instrumentation.js et app/layout.js sans toucher au reste de ces fichiers. Quand un de ces fichiers a été trop remanié pour être reconnu, le doctor n'y touche pas et liste les lignes à ajouter.

Les blocs, gabarits et pages publiques du projet gardent leurs anciennes classes. Ils s'affichent comme avant, mais ne suivent le thème qu'une fois réécrits avec les jetons. La déclaration @custom-variant dark et les variables --lrvo-bg / --lrvo-text d'un ancien globals.css peuvent rester : le core déclare désormais le variant lui même, et les jetons ne dépendent pas de ces variables.

Sur cette page