diff --git a/setup/web_theme_color/odoo/addons/web_theme_color b/setup/web_theme_color/odoo/addons/web_theme_color new file mode 120000 index 0000000..b72d255 --- /dev/null +++ b/setup/web_theme_color/odoo/addons/web_theme_color @@ -0,0 +1 @@ +../../../../web_theme_color \ No newline at end of file diff --git a/setup/web_theme_color/setup.py b/setup/web_theme_color/setup.py new file mode 100644 index 0000000..28c57bb --- /dev/null +++ b/setup/web_theme_color/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_theme_color/README.rst b/web_theme_color/README.rst new file mode 100644 index 0000000..c54dd25 --- /dev/null +++ b/web_theme_color/README.rst @@ -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 `_. +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Escodoo + +Contributors +~~~~~~~~~~~~ + +* `Escodoo `_: + + * Wesley Oliveira + +Maintainers +~~~~~~~~~~~ + +This module is part of the `Escodoo/server-addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/web_theme_color/__init__.py b/web_theme_color/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/web_theme_color/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_theme_color/__manifest__.py b/web_theme_color/__manifest__.py new file mode 100644 index 0000000..5d85ec0 --- /dev/null +++ b/web_theme_color/__manifest__.py @@ -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, +} diff --git a/web_theme_color/data/ir_config_parameter.xml b/web_theme_color/data/ir_config_parameter.xml new file mode 100644 index 0000000..829b364 --- /dev/null +++ b/web_theme_color/data/ir_config_parameter.xml @@ -0,0 +1,9 @@ + + + + + web_theme_color.primary + #71639e + + diff --git a/web_theme_color/models/__init__.py b/web_theme_color/models/__init__.py new file mode 100644 index 0000000..7beafac --- /dev/null +++ b/web_theme_color/models/__init__.py @@ -0,0 +1,2 @@ +from . import web_theme_color +from . import ir_config_parameter diff --git a/web_theme_color/models/ir_config_parameter.py b/web_theme_color/models/ir_config_parameter.py new file mode 100644 index 0000000..37c766e --- /dev/null +++ b/web_theme_color/models/ir_config_parameter.py @@ -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 diff --git a/web_theme_color/models/web_theme_color.py b/web_theme_color/models/web_theme_color.py new file mode 100644 index 0000000..7ba7d91 --- /dev/null +++ b/web_theme_color/models/web_theme_color.py @@ -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") diff --git a/web_theme_color/pyproject.toml b/web_theme_color/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/web_theme_color/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_theme_color/readme/CONTRIBUTORS.rst b/web_theme_color/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..2f9bd6d --- /dev/null +++ b/web_theme_color/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Escodoo `_: + + * Wesley Oliveira diff --git a/web_theme_color/readme/DESCRIPTION.rst b/web_theme_color/readme/DESCRIPTION.rst new file mode 100644 index 0000000..6b5845b --- /dev/null +++ b/web_theme_color/readme/DESCRIPTION.rst @@ -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. diff --git a/web_theme_color/readme/USAGE.rst b/web_theme_color/readme/USAGE.rst new file mode 100644 index 0000000..825e71c --- /dev/null +++ b/web_theme_color/readme/USAGE.rst @@ -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. diff --git a/web_theme_color/static/description/icon.png b/web_theme_color/static/description/icon.png new file mode 100644 index 0000000..12ab005 Binary files /dev/null and b/web_theme_color/static/description/icon.png differ diff --git a/web_theme_color/static/description/index.html b/web_theme_color/static/description/index.html new file mode 100644 index 0000000..84765d6 --- /dev/null +++ b/web_theme_color/static/description/index.html @@ -0,0 +1,476 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Web Theme Color

+ +

Beta License: AGPL-3 Escodoo/server-addons

+

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

+ +
+

Usage

+

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

+ +++++ + + + + + + + + + + + + +
ParameterDefaultWhat it sets
web_theme_color.primary#71639eBrand 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. +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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Escodoo
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the Escodoo/server-addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+
+ + diff --git a/web_theme_color/static/src/scss/primary_variables.scss b/web_theme_color/static/src/scss/primary_variables.scss new file mode 100644 index 0000000..ee71938 --- /dev/null +++ b/web_theme_color/static/src/scss/primary_variables.scss @@ -0,0 +1,7 @@ +// Default backend brand color. Loaded first in web._assets_primary_variables so +// the core !default assignments keep this value. +// Rewritten from the system parameter web_theme_color.primary. +$o-community-color: #71639e !default; +$o-enterprise-color: #71639e !default; +$o-brand-odoo: #71639e !default; +$o-brand-primary: #71639e !default;