Référence du manifest thème
Chaque thème exporte un unique depuis son . C'est le contrat entre le thème et l'admin. Faites ça bien et tout le reste suit.
Chaque thème exporte un ThemeManifest<TConfig> unique depuis son manifest.ts. C'est le contrat entre le thème et l'admin. Faites ça bien et tout le reste suit.
Shape complète
export interface ThemeManifest<TConfig = unknown> {
id: string;
name: string;
version: string;
description?: string;
imageFormats?: ImageFormatConfig;
scssEntry?: string;
cssText: string;
compileCss?: (config: TConfig) => string;
templates: {
base: ComponentType<BaseLayoutProps>;
home: ComponentType<HomeTemplateProps>;
single: ComponentType<SingleTemplateProps>;
category: ComponentType<CategoryTemplateProps>;
author: ComponentType<AuthorTemplateProps>;
notFound: ComponentType<NotFoundTemplateProps>;
};
blocks?: BlockManifest[];
settings?: {
navLabelKey: string;
defaultConfig: TConfig;
component: ComponentType<ThemeSettingsPageProps<TConfig>>;
};
i18n?: Record<string, Record<string, unknown>>;
jsText?: string; // optionnel — code du menu-loader / posts-loader inline
}
Champs
id — obligatoire
Kebab-case, ASCII lower. Immuable. Utilisé comme :
- Clé de stockage :
settings.activeThemeId,settings.themeConfigs[id] - Path d'asset :
theme-assets/<id>.csssur Flexweg - Namespace de bloc : tous les blocs
<id>/<name> - Namespace i18n :
theme-<id> - Path d'install (thèmes externes) :
/admin/themes/<id>/
name — obligatoire
Affichage UI dans la liste des thèmes.
version — obligatoire
Semver. Affichée à la réinstallation pour les thèmes externes (v1.0.0 → v1.1.0).
description — optionnel
Phrase courte affichée sur la carte du thème.
imageFormats — optionnel
Déclare les variantes d'image que le thème consomme. Voir Variantes d'image.
imageFormats: {
inputFormats: [".jpg", ".jpeg", ".png", ".webp", ".gif"],
outputFormat: "webp",
quality: 80,
variants: [
{ name: "thumbnail", maxWidth: 400, maxHeight: 400, fit: "cover" },
{ name: "medium", maxWidth: 800, maxHeight: 800, fit: "contain" },
{ name: "large", maxWidth: 1600, maxHeight: 1600, fit: "contain" },
],
}
Si omis, le pipeline standard s'applique (les trois variantes admin-* + un fallback default).
scssEntry — optionnel
Indique le fichier SCSS principal (à des fins de documentation). N'a pas d'impact runtime — c'est cssText qui compte.
cssText — obligatoire
La CSS finale que l'admin upload sur Flexweg. Typiquement importée via ?inline ou ?raw :
// Pipeline SCSS
import cssText from "./theme.scss?inline";
// Pipeline Tailwind (theme.compiled.css est produit par le prebuild)
import cssText from "./theme.compiled.css?inline";
// Pure CSS / hand-written
import cssText from "./theme.css?raw";
L'admin upload cssText (ou compileCss(config) si défini) à theme-assets/<id>.css à l'activation du thème + à chaque save de la page de réglages.
compileCss — optionnel
Hook qui transforme cssText (baseline) en CSS live (avec overrides utilisateur). Appelé chaque fois que l'admin upload theme-assets/<id>.css.
compileCss: (config: MyThemeConfig) => {
let css = cssText;
// Append :root with user overrides
const overrides = Object.entries(config.style.vars)
.map(([k, v]) => ` ${k}: ${v};`)
.join("\n");
css += `\n\n:root {\n${overrides}\n}\n`;
// Swap font @imports
css = css.replace(
/@import url\("https:\/\/fonts\.googleapis\.com[^"]+"\);/,
`@import url("https://fonts.googleapis.com/css2?family=${config.style.fontHeadline}&display=swap");`
);
return css;
};
Sans compileCss, chaque sync écrase les overrides utilisateur — donc obligatoire dès que la page de réglages expose des overrides de style.
templates — obligatoire
Les six composants React. Tous obligatoires. Voir Templates et props.
blocks — optionnel
Tableau de BlockManifest. Auto-enregistrés à l'activation du thème. Voir Blocs de thème.
settings — optionnel
Déclare une page de réglages thème (/theme-settings). Voir Page de réglages thème.
i18n — optionnel
Bundles de traduction par locale. Chargés au boot dans le namespace theme-<id>. Mêmes conventions que pour les plugins.
jsText — optionnel
Code JavaScript runtime inline. Typique : un menu-loader.js qui remplit les [data-cms-menu] containers depuis /menu.json au chargement de la page.
import jsText from "./menu-loader.js?raw";
const manifest: ThemeManifest = {
// ...
jsText,
};
L'admin upload jsText à theme-assets/<id>-menu.js à l'activation du thème. Le BaseLayout référence ce fichier via <script defer src="/theme-assets/<id>-menu.js"></script>.
Pour les thèmes avec plusieurs loaders, utilisez des conventions de noms (<id>-menu.js, <id>-posts.js, <id>-search.js, etc.) et uploadez chacun séparément dans la cible de régénération du thème.
Exemple minimal
import cssText from "./theme.scss?inline";
import { BaseLayout } from "./templates/BaseLayout";
import { HomeTemplate } from "./templates/HomeTemplate";
import { SingleTemplate } from "./templates/SingleTemplate";
import { CategoryTemplate } from "./templates/CategoryTemplate";
import { AuthorTemplate } from "./templates/AuthorTemplate";
import { NotFoundTemplate } from "./templates/NotFoundTemplate";
import type { ThemeManifest } from "@flexweg/cms-runtime";
const manifest: ThemeManifest = {
id: "my-theme",
name: "My Theme",
version: "1.0.0",
description: "A minimal example theme",
cssText,
templates: {
base: BaseLayout,
home: HomeTemplate,
single: SingleTemplate,
category: CategoryTemplate,
author: AuthorTemplate,
notFound: NotFoundTemplate,
},
};
export default manifest;
C'est tout pour un thème fonctionnel. Ajoutez blocks, settings, i18n, compileCss, jsText au besoin.