> ## 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.

# Themes Management

> The Paradigm theme customization feature allows you to personalize the Paradigm interface by changing its colors and uploading your company's logo.

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>;
};

The Paradigm theme customization feature allows you to personalize the Paradigm interface by changing its colors and uploading your company's logo.

## Who Can Access Theme Management?

Only Admin and Company Admin roles have access to the admin panel to modify themes. Both roles have the same permissions, except that the Admin can define the default theme and manage every theme. This ensures that theme customization is securely managed by authorized personnel.

## Where to Access Theme Management?

You can access the theme management feature in the admin panel, under Settings > Visual Theme.

## How to Use Theme Management?

On the theme management page, you can define your brand assets and key interface colors.

<Info>
  Changes in Company Theme Configuration with Wise Wolf

  **Placement in Paradigm Academy Navigation:** Administration > Organization Setup > Themes Management

  **Summary:**\
  The Wise Wolf release introduces significant changes to company theme configuration. These changes aim to simplify the visual theme model by removing unused color fields and adding a neutral color palette field aligned with Tailwind palettes. This article describes the technical changes, the reasons behind them, and how users can adapt their configuration.

  #### **What Changed?**

  1. **Removed 7 unused color fields** from the `VisualTheme` model:

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

     These fields were not being used in the application, causing confusion and maintenance overhead.
  2. \*\*Added the \*\*`neutral`**field**  to support configurable neutral color palettes (slate, gray, zinc, neutral, stone).
</Info>

### 1. Define Illustrations per Theme:

| **Field Name**  | **Description/Constraints**                                                                                                                                                                                                                                     | **Status**                           |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| **Logo login**  | Logo displayed on the login page. <br />- Shape: Rounded or square., <br />- Size: Approximately 80x80 pixels. <br />- Formats: JPEG and PNG.                                                                                                                   | FUNCTIONAL<br />Customize as needed. |
| **Logo header** | Logo displayed in the top navigation bar (visible on all primary pages).. <br />- Maximum height of 40 pixels., <br />- Shape: Can accommodate a rectangular shape., <br />- Aspect Ratio: Approximately 1:3 (width to height), ,<br />- Formats: JPEG and PNG. | FUNCTIONAL<br />Customize as needed. |
| **Icon**        | Upload a default image because the field is required, but it will not be displayed.                                                                                                                                                                             | OBSOLETE                             |
| **Favicon**     | Icon displayed in the browser tab.                                                                                                                                                                                                                              | FUNCTIONAL<br />Customize as needed. |

#### 2. Choose Colors for Your Theme:

The color options available directly affect key elements of the interface:

| **Field Name**        | **Description**                                                                                                                                                                               | **Status**                           |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| **Primary**           | The main background color of primary buttons (e.g., "New Chat" button, "Submit Query" button, "Save" button) and selected elements (e.g., the background color of the selected session link). | FUNCTIONAL<br />Customize as needed. |
| **Primary content**   | The text color that appears on top of the elements defined by the Primary element.                                                                                                            | FUNCTIONAL<br />Customize as needed. |
| **Secondary**         | Enter a default value (e.g., `#FFFFFF`) as this field is still required by the system.                                                                                                        | OBSOLETE                             |
| **Secondary content** | Enter a default value (e.g., `#FFFFFF`) as this field is still required by the system.                                                                                                        | OBSOLETE                             |
| **Homepage**          | Changes the background color of the left-hand navigation bar.                                                                                                                                 | FUNCTIONAL<br />Customize as needed. |
| **Homepage light**    | Enter a default value (e.g., `#FFFFFF`) as this field is still required by the system.                                                                                                        | OBSOLETE                             |
| **Light**             | Enter a default value (e.g., `#FFFFFF`) as this field is still required by the system.                                                                                                        | OBSOLETE                             |
| **Second light**      | Enter a default value (e.g., `#FFFFFF`) as this field is still required by the system.                                                                                                        | OBSOLETE                             |

## Color Generator

Here is a tool you can use to help get the correct color values.

<Tip>
  Edit any format to update the color

  Click color swatches to copy HEX value
</Tip>

<ColorGenerator />

## Impact of Theme Management

Your custom theme will be applied to the entire interface, as well as automatic emails (such as user invitations and password reset emails). This ensures a consistent brand experience across all touchpoints.

## Limitations

The login page is not customizable and retains a default theme. This limitation ensures security and consistency in the initial user access interface.
