Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions setup/web_theme_color/odoo/addons/web_theme_color
6 changes: 6 additions & 0 deletions setup/web_theme_color/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
114 changes: 114 additions & 0 deletions web_theme_color/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

===============
Web Theme Color
===============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b6507bf315d314cd97746f40e0ed42f18174133f1dda227d5b16f70ca744e3e4
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-Escodoo%2Fserver--addons-lightgray.png?logo=github
:target: https://github.com/Escodoo/server-addons/tree/16.0/web_theme_color
:alt: Escodoo/server-addons

|badge1| |badge2| |badge3|

Set the Odoo backend brand color from a system parameter, without writing a
module for each customer.

The navbar, its bottom border, the primary buttons, the form focus states and
the links follow the color. In 16.0 there is no separate ``$o-action``
variable, so everything derived from the brand color moves with it.

The color is a scss variable, not a runtime style, so changing the parameter
rewrites the theme scss file and rebuilds the web assets. The change is global
for the database: every company and every user sees the same color.

This 16.0 version only themes the light backend. Dark mode is an Enterprise
feature, and on 16.0 the ``web.dark_mode_variables`` bundle cannot be resolved
on Community at all: its own ``before`` directive targets
``base/static/src/scss/onboarding.variables.scss``, a file that bundle does not
carry, so writing into it raises. The 18.0 version of this module does handle
dark mode.

A few spots keep the Odoo purple because the core hardcodes it instead of
reading the variable: the table picker of the html editor and the
``theme-color`` meta tag, which colors the browser bar on mobile. Document
layout colors (PDF and email) and the Website theme palette are separate
settings.

**Table of contents**

.. contents::
:local:

Usage
=====

Go to **Settings > Technical > Parameters > System Parameters** and change the
value of the parameter created by the module:

.. list-table::
:header-rows: 1

* - Parameter
- Default
- What it sets
* - ``web_theme_color.primary``
- ``#71639e``
- Brand color of the backend

The value is an hexadecimal color such as ``#D01000``. Both the three digit
(``#D10``) and the six digit form are accepted. Any other value is rejected
when you save the parameter, so a typo cannot break the assets. Clearing the
value deletes the parameter, which puts the backend back on the standard Odoo
color.

After saving, reload the backend with a hard refresh (Ctrl+F5) so the browser
drops the cached assets. The default value is the standard Odoo color, so
installing the module alone changes nothing.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/Escodoo/server-addons/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/Escodoo/server-addons/issues/new?body=module:%20web_theme_color%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Escodoo

Contributors
~~~~~~~~~~~~

* `Escodoo <https://www.escodoo.com.br>`_:

* Wesley Oliveira <wesley.oliveira@escodoo.com.br>

Maintainers
~~~~~~~~~~~

This module is part of the `Escodoo/server-addons <https://github.com/Escodoo/server-addons/tree/16.0/web_theme_color>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions web_theme_color/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
28 changes: 28 additions & 0 deletions web_theme_color/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2026 - TODAY, Escodoo
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Web Theme Color",
"summary": """
Set the backend brand color from a system parameter""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Escodoo",
"website": "https://github.com/Escodoo/server-addons",
"depends": [
"web",
"web_editor",
],
"data": [
"data/ir_config_parameter.xml",
],
"assets": {
"web._assets_primary_variables": [
(
"prepend",
"web_theme_color/static/src/scss/primary_variables.scss",
),
],
},
"installable": True,
}
9 changes: 9 additions & 0 deletions web_theme_color/data/ir_config_parameter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2026 - TODAY, Escodoo
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo noupdate="1">
<record id="param_web_theme_color_primary" model="ir.config_parameter">
<field name="key">web_theme_color.primary</field>
<field name="value">#71639e</field>
</record>
</odoo>
2 changes: 2 additions & 0 deletions web_theme_color/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import web_theme_color
from . import ir_config_parameter
31 changes: 31 additions & 0 deletions web_theme_color/models/ir_config_parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2026 - TODAY, Escodoo
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, models

from .web_theme_color import THEME_PARAMS


class IrConfigParameter(models.Model):
_inherit = "ir.config_parameter"

def _apply_web_theme_color(self, keys):
if THEME_PARAMS.intersection(keys):
self.env["web.theme.color"]._apply_colors()

@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
records._apply_web_theme_color(records.mapped("key"))
return records

def write(self, vals):
res = super().write(vals)
self._apply_web_theme_color(self.mapped("key"))
return res

def unlink(self):
keys = self.mapped("key")
res = super().unlink()
self._apply_web_theme_color(keys)
return res
75 changes: 75 additions & 0 deletions web_theme_color/models/web_theme_color.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright 2026 - TODAY, Escodoo
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import re

from odoo import _, api, models
from odoo.exceptions import ValidationError

PARAM_PRIMARY = "web_theme_color.primary"

DEFAULT_PRIMARY = "#71639e"

COLOR_PATTERN = re.compile(r"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")

# (parameter, default, asset to rewrite, bundle it belongs to)
# 16.0 only handles the light theme: web.dark_mode_variables cannot be resolved
# on Community, its own `before` directive targets a file the bundle does not
# carry, so touching it raises. Dark mode is an Enterprise feature anyway.
THEME_ASSETS = (
(
PARAM_PRIMARY,
DEFAULT_PRIMARY,
"/web_theme_color/static/src/scss/primary_variables.scss",
"web._assets_primary_variables",
),
)

THEME_PARAMS = frozenset(asset[0] for asset in THEME_ASSETS)

SCSS_TEMPLATE = """\
// Generated from the system parameter %(param)s.
// Change that parameter instead of editing this file.
$o-community-color: %(color)s !default;
$o-enterprise-color: %(color)s !default;
$o-brand-odoo: %(color)s !default;
$o-brand-primary: %(color)s !default;
"""


class WebThemeColor(models.AbstractModel):
_name = "web.theme.color"
_description = "Backend Theme Color"

@api.model
def _check_color(self, param, color):
if not COLOR_PATTERN.match(color or ""):
raise ValidationError(
_(
"%(color)s is not a valid color for %(param)s.\n\n"
"Use an hexadecimal value such as #D01000.",
color=color or "",
param=param,
)
)
return color

@api.model
def _apply_colors(self):
"""Rewrite the theme scss files from the system parameters.

The colors are scss variables, so they are only picked up when the
bundle is compiled. Saving the asset replaces the file and invalidates
the bundle; on the default color the customization is removed instead,
so no attachment is left behind.
"""
assets = self.env["web_editor.assets"].sudo()
params = self.env["ir.config_parameter"].sudo()
for param, default, url, bundle in THEME_ASSETS:
color = params.get_param(param) or default
self._check_color(param, color)
if color.lower() == default.lower():
assets.reset_asset(url, bundle)
continue
content = SCSS_TEMPLATE % {"color": color, "param": param}
assets.save_asset(url, bundle, content, "scss")
3 changes: 3 additions & 0 deletions web_theme_color/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
3 changes: 3 additions & 0 deletions web_theme_color/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Escodoo <https://www.escodoo.com.br>`_:

* Wesley Oliveira <wesley.oliveira@escodoo.com.br>
23 changes: 23 additions & 0 deletions web_theme_color/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Set the Odoo backend brand color from a system parameter, without writing a
module for each customer.

The navbar, its bottom border, the primary buttons, the form focus states and
the links follow the color. In 16.0 there is no separate ``$o-action``
variable, so everything derived from the brand color moves with it.

The color is a scss variable, not a runtime style, so changing the parameter
rewrites the theme scss file and rebuilds the web assets. The change is global
for the database: every company and every user sees the same color.

This 16.0 version only themes the light backend. Dark mode is an Enterprise
feature, and on 16.0 the ``web.dark_mode_variables`` bundle cannot be resolved
on Community at all: its own ``before`` directive targets
``base/static/src/scss/onboarding.variables.scss``, a file that bundle does not
carry, so writing into it raises. The 18.0 version of this module does handle
dark mode.

A few spots keep the Odoo purple because the core hardcodes it instead of
reading the variable: the table picker of the html editor and the
``theme-color`` meta tag, which colors the browser bar on mobile. Document
layout colors (PDF and email) and the Website theme palette are separate
settings.
22 changes: 22 additions & 0 deletions web_theme_color/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Go to **Settings > Technical > Parameters > System Parameters** and change the
value of the parameter created by the module:

.. list-table::
:header-rows: 1

* - Parameter
- Default
- What it sets
* - ``web_theme_color.primary``
- ``#71639e``
- Brand color of the backend

The value is an hexadecimal color such as ``#D01000``. Both the three digit
(``#D10``) and the six digit form are accepted. Any other value is rejected
when you save the parameter, so a typo cannot break the assets. Clearing the
value deletes the parameter, which puts the backend back on the standard Odoo
color.

After saving, reload the backend with a hard refresh (Ctrl+F5) so the browser
drops the cached assets. The default value is the standard Odoo color, so
installing the module alone changes nothing.
Binary file added web_theme_color/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading