Design system : tokens, thèmes et accent¶
Référence du design system (DS) de Kirexo : où vivent les fichiers, comment le thème clair/sombre et l'accent d'instance sont pilotés, quelles variables CSS sont disponibles, et quelles contraintes d'accessibilité sont garanties. Pour le raisonnement derrière l'accent rendu côté serveur, voir l'explication Pourquoi un accent d'instance piloté serveur.
Fichiers du DS et emplacements¶
Le DS a une source de vérité versionnée dans design-system/, et des copies de travail effectivement servies par l'application. La source de vérité ne doit pas être réécrite : les copies en sont issues.
| Rôle | Source de vérité (versionnée) | Copie de travail (servie) |
|---|---|---|
| Feuille de tokens et composants | design-system/kirexo-ds.css |
assets/styles/kirexo-ds.css |
| Feuille des écrans | design-system/screens.css |
assets/styles/screens.css |
| Script d'accent + logomark | design-system/accent.js |
assets/js/accent.js (copie adaptée, voir plus bas) |
| Script de thème clair/sombre | — | assets/js/theme.js |
| Favicon et manifest | design-system/favicon/ |
public/favicon/ |
Le dossier public/favicon/ contient : favicon.ico, favicon-16.png, favicon-32.png, favicon-48.png, favicon-180.png, favicon-192.png, favicon-512.png, favicon-mono-512.png, safari-pinned-tab.svg, site.webmanifest.
accent.js est une copie adaptée
Contrairement aux CSS et au favicon copiés tels quels, assets/js/accent.js est dégraissé de la persistance et de la ré-application de l'accent depuis localStorage présentes dans la source. La raison est expliquée dans Pourquoi un accent d'instance piloté serveur.
Thème clair/sombre — data-theme¶
Le thème est porté par l'attribut data-theme sur <html>, avec deux valeurs admises :
| Valeur | Effet |
|---|---|
light |
Palette claire (valeur par défaut, équivalente à :root dans assets/styles/kirexo-ds.css) |
dark |
Palette sombre |
Le rendu serveur pose data-theme="light" par défaut. Le script assets/js/theme.js ajuste ensuite la valeur côté client :
- il lit la clé
localStoragekirexo-theme(préférence locale du visiteur) ; - en l'absence de préférence enregistrée, il suit
prefers-color-scheme; - il bascule l'attribut
data-themesur<html>en conséquence.
Le thème est donc une préférence par visiteur, persistée dans le navigateur.
Accent d'instance — data-accent¶
L'accent est porté par l'attribut data-accent sur <html> et rendu côté serveur. Les six valeurs admises correspondent aux cases de l'enum App\Entity\Enum\AccentColor (src/Entity/Enum/AccentColor.php) :
Valeur (data-accent) |
Libellé FR (AccentColor::label()) |
|---|---|
encre |
Encre (valeur par défaut) |
bordeaux |
Bordeaux |
foret |
Forêt |
prune |
Prune |
rouille |
Rouille |
graphite |
Graphite |
Contrairement au thème, l'accent n'est pas une préférence par visiteur : c'est un réglage d'instance, partagé par tous. Voir Pourquoi un accent d'instance piloté serveur.
Fonction Twig platform_accent()¶
La valeur de data-accent est injectée par la fonction Twig platform_accent(), utilisée dans templates/base.html.twig :
La fonction est exposée par src/Twig/PlatformAccentExtension.php et déléguée à src/Twig/Runtime/PlatformAccentRuntime.php. Le runtime lit le réglage via SettingRepositoryInterface (src/Repository/SettingRepositoryInterface.php) : il retourne la valeur de l'accent du singleton Setting, ou la valeur par défaut (encre) si le singleton n'a pas encore été initialisé.
Entité Setting et enum AccentColor¶
L'accent est persisté par l'entité singleton App\Entity\Setting (src/Entity/Setting.php) — une seule ligne en base, dans la table setting. Elle porte une propriété accent typée par l'enum AccentColor, stockée via le mapping Doctrine enumType.
L'enum App\Entity\Enum\AccentColor (src/Entity/Enum/AccentColor.php) est un backed enum string exposant deux méthodes :
| Méthode | Rôle |
|---|---|
label(): string |
Libellé FR affichable (Encre, Bordeaux, Forêt, Prune, Rouille, Graphite) |
default(): self (statique) |
Valeur par défaut centralisée — AccentColor::Encre |
L'accès au singleton se fait par SettingRepositoryInterface :
getSingleton(): ?Setting— lecture (peut êtrenullavant initialisation) ; utilisé par le runtime Twig ;getOrCreate(): Setting— lecture-ou-création, jamaisnull; réservé aux mutations (page Réglages à venir) ;save(Setting $setting, bool $flush = true): void— persistance.
Variables CSS principales¶
Les couleurs et la typographie passent exclusivement par des variables CSS définies dans assets/styles/kirexo-ds.css. Aucune valeur hexadécimale en dur dans un template ou une CSS applicative.
| Variable | Rôle |
|---|---|
var(--ink) |
Couleur de texte principale |
var(--ink-2), var(--ink-3) |
Texte secondaire et tertiaire |
var(--surface) |
Surface principale |
var(--surface-2), var(--surface-3) |
Surfaces secondaires |
var(--paper) |
Fond de page |
var(--line), var(--line-2) |
Bordures et séparateurs |
var(--accent) |
Couleur d'accent (dérivée de data-accent) |
var(--accent-hover) |
Accent au survol |
var(--accent-ink) |
Texte sur fond d'accent |
var(--accent-soft), var(--accent-line) |
Accent atténué et bordure d'accent |
var(--font-serif) |
Typo des corps d'article (Newsreader) |
var(--font-sans) |
Typo de l'interface (Public Sans) |
Chaque variable est redéfinie pour [data-theme="dark"] : changer data-theme suffit à basculer toute la palette.
Classes d'écran — Édition d'article¶
L'écran d'édition d'article (espace utilisateur) habille son markup via des classes définies dans la feuille des écrans design-system/screens.css (source) et sa copie servie assets/styles/screens.css. Toutes s'appuient exclusivement sur les variables CSS du DS — aucun hex en dur, donc thème clair/sombre et les six accents sont gérés automatiquement par les tokens.
| Classe | Rôle |
|---|---|
.article-edit |
Wrapper de la page de l'éditeur (colonne centrée, espacements verticaux). |
.article-editor |
Hôte de l'éditeur Milkdown : corps d'article rendu en var(--font-serif), sur var(--surface) bordé et ombré. |
.article-toolbar |
Barre de formatage au-dessus de l'éditeur. Les boutons sont ciblés par le sélecteur descendant .article-toolbar button (cibles ≥ 44px, anneau :focus-visible préservé) ; l'état actif est porté par .article-toolbar button[aria-pressed="true"] (fond var(--accent), texte var(--accent-ink)). |
.article-status |
Zone d'état de l'enregistrement automatique (autosave), annoncée en aria-live. Hauteur minimale fixe pour éviter le décalage de mise en page. |
.article-actions |
Conteneur des formulaires du cycle de vie de l'article (publier, republier, corbeille…). |
.article-unpublish |
Formulaire de dépublication inline. Le couple label/champ URL est habillé en .field / .input pour la parité visuelle avec le form theme du DS (le champ est du HTML écrit à la main, les classes y sont posées explicitement). |
Le hook JS .js-article-editor (attaché via data-controller) n'est pas une cible de style : aucune règle CSS ne lui est attachée.
Classes d'écran — Back-office (réglages, articles, analyse IA)¶
Les écrans d'administration (réglages, liste et détail d'articles, panneau d'analyse IA) sont habillés par des classes préfixées bo- définies dans la feuille des écrans design-system/screens.css (source) et sa copie servie assets/styles/screens.css. Comme partout dans le DS, elles s'appuient exclusivement sur les variables CSS : thème clair/sombre et les six accents sont gérés automatiquement par les tokens.
Familles de classes¶
| Famille | Écran | Rôle |
|---|---|---|
.bo-settings__api, .bo-field |
Réglages (templates/admin/settings.html.twig) |
Section « Clé API Claude » sous l'accent (.bo-settings__api) et wrapper label/champ d'un formulaire (.bo-field). L'<input> lui-même est habillé en .input par le form theme du DS, pas par .bo-field. |
.bo-articles-index* |
Liste d'articles (templates/admin/article/index.html.twig) |
En-tête (__head), sous-titre (__lead) et état vide (__empty) de la liste. La table réutilise .bo-table / .bo-articles. |
.bo-article-show* |
Détail d'article (templates/admin/article/show.html.twig) |
Conteneur de lecture et ses parties : en-tête (__head), méta auteur/date (__meta), corps publié en var(--font-serif) (__body), section d'analyse (__analysis), note clé API absente (__hint). |
.bo-analysis* |
Panneau analyse IA (templates/admin/article/_analysis.html.twig) |
Form déclencheur (__form), rapport en carte (__report), avertissement non juridique (__disclaimer), résumé (__summary), chips de thèmes (__themes), grille de conformité (__grid), horodatage (__date). |
Badges de risque .bo-risk--*¶
Le panneau d'analyse IA affiche un niveau de risque sous forme de badge. Le modificateur reprend la valeur de l'enum App\Entity\Enum\RiskLevel (src/Entity/Enum/RiskLevel.php) — d'où l'underscore de a_verifier. Chaque niveau mappe vers un couple de tokens sémantiques :
| Classe | Niveau (RiskLevel) |
background |
color |
|---|---|---|---|
.bo-risk |
— (badge de base) | — | — |
.bo-risk--aucun |
None (aucun) |
var(--surface-2) |
var(--ink-2) |
.bo-risk--faible |
Low (faible) |
var(--ok-soft) |
var(--ok) |
.bo-risk--a_verifier |
ToVerify (a_verifier) |
var(--warn-soft) |
var(--warn) |
.bo-risk--eleve |
High (eleve) |
var(--danger-soft) |
var(--danger) |
aucun est volontairement neutre (gris --ink-2, « rien à signaler ») et non vert : le vert --ok est réservé à faible (risque présent mais mineur).
Préfixe de classes admin : bo-¶
Les classes propres à l'espace d'administration (back-office) utilisent le préfixe bo- (ex. bo-space__main), jamais ad- — un préfixe ad- est fréquemment bloqué par les bloqueurs de publicité. L'espace utilisateur utilise des classes sans préfixe bo-.
Contraintes RGAA¶
Le DS garantit plusieurs règles d'accessibilité, à ne jamais contourner :
- Anneau de focus — l'anneau
:focus-visiblen'est jamais retiré. La règle vit dansassets/styles/kirexo-ds.css. - Lien d'évitement — un skip-link
.skip-link(« Aller au contenu ») est le premier enfant du<body>danstemplates/base.html.twiget cible#main. Le<main>des layouts utilisateur et admin porte doncid="main". - Cibles tactiles ≥ 44px — les composants interactifs du DS (
.btn,.input…) garantissent une hauteur minimale de 44px.
Chargement des assets¶
Les CSS et les scripts du DS sont importés depuis assets/app.js :
import './styles/kirexo-ds.css';
import './styles/screens.css';
import './js/accent.js';
import './js/theme.js';
app.js est le seul entrypoint injecté dans templates/base.html.twig via {{ importmap('app') }}. Cet appel injecte automatiquement les <link> des CSS importés — il ne faut donc pas lier kirexo-ds.css une seconde fois via asset() (double chargement). Les deux modules accent.js et theme.js sont déclarés dans importmap.php comme modules importables (sans entrypoint), pour être résolus et versionnés par AssetMapper, et sont chargés sur toute page héritant du layout via les import d'app.js.
Voir aussi¶
- Pourquoi un accent d'instance piloté serveur — accent (serveur) vs thème (client), cohérence multi-appareils, dégraissage d'
accent.js. - Form theme du design-system — mapping des widgets Symfony vers les composants DS (
.field,.input,.btn…). - Espaces utilisateur et admin — les pages qui héritent des layouts DS.