// charte-tabs-3.jsx // Final tabs: Templates (3 example pages) + Tokens (theme.json + CSS) // Plus the main App shell with sidebar nav and Tweaks panel. const { useState: __useState } = React; /* ---------- Tab: Templates (3 example pages) ---------- */ function TabTemplates({ tweaks }) { const [active, setActive] = __useState("primaire"); const density = tweaks.density; const qrVisible = tweaks.qrVisible; const scoreVisible = tweaks.scoreVisible; const templates = [ { id: "primaire", label: "Primaire · Français CM2", pageEl: }, { id: "college", label: "Collège · Maths 4ᵉ", pageEl: }, { id: "lycee", label: "Lycée · SVT 1ʳᵉ", pageEl: }, ]; return ( <>

Templates de référence

Trois pages produites avec le système, à l'échelle réelle 8.5×11 (vue à 65%). Mêmes header / footer, mêmes composants, identité partagée — seul le centre de page change.

{templates.map(t => ( ))}
{React.cloneElement(templates.find(t => t.id === active).pageEl, { scale: 0.7 })}

Comment lire ces templates

Identique partout
Header, footer, marges, grille, typo, palette.
Variable par page
Matière, niveau, page, contenu central, présence Ketty.
Variable par niveau
Densité, taille de texte, place des illustrations.
Pilotable depuis Tweaks
Densité, QR / score visible, niveau, primaire color, typo.
); } /* ---------- Tab: Tokens ---------- */ const themeJsonString = `{ "$schema": "./allo-education.schema.json", "brand": "Allo Education", "edition": "Éditions Allo Education", "format": { "width": "8.5in", "height": "11in", "dpi": 300, "kdp": true }, "level": "college", "density": "standard", "fontPair": "fredoka-nunito", "colors": { "primary": "#1B3FB8", "primaryDark": "#102A85", "primaryDeep": "#0B1F66", "primarySoft": "#E8EEFB", "secondary": "#F5781C", "secondaryDark":"#D85F0A", "accent": "#FFC533", "accentSoft": "#FFF6D6", "success": "#1F9E5A", "successSoft": "#E2F4EA", "warning": "#E6A82B", "error": "#D62E2E", "errorSoft": "#FCE7E7", "background": "#FFFFFF", "backgroundAlt":"#FBF8F1", "text": "#0F1A3D", "textSoft": "#2B3656", "muted": "#6A748F", "border": "#D8DEEC", "rule": "#C4CCDF" }, "typography": { "title": { "family": "Fredoka", "weights": [500, 600, 700] }, "body": { "family": "Nunito Sans", "weights": [400, 600, 700, 800] }, "mono": { "family": "JetBrains Mono", "fallback": "Arial, Noto Sans Math" }, "scale": { "displayCover": "0.9in", "h1": "0.36in", "h2": "0.22in", "h3": "0.18in", "consigne": "0.15in", "body": "0.13in", "bodyMin": "0.12in", "eyebrow": "0.10in" } }, "grid": { "marginSide": "0.55in", "marginTop": "0.5in", "marginBottom": "0.5in", "headerHeight": "0.95in", "footerHeight": "0.85in", "columns": 6, "gutter": "0.18in", "baseline": "0.21in", "bleed": "0.125in" }, "header": { "background": "primary", "logoColor": ["#FFFFFF", "secondary"], "matierePill": { "border": "rgba(255,255,255,.45)", "color": "#FFFFFF" }, "pageBadge": { "background": "accent", "color": "primaryDeep" }, "doodles": true }, "footer": { "score": { "visible": true, "border": "primary", "style": "dashed" }, "qr": { "visible": true, "discColor": "primary", "label": "Corriger avec Ketty", "url": "alloeducation.fr" }, "page": { "background": "primary", "color": "#FFFFFF" } }, "components": { "lessonCard": { "tone": "yellow", "tabPosition": "top-left" }, "method": { "tone": "green", "label": "Méthode" }, "pitfall": { "tone": "red", "label": "Erreur à éviter" }, "exercice": { "tone": "primary", "tabStyle": "halfPill" }, "qcm": { "tone": "secondary","letterStyle": "boxed" }, "kettyBubble": { "border": "primary", "labelStyle": "filled-pill" }, "qrBlock": { "tone": "yellow", "minSize": "0.6in" }, "bilan": { "tone": "yellow-orange-gradient" }, "defi": { "tone": "secondary", "border": "dashed" } }, "density": { "air": { "blockGap": "0.26in", "lineHeight": 1.6, "answerBoxHeight": "0.84in" }, "standard": { "blockGap": "0.20in", "lineHeight": 1.5, "answerBoxHeight": "0.6in" }, "dense": { "blockGap": "0.14in", "lineHeight": 1.45, "answerBoxHeight": "0.5in" } }, "levelOverrides": { "cp": { "density": "air", "bodySize": "0.16in", "kettyPerPage": 2 }, "ce": { "density": "air", "bodySize": "0.14in", "kettyPerPage": 1 }, "6e": { "density": "standard", "bodySize": "0.14in", "kettyPerPage": 1 }, "4e": { "density": "standard", "bodySize": "0.13in", "kettyPerPage": 1 }, "lycee": { "density": "dense", "bodySize": "0.13in", "kettyPerPage": 0 } }, "ketty": { "asset": "img/ketty/{pose}.png", "poses": ["hello", "pointing", "thinking", "celebrating", "thumbsup"], "maxPerPage": 2, "defaultWidth": "0.85in" }, "qr": { "factoryUrl": "https://qr.alloeducation.fr/{slug}", "minPrintSize": "0.6in", "quietZone": "0.06in", "darkColor": "#0F1A3D", "lightColor": "#FFFFFF" }, "i18n": { "locale": "fr-FR", "decimalSeparator": "," } }`; const cssVarsString = `:root { /* Brand */ --ae-primary: #1B3FB8; --ae-primary-dark: #102A85; --ae-primary-deep: #0B1F66; --ae-primary-soft: #E8EEFB; --ae-orange: #F5781C; --ae-orange-dark: #D85F0A; --ae-orange-soft: #FFEEDC; --ae-yellow: #FFC533; --ae-yellow-dark: #E6A82B; --ae-yellow-soft: #FFF6D6; --ae-pink: #E91E78; /* couverture only */ /* Sémantiques */ --ae-success: #1F9E5A; --ae-success-soft: #E2F4EA; --ae-warning: #E6A82B; --ae-error: #D62E2E; --ae-error-soft: #FCE7E7; /* Neutres */ --ae-bg: #FFFFFF; --ae-bg-cream: #FBF8F1; --ae-bg-cool: #F6F8FC; --ae-text: #0F1A3D; --ae-text-soft: #2B3656; --ae-muted: #6A748F; --ae-border: #D8DEEC; /* Typographie */ --ae-font-title: "Fredoka", system-ui, sans-serif; --ae-font-body: "Nunito Sans", system-ui, sans-serif; --ae-font-mono: "JetBrains Mono", "Arial", monospace; /* Grille 8.5 × 11 */ --ae-page-w: 8.5in; --ae-page-h: 11in; --ae-margin-side: 0.55in; --ae-margin-top: 0.5in; --ae-margin-bottom: 0.5in; --ae-header-h: 0.95in; --ae-footer-h: 0.85in; /* Density (override par .density-air | .density-std | .density-dense) */ --ae-block-gap: 0.20in; --ae-density-y: 0.18in; }`; function colorize(json) { // Light syntax tinting for pretty display (JSON) return json .replace(/("[^"]+")\s*:/g, '$1:') .replace(/:\s*("[^"]+")/g, ': $1') .replace(/:\s*(true|false|null)/g, ': $1') .replace(/:\s*(-?\d+(\.\d+)?)/g, ': $1'); } function TabTokens() { return ( <>

theme.json

Schéma central de la collection. Tout fichier de cahier (Maths-CM2, SVT-1re…) hérite de ce thème de base et y applique des overrides précis (matière, niveau, palette par matière éventuelle).

      

Variables CSS

Le développeur peut consommer ces tokens directement dans les templates HTML / SCSS. Tous les composants de la charte référencent ces variables — changer une valeur ici la propage à toute la collection.

{cssVarsString}

Override d'un cahier (exemple)

Configuration minimale pour générer le cahier Maths · 4ᵉ à partir du thème de base :

{`{
  "extends": "./theme.json",
  "title": "Mon cahier de Maths",
  "matiere": "Maths",
  "niveau": "4ᵉ",
  "level": "4e",
  "density": "standard",
  "header": { "page": "Bloc {block} · Page {n}" },
  "ketty": { "maxPerPage": 1 },
  "qr": { "slug": "maths-4e/{block}-{page}" }
}`}

Tableau récapitulatif

{[ ["--ae-primary", "#1B3FB8", "Bleu Allo Education — header, primary actions"], ["--ae-orange", "#F5781C", "Énergie — QCM, défis, mise en exergue"], ["--ae-yellow", "#FFC533", "Accent — leçon, je retiens, badges"], ["--ae-success", "#1F9E5A", "Méthode, validation, corrigé"], ["--ae-error", "#D62E2E", "Erreur à éviter, piège"], ["--ae-text", "#0F1A3D", "Texte courant, titres en bleu deep"], ["--ae-muted", "#6A748F", "Métadonnées, légendes"], ["--ae-border", "#D8DEEC", "Bordures de cartes neutres"], ["--ae-page-w", "8.5in", "Largeur page (KDP)"], ["--ae-page-h", "11in", "Hauteur page"], ["--ae-header-h", "0.95in", "Hauteur header"], ["--ae-footer-h", "0.85in", "Hauteur footer"], ["--ae-margin-side", "0.55in", "Marge latérale (+0.125in côté reliure)"], ].map(([t, v, r]) => ( ))}
TokenValeurRôle
{t}{v}{r}
); } /* ========================================================================= App shell with sidebar + Tweaks panel ========================================================================= */ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "primaryHue": "#1B3FB8", "level": "college", "density": "std", "qrVisible": true, "scoreVisible": true, "fontPair": "fredoka-nunito" }/*EDITMODE-END*/; const PRIMARY_PALETTES = [ "#1B3FB8", // Bleu Allo Education (officiel) "#0E7C66", // Variante verte (cahier sciences) "#9F1239", // Variante bordeaux (cahier histoire) "#5B21B6", // Variante violette (cahier philo) ]; const FONT_PAIRS = { "fredoka-nunito": { title: "Fredoka", body: "Nunito Sans" }, "plus-jakarta": { title: "Plus Jakarta Sans", body: "Plus Jakarta Sans" }, "lora-nunito": { title: "Lora", body: "Nunito Sans" }, }; function App() { const [tab, setTab] = __useState("overview"); const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); // Apply primary color override across the whole app React.useEffect(() => { document.documentElement.style.setProperty("--ae-primary", t.primaryHue); // derive a dark version const dark = darken(t.primaryHue, 0.18); const deep = darken(t.primaryHue, 0.36); const soft = lighten(t.primaryHue, 0.85); document.documentElement.style.setProperty("--ae-primary-dark", dark); document.documentElement.style.setProperty("--ae-primary-deep", deep); document.documentElement.style.setProperty("--ae-primary-soft", soft); }, [t.primaryHue]); React.useEffect(() => { const pair = FONT_PAIRS[t.fontPair] || FONT_PAIRS["fredoka-nunito"]; document.documentElement.style.setProperty("--ae-font-title", `"${pair.title}", system-ui, sans-serif`); document.documentElement.style.setProperty("--ae-font-body", `"${pair.body}", system-ui, sans-serif`); }, [t.fontPair]); const tabs = [ { id: "overview", num: "00", label: "Vue d'ensemble", section: "Marque" }, { id: "colors", num: "01", label: "Couleurs", section: "Marque" }, { id: "typography", num: "02", label: "Typographie", section: "Marque" }, { id: "grid", num: "03", label: "Grille 8.5×11", section: "Système" }, { id: "header", num: "04", label: "Header / Footer", section: "Système" }, { id: "components", num: "05", label: "Composants", section: "Système" }, { id: "ketty", num: "06", label: "Ketty", section: "Système" }, { id: "levels", num: "07", label: "Variantes niveau", section: "Règles" }, { id: "dodont", num: "08", label: "Do / Don't", section: "Règles" }, { id: "templates", num: "09", label: "Templates", section: "Production" }, { id: "stress", num: "10", label: "Stress test (10)", section: "Production" }, { id: "pack1", num: "11", label: "Pack 1 · Universel",section: "Production" }, { id: "pack2", num: "12", label: "Pack 2 · FR / Langues", section: "Production" }, { id: "mathsbrevet",num: "13", label: "Maths Brevet", section: "Production" }, { id: "pack3", num: "14", label: "Pack 3 · HG / Sciences", section: "Production" }, { id: "pack4", num: "15", label: "Pack 4 · Jeux éducatifs", section: "Production" }, { id: "pack5", num: "16", label: "Pack 5 · Primaire", section: "Production" }, { id: "pack6", num: "17", label: "Pack 6 · Fin de livre", section: "Production" }, { id: "pack7", num: "18", label: "Pack 7 · Patterns", section: "Production" }, { id: "composition", num: "19", label: "Règles de composition", section: "Charte" }, { id: "tokens", num: "20", label: "Tokens", section: "Production" }, ]; const currentTab = tabs.find(x => x.id === tab) || tabs[0]; // Group sidebar const sections = []; tabs.forEach(t => { let g = sections.find(s => s.label === t.section); if (!g) { g = { label: t.section, items: [] }; sections.push(g); } g.items.push(t); }); return (
{currentTab.num} · {currentTab.section}

{currentTab.label}

{{ overview: "La carte d'identité de la collection Allo Education — du CP à la Terminale, multi-matières, imprimable KDP.", colors: "Bleu profond, orange énergie, jaune accent. Une palette systémique, des règles claires, une identité reconnaissable.", typography: "Fredoka pour la chaleur des titres, Nunito Sans pour le confort de lecture en print. Une échelle calée en pouces.", grid: "Toutes les pages partent de la même grille 8.5 × 11 in, 6 colonnes, marges fixes — l'ossature commune de la collection.", header: "Le shell que toutes les pages partagent. On change les données, jamais la structure.", components: "Les briques pédagogiques réutilisables : leçon, méthode, exercice, QCM, Ketty, QR, bilan…", ketty: "La coach pédagogique 3D de la collection. Toujours utile, jamais décorative.", levels: "Le même système se décline en cinq niveaux d'intensité, du plus illustré au plus académique.", dodont: "Cas concrets pour calibrer hiérarchie, alignements, couleurs, zones de réponse et présence de Ketty.", templates: "Trois pages réelles produites avec le système, à l'échelle 8.5 × 11 in.", stress: "10 pages de stress test du CP à la Terminale, construites uniquement avec les blocs verrouillés.", pack1: "Pack 1 · 10 templates universels prêts pour la production : les patterns les plus utilisés de la collection.", pack2: "Pack 2 · 10 templates pour le texte : vocabulaire, conjugaison, grammaire, lecture, dictée, écriture, dialogue, traduction.", mathsbrevet:"Maths Brevet · 15 templates pour générer les 100 pages d'Objectif Brevet Maths 3e (calculs, équations, fonctions, géométrie, brevets blancs, corrections).", pack3: "Pack 3 · 10 templates pour les pages visuelles complexes — frises, cartes, schémas, protocoles, documents et tableaux scientifiques.", pack4: "Pack 4 · 12 templates de jeux éducatifs universels — mots croisés, mots mêlés, code secret, intrus, V/F, relier, ordre, labyrinthe, coloriage magique, pixel art, memory, énigmes.", pack5: "Pack 5 · 12 templates primaire CP / CE1 / CE2 — sons, lecture, compréhension, écriture, dictée, calcul mental, calcul posé, problèmes, numération, géométrie, fiche du jour, modèle prof / parent.", pack7: "Pack 7 · Planche design — 18 blocs autorisés documentés visuellement (standard + compact), 5 compositions recommandées, 5 à éviter, règles d'espacement. Référence partagée rédacteur / dev / auditeur PDF.", composition: "Charte d'espacement v1.3 — anatomie de page + de bloc, hiérarchie des gaps (intra / sm / md / lg / section), 3 densités, blocs majeurs vs mineurs, exemples bon/mauvais, règles anti-overflow, 11 tokens officiels.", pack6: "Pack 6 · 12 templates de fin de livre — diplôme, bilan, hub QR, suite collection, défi bonus, brouillon, carnet d'erreurs, planning, mentions légales, couverture intérieure, ouverture de chapitre.", tokens: "Le contrat développeur : theme.json + variables CSS pour générer les 50+ templates de manière cohérente.", }[tab]}

{currentTab.num === "00" ? "Commence ici" : `Étape ${parseInt(currentTab.num,10)} / ${tabs.length - 1}`}
{tab === "overview" && } {tab === "colors" && } {tab === "typography" && } {tab === "grid" && } {tab === "header" && } {tab === "components" && } {tab === "ketty" && } {tab === "levels" && } {tab === "dodont" && } {tab === "templates" && } {tab === "stress" && } {tab === "pack1" && } {tab === "pack2" && } {tab === "mathsbrevet"&& } {tab === "pack3" && } {tab === "pack4" && } {tab === "pack5" && } {tab === "pack6" && } {tab === "pack7" && } {tab === "composition" && } {tab === "tokens" && }
setTweak("primaryHue", v)} /> setTweak("fontPair", v)} /> setTweak("level", v)} /> setTweak("density", v)} /> setTweak("qrVisible", v)} /> setTweak("scoreVisible", v)} />
); } /* ---------- color helpers ---------- */ function hexToRgb(hex) { const h = hex.replace("#", ""); return [parseInt(h.slice(0,2),16), parseInt(h.slice(2,4),16), parseInt(h.slice(4,6),16)]; } function rgbToHex(r,g,b) { return "#" + [r,g,b].map(v => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2,"0")).join(""); } function darken(hex, amount) { const [r,g,b] = hexToRgb(hex); return rgbToHex(r * (1 - amount), g * (1 - amount), b * (1 - amount)); } function lighten(hex, amount) { const [r,g,b] = hexToRgb(hex); return rgbToHex(r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount); } Object.assign(window, { App, TabTemplates, TabTokens });