Skip to content

Commit

Permalink
add theme colors option
Browse files Browse the repository at this point in the history
  • Loading branch information
emge-odoo committed Mar 7, 2025
1 parent b651514 commit 1403a48
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class BuilderRow extends Component {
static components = { BuilderComponent };
static props = {
...basicContainerBuilderComponentProps,
label: String,
label: { type: String, optional: true },
tooltip: { type: String, optional: true },
slots: { type: Object, optional: true },
level: { type: Number, optional: true },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@

<t t-name="html_builder.BuilderRow">
<BuilderComponent>
<div class="d-flex position-relative p-1 px-2 ps-3 hb-row" t-att-class="this.getLevelClass()" t-ref="root" t-att-data-label="props.label">
<div
class="d-flex position-relative p-1 px-2 ps-3 hb-row"
t-att-class="this.getLevelClass()"
t-ref="root"
t-att-data-label="props.label">
<button t-if="state.hasCollapseContent"
class="o_we_collapse_toggler pt-1" t-att-class="{ 'active': state.expanded }"
title="Toggle more options"
t-on-click="toggleCollapseContent"
t-att-aria-expanded="state.expanded ? 'true' : 'false'"
t-att-aria-controls="collapseContentId"/>
<div class="d-flex" style="flex-grow: 0.4; flex-basis: 0; min-width: 0;" t-att-data-tooltip="props.tooltip" t-on-click="toggleCollapseContent">
<span class="text-nowrap text-truncate" t-out="props.label"/>
</div>
<div class="d-flex" style="flex-grow: 0.6; flex-basis: 0; min-width: 0; gap: 4px;" t-ref="content">
<t t-if="props.label">
<div class="d-flex" style="flex-grow: 0.4; flex-basis: 0; min-width: 0;" t-att-data-tooltip="props.tooltip" t-on-click="toggleCollapseContent">
<t t-if="props.label">
<span class="text-nowrap text-truncate" t-out="props.label"/>
</t>
</div>
<div class="d-flex" style="flex-grow: 0.6; flex-basis: 0; min-width: 0; gap: 4px;" t-ref="content">
<t t-slot="default"/>
</div>
</t>
<div t-else="" class="d-flex" style="flex-grow: 1; flex-basis: 0; min-width: 0; gap: 4px;" t-ref="content">
<t t-slot="default"/>
</div>
</div>
Expand Down
78 changes: 78 additions & 0 deletions addons/html_builder/static/src/sidebar/theme_colors_option.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Component, useState, onMounted } from "@odoo/owl";
import { getCSSVariableValue } from "@html_builder/utils/utils_css";
import { defaultBuilderComponents } from "../core/default_builder_components";

export class ThemeColorsOption extends Component {
static template = "html_builder.ThemeColorsOption";
static components = { ...defaultBuilderComponents };
static props = {};
setup() {
this.presets = useState([]);
this.palettes = this._getPalettes();
const observer = new MutationObserver(this._updatePresets.bind(this));
onMounted(() => {
this.iframeDocument = document.querySelector("iframe").contentWindow.document;
observer.observe(this.iframeDocument.documentElement, {
attributes: true,
childList: true,
subtree: true,
attributeFilter: ["style"],
});
this._updatePresets();
});
}

_getPalettes() {
const palettes = [];
const style = window.getComputedStyle(document.documentElement);
const allPaletteNames = getCSSVariableValue("palette-names", style)
.split(", ")
.map((name) => name.replace(/'/g, ""));
for (const paletteName of allPaletteNames) {
const palette = {
name: paletteName,
colors: [],
};
[1, 3, 2].forEach((c) => {
const color = getCSSVariableValue(`o-palette-${paletteName}-o-color-${c}`, style);
palette.colors.push(color);
});
palettes.push(palette);
}
return palettes;
}

_updatePresets() {
this.presets.length = 0;
for (let i = 1; i <= 5; i++) {
const preset = {
id: i,
background: this._getColor(`o-cc${i}-bg`),
backgroundGradient: this._getColor(`o-cc${i}-bg-gradient`),
text: this._getColor(`o-cc${i}-text`),
headings: this._getColor(`o-cc${i}-headings`),
primaryBtn: this._getColor(`o-cc${i}-btn-primary`),
primaryBtnText: this._getColor(`o-cc${i}-btn-primary-text`),
primaryBtnBorder: this._getColor(`o-cc${i}-btn-primary-border`),
secondaryBtn: this._getColor(`o-cc${i}-btn-secondary`),
secondaryBtnText: this._getColor(`o-cc${i}-btn-secondary-text`),
secondaryBtnBorder: this._getColor(`o-cc${i}-btn-secondary-border`),
};

// TODO: check if this is necessary
if (preset.backgroundGradient) {
preset.backgroundGradient += ", url('/web/static/img/transparent.png')";
}
this.presets.push(preset);
}
}

_getColor(color) {
if (!this.iframeStyle) {
this.iframeStyle = this.iframeDocument.defaultView.getComputedStyle(
this.iframeDocument.documentElement
);
}
return getCSSVariableValue(color, this.iframeStyle);
}
}
154 changes: 154 additions & 0 deletions addons/html_builder/static/src/sidebar/theme_colors_option.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="html_builder.ThemeColorsOption">
<BuilderContext preview="false">
<!-- TODO
<we-alert class="o_old_color_system_warning d-none mt-2">
It appears your website is still using the old color system of
Odoo 13.0 in some places. We made sure it is still working but
we recommend you to try to use the new color system, which is
still customizable.
</we-alert>-->
<BuilderRow>
<div class="d-flex flex-row gap-3 w-100 justify-content-between" style="height: 50px">
<div class="d-flex flex-column h-100 justify-content-between">
<span class="font-italic">Main</span>
<div class="d-flex flex-row">
<BuilderColorPicker
title="Primary"
action="'customizeWebsiteColor'"
actionParam="'o-color-1'"/>
<BuilderColorPicker
title="Secondary"
action="'customizeWebsiteColor'"
actionParam="'o-color-2'"/>
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="'o-color-3'"/>
</div>
</div>
<div class="d-flex flex-column h-100 justify-content-between">
<span class="font-italic">Light &amp; Dark</span>
<div class="d-flex flex-row">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="'o-color-4'" />
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="'o-color-5'" />
</div>
</div>
<div class="d-flex flex-column h-100">
<!-- TODO: use icon for palette selection button -->
<!-- <button class="btn btn-primary h-100 p-2">
<img class="p-2 h-100" src="/website/static/src/img/snippets_options/palette.svg" />
</button> -->
<div class="d-flex flex-column h-100 justify-content-between">
<span class="font-italic">Palette</span>
<BuilderSelect action="'customizeWebsiteVariable'" actionParam="'color-palettes-name'">
<t t-foreach="palettes" t-as="palette" t-key="palette.name">
<BuilderSelectItem actionValue="palette.name">
<div class="d-flex flex-row" style="min-width: 60px">
<t t-foreach="palette.colors" t-as="color" t-key="color">
<span class="w-100" t-attf-style="background-color: {{color}}; height: 25px"></span>
</t>
</div>
</BuilderSelectItem>
</t>
</BuilderSelect>
</div>
</div>
</div>
</BuilderRow>
<BuilderRow label.translate="Color Presets">
<div></div> <!-- This is required, without it the row is not displayed at all -->
<t t-set-slot="collapse">
<t t-foreach="presets" t-as="preset" t-key="preset.id">
<BuilderRow>
<div
t-attf-class="
w-100 p-2 d-flex justify-content-between
align-items-center"
t-attf-style="
background-color: {{preset.background}};
background-image: {{preset.backgroundGradient}};
color: {{preset.text}}">
<h3
class="m-0"
t-attf-style="color: {{preset.headings}}">
Title
</h3>
<p class="m-0">
Text
</p>
<button
class="btn btn-sm"
t-attf-style="
background-color: {{preset.primaryBtn}};
color: {{preset.primaryBtnText}};
border: 1px solid {{preset.primaryBtnBorder}}">
Button
</button>
<button
class="btn btn-sm"
t-attf-style="
background-color: {{preset.secondaryBtn}};
color: {{preset.secondaryBtnText}};
border: 1px solid {{preset.secondaryBtnBorder}}">
Button
</button>
</div>
<t t-set-slot="collapse">
<BuilderRow label.translate="Background">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-bg`" />
</BuilderRow>
<BuilderRow label.translate="Text">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-text`" />
</BuilderRow>
<BuilderRow label.translate="Headings">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-headings`" />
<t t-set-slot="collapse">
<t t-foreach="[2, 3, 4, 5, 6]" t-as="j" t-key="j">
<BuilderRow label="`Headings ${j}`">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-h${j}`"/>
</BuilderRow>
</t>
</t>
</BuilderRow>
<BuilderRow label.translate="Links">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-link`" />
</BuilderRow>
<BuilderRow label.translate="Primary Buttons">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-btn-primary`" />
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-btn-primary-border`" />
</BuilderRow>
<BuilderRow label.translate="Secondary Buttons">
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-btn-secondary`" />
<BuilderColorPicker
action="'customizeWebsiteColor'"
actionParam="`o-cc${preset.id}-btn-secondary-border`" />
</BuilderRow>
</t>
</BuilderRow>
</t>
</t>
</BuilderRow>
</BuilderContext>
</t>
</templates>
38 changes: 0 additions & 38 deletions addons/html_builder/static/src/sidebar/theme_tab.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,6 @@
</div>
</div>
</t>

<t t-name="html_builder.ThemeColorsOption">
<BuilderContext preview="false">
TODO
<!--
<we-alert class="o_old_color_system_warning d-none mt-2">
It appears your website is still using the old color system of
Odoo 13.0 in some places. We made sure it is still working but
we recommend you to try to use the new color system, which is
still customizable.
</we-alert>
<we-row class="o_we_theme_colors_selector">
<div class="o_we_theme_colors_selector_group">
<we-title>Main</we-title>
<we-colorpicker data-name="color_1_opt" title="Primary"
data-customize-website-color="" data-color="o-color-1"
data-use-css-color="true" data-selected-tab="custom-colors"/>
<we-colorpicker data-name="color_2_opt" title="Secondary"
data-customize-website-color="" data-color="o-color-2"
data-use-css-color="true" data-selected-tab="custom-colors"/>
<we-colorpicker data-customize-website-color="" data-color="o-color-3"
data-use-css-color="true" data-selected-tab="custom-colors"/>
</div>
<div class="o_we_theme_colors_selector_group">
<we-title>Light &amp; Dark</we-title>
<we-colorpicker data-customize-website-color="" data-color="o-color-4"
data-use-css-color="true" data-selected-tab="custom-colors"/>
<we-colorpicker data-customize-website-color="" data-color="o-color-5"
data-use-css-color="true" data-selected-tab="custom-colors"/>
</div>
<we-select data-img="/website/static/src/img/snippets_options/palette.svg" class="o_we_theme_colors_select" data-variable="color-palettes-name"/>
</we-row>
<we-collapse class="o_we_theme_presets_collapse" string="Color Presets">
</we-collapse>
-->
</BuilderContext>
</t>

<t t-name="html_builder.ThemeWebsiteSettingsOption">
<BuilderContext preview="false">
<BuilderRow label.translate="Theme">
Expand Down
25 changes: 13 additions & 12 deletions addons/html_builder/static/src/sidebar/theme_tab_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { isCSSColor } from "@web/core/utils/colors";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { getCSSVariableValue, isColorCombinationName } from "../utils/utils_css";
import { withSequence } from "@html_editor/utils/resource";
import { ThemeColorsOption } from "./theme_colors_option";

export class ThemeTabPlugin extends Plugin {
static id = "themeTab";
Expand All @@ -15,11 +16,7 @@ export class ThemeTabPlugin extends Plugin {
theme_options: [
withSequence(
10,
this.getThemeOptionBlock(
"theme-colors",
_t("Colors"),
"html_builder.ThemeColorsOption"
)
this.getThemeOptionBlock("theme-colors", _t("Colors"), null, ThemeColorsOption)
),
withSequence(
20,
Expand Down Expand Up @@ -342,25 +339,29 @@ export class ThemeTabPlugin extends Plugin {
}
});
}
getThemeOptionBlock(id, name, template) {
getThemeOptionBlock(id, name, template = null, Component = null) {
// TODO Have a specific kind of options container that takes the specific parameters like name, no element, no selector...
const el = this.document.createElement("div");
el.dataset.name = name;
this.document.body.appendChild(el); // Currently editingElement needs to be isConnected

const option = {
selector: "*",
};
if (template) {
option.template = template;
} else {
option.OptionComponent = Component;
}

return {
id: id,
element: el,
hasOverlayOptions: false,
headerMiddleButton: false,
isClonable: false,
isRemovable: false,
options: [
{
template: template,
selector: "*",
},
],
options: [option],
optionsContainerTopButtons: [],
snippetModel: {},
};
Expand Down

0 comments on commit 1403a48

Please sign in to comment.