> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lighton.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gestion des Thèmes

> La fonctionnalité de personnalisation de thème Paradigm vous permet de personnaliser l'interface Paradigm en changeant ses couleurs et en téléchargeant le logo de votre entreprise.

export const ColorGenerator = () => {
  const [hue, setHue] = useState(180);
  const [saturation, setSaturation] = useState(50);
  const [lightness, setLightness] = useState(50);
  const [colors, setColors] = useState([]);
  const [hInput, setHInput] = useState('180');
  const [sInput, setSInput] = useState('50');
  const [lInput, setLInput] = useState('50');
  const [rInput, setRInput] = useState('64');
  const [gInput, setGInput] = useState('191');
  const [bInput, setBInput] = useState('191');
  const [hexInput, setHexInput] = useState('');
  const hslToRgb = (h, s, l) => {
    s /= 100;
    l /= 100;
    const k = n => (n + h / 30) % 12;
    const a = s * Math.min(l, 1 - l);
    const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
    return [Math.round(255 * f(0)), Math.round(255 * f(8)), Math.round(255 * f(4))];
  };
  const rgbToHex = (r, g, b) => {
    return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
  };
  const hslToHex = (h, s, l) => {
    const [r, g, b] = hslToRgb(h, s, l);
    return rgbToHex(r, g, b);
  };
  const rgbToHsl = (r, g, b) => {
    r /= 255;
    g /= 255;
    b /= 255;
    const max = Math.max(r, g, b);
    const min = Math.min(r, g, b);
    let h, s, l = (max + min) / 2;
    if (max === min) {
      h = s = 0;
    } else {
      const d = max - min;
      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
      switch (max) {
        case r:
          h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
          break;
        case g:
          h = ((b - r) / d + 2) / 6;
          break;
        case b:
          h = ((r - g) / d + 4) / 6;
          break;
      }
    }
    return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
  };
  const hexToRgb = hex => {
    hex = hex.replace('#', '');
    if (hex.length === 3) {
      hex = hex.split('').map(char => char + char).join('');
    }
    const num = parseInt(hex, 16);
    return [num >> 16 & 255, num >> 8 & 255, num & 255];
  };
  useEffect(() => {
    const newColors = [];
    for (let i = 0; i < 5; i++) {
      const l = Math.max(10, Math.min(90, lightness - 20 + i * 10));
      newColors.push({
        hsl: `hsl(${hue}, ${saturation}%, ${l}%)`,
        rgb: hslToRgb(hue, saturation, l),
        hex: hslToHex(hue, saturation, l)
      });
    }
    setColors(newColors);
    const rgb = hslToRgb(hue, saturation, lightness);
    setHInput(String(hue));
    setSInput(String(saturation));
    setLInput(String(lightness));
    setRInput(String(rgb[0]));
    setGInput(String(rgb[1]));
    setBInput(String(rgb[2]));
    setHexInput(hslToHex(hue, saturation, lightness));
  }, [hue, saturation, lightness]);
  const copyToClipboard = text => {
    navigator.clipboard.writeText(text).then(() => {
      console.log(`Copied ${text} to clipboard!`);
    }).catch(err => {
      console.error("Failed to copy: ", err);
    });
  };
  const handleHslInputChange = (h, s, l) => {
    const hVal = Math.max(0, Math.min(360, Number(h) || 0));
    const sVal = Math.max(0, Math.min(100, Number(s) || 0));
    const lVal = Math.max(0, Math.min(100, Number(l) || 0));
    setHue(hVal);
    setSaturation(sVal);
    setLightness(lVal);
  };
  const handleRgbInputChange = (r, g, b) => {
    const rVal = Math.max(0, Math.min(255, Number(r) || 0));
    const gVal = Math.max(0, Math.min(255, Number(g) || 0));
    const bVal = Math.max(0, Math.min(255, Number(b) || 0));
    const [h, s, l] = rgbToHsl(rVal, gVal, bVal);
    setHue(h);
    setSaturation(s);
    setLightness(l);
  };
  const handleHexChange = value => {
    setHexInput(value);
    if ((/^#?[0-9A-Fa-f]{6}$/).test(value) || (/^#?[0-9A-Fa-f]{3}$/).test(value)) {
      const [r, g, b] = hexToRgb(value);
      const [h, s, l] = rgbToHsl(r, g, b);
      setHue(h);
      setSaturation(s);
      setLightness(l);
    }
  };
  return <div className="space-y-4">
            <div className="space-y-2">
                <label className="block text-sm font-medium">
                    Hue: {hue}°
                    <input type="range" min="0" max="360" value={hue} onChange={e => setHue(Number.parseInt(e.target.value))} className="w-full h-2 rounded-lg appearance-none cursor-pointer mt-1" style={{
    background: `linear-gradient(to right, 
                  hsl(0, ${saturation}%, ${lightness}%), 
                  hsl(60, ${saturation}%, ${lightness}%), 
                  hsl(120, ${saturation}%, ${lightness}%), 
                  hsl(180, ${saturation}%, ${lightness}%), 
                  hsl(240, ${saturation}%, ${lightness}%), 
                  hsl(300, ${saturation}%, ${lightness}%), 
                  hsl(360, ${saturation}%, ${lightness}%))`
  }} />
                </label>

                <label className="block text-sm font-medium">
                    Saturation: {saturation}%
                    <input type="range" min="0" max="100" value={saturation} onChange={e => setSaturation(Number.parseInt(e.target.value))} className="w-full h-2 rounded-lg appearance-none cursor-pointer mt-1" style={{
    background: `linear-gradient(to right, 
                  hsl(${hue}, 0%, ${lightness}%), 
                  hsl(${hue}, 50%, ${lightness}%), 
                  hsl(${hue}, 100%, ${lightness}%))`
  }} />
                </label>

                <label className="block text-sm font-medium">
                    Lightness: {lightness}%
                    <input type="range" min="0" max="100" value={lightness} onChange={e => setLightness(Number.parseInt(e.target.value))} className="w-full h-2 rounded-lg appearance-none cursor-pointer mt-1" style={{
    background: `linear-gradient(to right, 
                  hsl(${hue}, ${saturation}%, 0%), 
                  hsl(${hue}, ${saturation}%, 50%), 
                  hsl(${hue}, ${saturation}%, 100%))`
  }} />
                </label>
            </div>

            <div className="flex space-x-2">
                {colors.map((color, idx) => <div key={idx} className="h-20 rounded-lg flex-1 cursor-pointer transition-transform hover:scale-105 shadow-md" style={{
    backgroundColor: color.hsl
  }} title={`Click to copy: ${color.hex}`} onClick={() => copyToClipboard(color.hex)} />)}
            </div>

            <div className="bg-gray-50 dark:bg-gray-800 p-4 rounded-lg space-y-3">
                <div className="space-y-3">
                    <div>
                        <label className="block text-xs text-gray-600 dark:text-gray-400 mb-1">HSL</label>
                        <div className="flex gap-2">
                            <input type="number" value={hInput} onChange={e => {
    setHInput(e.target.value);
    handleHslInputChange(e.target.value, sInput, lInput);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="H (0-360)" min="0" max="360" />
                            <input type="number" value={sInput} onChange={e => {
    setSInput(e.target.value);
    handleHslInputChange(hInput, e.target.value, lInput);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="S (0-100)" min="0" max="100" />
                            <input type="number" value={lInput} onChange={e => {
    setLInput(e.target.value);
    handleHslInputChange(hInput, sInput, e.target.value);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="L (0-100)" min="0" max="100" />
                        </div>
                    </div>

                    <div>
                        <label className="block text-xs text-gray-600 dark:text-gray-400 mb-1">RGB</label>
                        <div className="flex gap-2">
                            <input type="number" value={rInput} onChange={e => {
    setRInput(e.target.value);
    handleRgbInputChange(e.target.value, gInput, bInput);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="R (0-255)" min="0" max="255" />
                            <input type="number" value={gInput} onChange={e => {
    setGInput(e.target.value);
    handleRgbInputChange(rInput, e.target.value, bInput);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="G (0-255)" min="0" max="255" />
                            <input type="number" value={bInput} onChange={e => {
    setBInput(e.target.value);
    handleRgbInputChange(rInput, gInput, e.target.value);
  }} className="flex-1 px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="B (0-255)" min="0" max="255" />
                        </div>
                    </div>

                    <div>
                        <label className="block text-xs text-gray-600 dark:text-gray-400 mb-1">HEX</label>
                        <input type="text" value={hexInput} onChange={e => handleHexChange(e.target.value)} className="w-full px-3 py-2 font-mono text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="#80bfbf" />
                    </div>
                </div>
            </div>
        </div>;
};

La fonctionnalité de personnalisation de thème Paradigm vous permet de personnaliser l'interface Paradigm en changeant ses couleurs et en téléchargeant le logo de votre entreprise.

## Qui Peut Accéder à la Gestion des Thèmes ?

Seuls les rôles Admin et Administrateur d'Entreprise ont accès au panneau d'administration pour modifier les thèmes. Les deux rôles ont les mêmes permissions, sauf que l'Admin peut définir le thème par défaut et gérer tous les thèmes. Cela garantit que la personnalisation des thèmes est gérée de manière sécurisée par le personnel autorisé.

## Où Accéder à la Gestion des Thèmes ?

Vous pouvez accéder à la fonctionnalité de gestion des thèmes dans le panneau d'administration, sous Paramètres > Thème Visuel.

## \\

\
\
Comment Utiliser la Gestion des Thèmes ?

<Info>
  Changements dans la configuration des thèmes des entreprises avec Wise Wolf

  **Placement dans la navigation de Paradigm Academy :** Administration > Configuration de l'organisation > Gestion des thèmes

  **Résumé :**\
  La version Wise Wolf introduit des modifications importantes dans la configuration des thèmes des entreprises. Ces changements visent à simplifier le modèle de thème visuel.

  #### **Qu'est-ce qui a changé ?**

  1. **Suppression de 7 champs de couleur inutilisés** du modèle `VisualTheme` :

     * `primary_content`
     * `secondary`
     * `secondary_content`
     * `homepage`
     * `homepage_light`
     * `light`
     * `second_light`

     Ces champs n'étaient pas utilisés dans l'application, ce qui causait de la confusion et une surcharge de maintenance.
  2. \*\*Ajout du champ \*\*`neutral` pour supporter des palettes de couleurs neutres configurables (slate, gray, zinc, neutral, stone).
</Info>

Sur la page de gestion des thèmes, vous pouvez définir les actifs de votre marque et les couleurs clés de l'interface.

#### 1. Définir les Illustrations par Thème :

| **Nom du Champ** | **Description**                                                                                                                                                                                                                                                                                    | **Statut**  |
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- |
| **Logo login**   | Logo affiché sur la page de connexion.	  - Forme : Arrondie ou carrée.	<br />- Taille : Environ 80×80 pixels.	<br />- Formats : JPEG et PNG.                                                                                                                                                       | FONCTIONNEL |
| **Logo header**  | Logo affiché dans la barre de navigation supérieure (visible sur toutes les pages principales).  - Contrainte de hauteur : Maximum 40 pixels.	<br />- Forme : Peut s'adapter à une forme rectangulaire.	<br />- Ratio d'aspect : Environ 1:3 (largeur sur hauteur).	<br />- Formats : JPEG et PNG. | FONCTIONNEL |
| **Icon**         | Télécharger une image par défaut car le champ est requis, mais elle ne sera pas affichée.                                                                                                                                                                                                          | OBSOLETE    |
| **Favicon**      | Icône affichée dans l'onglet du navigateur.                                                                                                                                                                                                                                                        | FONCTIONNEL |

#### 2. Choisir les Couleurs de Votre Thème :

Les options de couleur disponibles affectent directement les éléments clés de l'interface :

| **Nom du Champ**      | **Description**                                                                                                                                                                                                             | **Statut**                   |
| :-------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------- |
| **Primary**           | La couleur principale d'arrière-plan des boutons primaires (ex: bouton "Nouveau Chat", bouton "Soumettre Requête", bouton "Sauvegarder") et des éléments sélectionnés (ex: couleur de fond du lien de session sélectionné). | FONCTIONNEL                  |
| **Primary content**   | La couleur du texte qui apparaît sur les éléments définis par la couleur Primary.                                                                                                                                           | FONCTIONNEL                  |
| **Secondary**         | Obsolète                                                                                                                                                                                                                    | Laisser la valeur par défaut |
| **Secondary content** | Obsolète                                                                                                                                                                                                                    | Laisser la valeur par défaut |
| **Homepage**          | Change la **c**ouleur de fond de la barre de navigation.                                                                                                                                                                    | FONCTIONNEL                  |
| **Homepage light**    | Obsolète                                                                                                                                                                                                                    | Laisser la valeur par défaut |
| **Light**             | Obsolète                                                                                                                                                                                                                    | Laisser la valeur par défaut |
| **Second light**      | Obsolète                                                                                                                                                                                                                    | Laisser la valeur par défaut |

## Générateur de couleurs

Voici un outil que vous pouvez utiliser pour obtenir les bonnes valeurs de couleur.

<Tip>
  Modifiez n'importe quel format pour mettre à jour la couleur

  Cliquez sur les nuanciers pour copier la valeur HEX
</Tip>

<ColorGenerator />

## Impact de la Gestion des Thèmes

Votre thème personnalisé sera appliqué à l'ensemble de l'interface, ainsi qu'aux emails automatiques (tels que les invitations d'utilisateurs et les emails de réinitialisation de mot de passe). Cela garantit une expérience de marque cohérente sur tous les points de contact.

## Limitations

La page de connexion n'est pas personnalisable et conserve un thème par défaut. Cette limitation garantit la sécurité et la cohérence dans l'interface d'accès initial des utilisateurs.
