diff --git a/awesome_website/__manifest__.py b/awesome_website/__manifest__.py
index 9f34d035002..9c0fe0b3bb8 100644
--- a/awesome_website/__manifest__.py
+++ b/awesome_website/__manifest__.py
@@ -1,31 +1,52 @@
{
- 'name': "Awesome Website",
-
- 'summary': """
+ "name": "Awesome Website",
+ "summary": """
Companion addon for the Odoo JS Framework Training
""",
-
- 'description': """
+ "description": """
Companion addon for the Odoo JS Framework Training
""",
-
- 'author': "Odoo",
- 'website': "https://www.odoo.com",
-
+ "author": "Odoo",
+ "website": "https://www.odoo.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/data/ir_module_category_data.xml
# for the full list
- 'category': 'Tutorials',
- 'version': '0.2',
-
+ "category": "Tutorials",
+ "version": "0.2",
# any module necessary for this one to work correctly
- 'depends': ['website'],
- 'application': True,
- 'installable': True,
- 'data': [
- 'data/images.xml',
+ "depends": ["website"],
+ "application": True,
+ "installable": True,
+ "data": [
+ "data/images.xml",
+ "views/snippets/snippets.xml",
+ "views/snippets/s_image_comparison.xml",
+ "views/snippets/static_banner.xml",
],
- 'assets': {
+ "assets": {
+ "web.assets_frontend": [
+ "awesome_website/static/src/interactions/**/*",
+ "awesome_website/static/src/snippets/**/*",
+ "awesome_website/static/src/components/**/*",
+ ("remove", "awesome_website/static/src/interactions/**/*.edit.*"),
+ ("remove", "awesome_website/static/src/snippets/**/*.edit.*"),
+ ],
+ "website.assets_inside_builder_iframe": [
+ "awesome_website/static/src/snippets/**/*.edit.*",
+ ],
+ "website.website_builder_assets": [
+ "awesome_website/static/src/builder/**/*",
+ ],
+ "web.assets_unit_tests": [
+ "website/static/tests/builder/website_helpers.js",
+ "awesome_website/static/tests/interactions/**/*",
+ "awesome_website/static/tests/builder/**/*",
+ ],
+ "web.assets_unit_tests_setup": [
+ "awesome_website/static/src/interactions/**/*",
+ "awesome_website/static/src/snippets/**/*",
+ "awesome_website/static/src/builder/**/*",
+ ],
},
- 'license': 'AGPL-3'
+ "license": "AGPL-3",
}
diff --git a/awesome_website/static/src/builder/image_comparison_colorslide.xml b/awesome_website/static/src/builder/image_comparison_colorslide.xml
new file mode 100644
index 00000000000..05998f0dba9
--- /dev/null
+++ b/awesome_website/static/src/builder/image_comparison_colorslide.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_website/static/src/components/static_banner.js b/awesome_website/static/src/components/static_banner.js
new file mode 100644
index 00000000000..729bc1d5bdb
--- /dev/null
+++ b/awesome_website/static/src/components/static_banner.js
@@ -0,0 +1,14 @@
+import { Component, xml } from "@odoo/owl";
+import { registry } from "@web/core/registry";
+
+
+export class StaticBanner extends Component {
+ static template = xml`
Hello, !
`
+ static props = {
+ name: {
+ type: String,
+ },
+ };
+}
+
+registry.category("public_components").add("static_banner", StaticBanner);
diff --git a/awesome_website/static/src/interactions/main.js b/awesome_website/static/src/interactions/main.js
index fbcfe5f773b..b8923999c75 100644
--- a/awesome_website/static/src/interactions/main.js
+++ b/awesome_website/static/src/interactions/main.js
@@ -2,14 +2,16 @@ import { registry } from "@web/core/registry";
import { Interaction } from "@web/public/interaction";
class Main extends Interaction {
- /* Interaction's lifecycle methods:
+ static selector = "main";
- setup() { }
- async willStart() { }
- start() { }
- destroy() { }
-
- */
+ dynamicContent = {
+ _root: {
+ "t-out": () => {
+ const now = new Date();
+ return now.toLocaleString('en-US');
+ }
+ }
+ };
}
-registry.category("public.interactions").add("awesome_website.main", Main);
+// registry.category("public.interactions").add("awesome_website.main", Main);
diff --git a/awesome_website/static/src/interactions/mouse_follower.js b/awesome_website/static/src/interactions/mouse_follower.js
new file mode 100644
index 00000000000..5d4e5facc68
--- /dev/null
+++ b/awesome_website/static/src/interactions/mouse_follower.js
@@ -0,0 +1,41 @@
+import { registry } from "@web/core/registry";
+import { Interaction } from "@web/public/interaction";
+
+export class MouseFollower extends Interaction {
+ static selector = "#wrapwrap";
+
+ dynamicSelectors = {
+ ...this.dynamicSelectors,
+ _highlighter: () => this.highlighter,
+ }
+
+ dynamicContent = {
+ _root: {
+ "t-on-pointermove": this.debounced(this.onPointerMove, 5),
+ },
+ _highlighter: {
+ "t-att-style": () => ({
+ top: `${this.my}px`,
+ left: `${this.mx}px`,
+ }),
+ },
+ };
+
+ setup() {
+ this.mx = 0;
+ this.my = 0;
+ this.highlighter = document.createElement("div");
+ this.highlighter.classList.add("x_mouse_follower");
+ }
+
+ start() {
+ this.insert(this.highlighter);
+ }
+
+ onPointerMove(ev) {
+ this.mx = ev.clientX;
+ this.my = ev.clientY;
+ }
+}
+
+registry.category("public.interactions").add("awesome_website.mouse_follower", MouseFollower);
diff --git a/awesome_website/static/src/snippets/s_image_comparison/000.edit.scss b/awesome_website/static/src/snippets/s_image_comparison/000.edit.scss
index d01a0fe645b..2a36d221cce 100644
--- a/awesome_website/static/src/snippets/s_image_comparison/000.edit.scss
+++ b/awesome_website/static/src/snippets/s_image_comparison/000.edit.scss
@@ -1,5 +1,23 @@
.o_image_comparison_container {
+ .o_image_comparison_horizontal & {
+ --slider-left: var(--slider-img-left);
+ --slider-right: calc(var(--slider-left) + 1%);
+ --slider-top: 0;
+ --slider-bottom: 100%;
+
+ .o_rtl & {
+ --slider-right: var(--slider-img-right);
+ --slider-left: calc(var(--slider-right) - 1%);
+ }
+ }
+ .o_image_comparison_vertical & {
+ --slider-top: var(--slider-img-top);
+ --slider-bottom: calc(var(--slider-top) + 1%);
+ --slider-left: var(--slider-img-left);
+ --slider-right: var(--slider-img-right);
+ }
.o_image_comparison_slider {
+ pointer-events: none;
clip-path: rect(0 calc(var(--slider-position) + 1%) 100% var(--slider-position));
.o_rtl & {
diff --git a/awesome_website/static/src/snippets/s_image_comparison/000.scss b/awesome_website/static/src/snippets/s_image_comparison/000.scss
index 10edad69f8d..5886e865f1e 100644
--- a/awesome_website/static/src/snippets/s_image_comparison/000.scss
+++ b/awesome_website/static/src/snippets/s_image_comparison/000.scss
@@ -1,6 +1,41 @@
.o_image_comparison_container {
--slider-position: 50%;
+ .o_image_comparison_horizontal & {
+ --handle-left: var(--slider-position);
+ --handle-top: 50%;
+ --slider-img-left: var(--slider-position);
+ --slider-img-right: 100%;
+ --slider-img-top: 0;
+ --slider-cursor: ew-resize;
+ --slider-height: 100vh;
+ --slider-width: 4px;
+ --slider-margin-inline: -2px;
+ --slider-margin-block: 0;
+ --slider-writing-mode: horizontal-tb;
+ --slider-transform: unset;
+
+ .o_rtl & {
+ --slider-img-left: 0;
+ --slider-img-right: calc(100% - var(--slider-position));
+ }
+ }
+ .o_image_comparison_vertical & {
+ --handle-left: 50%;
+ --handle-top: var(--slider-position);
+ --slider-img-top: var(--slider-position);
+ --slider-img-left: 0;
+ --slider-img-right: 100%;
+ --slider-cursor: ns-resize;
+ --slider-height: 4px;
+ --slider-width: 100vw;
+ --slider-margin-inline: 0;
+ --slider-margin-block: -2px;
+ --slider-writing-mode: vertical-rl;
+ --slider-transform: scaleY(-1);
+ }
+
+
img {
grid-area: 1 / 1;
width: 100%;
diff --git a/awesome_website/static/src/snippets/s_image_comparison/image_comparison.edit.js b/awesome_website/static/src/snippets/s_image_comparison/image_comparison.edit.js
new file mode 100644
index 00000000000..f49fc567483
--- /dev/null
+++ b/awesome_website/static/src/snippets/s_image_comparison/image_comparison.edit.js
@@ -0,0 +1,12 @@
+import { registry } from "@web/core/registry";
+import { ImageComparison } from "./image_comparison";
+
+const ImageComparisonEdit = (I) =>
+ class extends I {
+ onSliderSlide() { }
+ };
+
+registry.category("public.interactions.edit").add("awesome_website.image_comparison", {
+ Interaction: ImageComparison,
+ mixin: ImageComparisonEdit,
+});
diff --git a/awesome_website/static/src/snippets/s_image_comparison/image_comparison.js b/awesome_website/static/src/snippets/s_image_comparison/image_comparison.js
new file mode 100644
index 00000000000..4c18ba0808c
--- /dev/null
+++ b/awesome_website/static/src/snippets/s_image_comparison/image_comparison.js
@@ -0,0 +1,28 @@
+import { registry } from "@web/core/registry";
+import { Interaction } from "@web/public/interaction";
+
+export class ImageComparison extends Interaction {
+ static selector = ".s_image_comparison";
+
+ dynamicContent = {
+ ".o_image_comparison_slider": {
+ "t-on-input": this.debounced(this.onSliderSlide, 5)
+ },
+ ".o_image_comparison_container": {
+ "t-att-style": () => ({
+ "--slider-position": this.sliderPosition,
+ }),
+ },
+ };
+
+ setup() {
+ this.sliderPosition = "50%";
+ }
+
+ onSliderSlide() {
+ let value = document.querySelector(".o_image_comparison_slider").value;
+ this.sliderPosition = `${value}%`;
+ }
+}
+
+registry.category("public.interactions").add("awesome_website.image_comparison", ImageComparison);
diff --git a/awesome_website/static/tests/builder/image_comparison_colorslide.test.js b/awesome_website/static/tests/builder/image_comparison_colorslide.test.js
new file mode 100644
index 00000000000..f2bc067b296
--- /dev/null
+++ b/awesome_website/static/tests/builder/image_comparison_colorslide.test.js
@@ -0,0 +1,30 @@
+import { expect, manuallyDispatchProgrammaticEvent, test } from "@odoo/hoot";
+import { defineWebsiteModels, setupWebsiteBuilderWithSnippet } from "@website/../tests/builder/website_helpers";
+import { contains, defineStyle } from "@web/../tests/web_test_helpers";
+import { animationFrame, queryOne } from "@odoo/hoot-dom";
+
+defineWebsiteModels();
+
+test("Change slider handle color using the custom builder option", async () => {
+ defineStyle(`* { transition: none !important; }`);
+ await setupWebsiteBuilderWithSnippet("s_image_comparison", { loadIframeBundles: true });
+
+ await contains(":iframe .s_image_comparison").click();
+
+ expect("[data-label='Pick Slider Color']").toHaveCount(1);
+
+ await contains("[data-label='Pick Slider Color'] .o_we_color_preview").click();
+
+ await contains(".o-hb-colorpicker-popover .custom-tab").click();
+ await animationFrame();
+
+ const hexInput = queryOne(".o-hb-colorpicker-popover input[data-color-method='hex']");
+ expect(hexInput).toBeDisplayed();
+ hexInput.value = "#ff0000";
+ await manuallyDispatchProgrammaticEvent(hexInput, "input", { bubbles: true });
+ await animationFrame();
+
+ expect(":iframe .s_image_comparison .o_image_comparison_handle").toHaveStyle({
+ "background-color": "rgb(255, 0, 0)",
+ });
+});
diff --git a/awesome_website/static/tests/interactions/image_comparison.test.js b/awesome_website/static/tests/interactions/image_comparison.test.js
new file mode 100644
index 00000000000..fe7189e625d
--- /dev/null
+++ b/awesome_website/static/tests/interactions/image_comparison.test.js
@@ -0,0 +1,34 @@
+import { advanceTime, expect, manuallyDispatchProgrammaticEvent, queryOne, test } from "@odoo/hoot";
+import { setupInteractionWhiteList, startInteractions } from "@web/../tests/public/helpers";
+import { defineStyle } from "@web/../tests/web_test_helpers";
+
+setupInteractionWhiteList("awesome_website.image_comparison");
+
+test("image comparison slider should update the value of the input.", async () => {
+ defineStyle(`* { transition: none !important; }`);
+ const { core } = await startInteractions(`
+
+
+
+

+

+
+
+
+
+
+ `);
+
+ expect(core.interactions).toHaveLength(1);
+ expect("input").toHaveStyle({ "--slider-position": "50%" });
+
+ for (var input_value = 10; input_value <= 100; input_value += 10) {
+ let input = queryOne("input");
+ input.value = `${input_value}`;
+ await manuallyDispatchProgrammaticEvent(input, "input", { bubbles: true });
+ await advanceTime(5);
+
+ expect("input").toHaveStyle({ "--slider-position": `${input_value}%` });
+ }
+
+});
diff --git a/awesome_website/views/snippets/s_image_comparison.xml b/awesome_website/views/snippets/s_image_comparison.xml
index a946cc01a03..38e2f7fe30d 100644
--- a/awesome_website/views/snippets/s_image_comparison.xml
+++ b/awesome_website/views/snippets/s_image_comparison.xml
@@ -1,8 +1,15 @@
-
-
-
-
-
+
+
+
+
+

+

+
+
+
+
+
+
diff --git a/awesome_website/views/snippets/snippets.xml b/awesome_website/views/snippets/snippets.xml
new file mode 100644
index 00000000000..4be06cc6151
--- /dev/null
+++ b/awesome_website/views/snippets/snippets.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ image comparison, before, after, compare, side-by-side, photo, picture, contrast, split, match, slider
+
+
+
+
+ static, banner, static banner, hello
+
+
+
+
diff --git a/awesome_website/views/snippets/static_banner.xml b/awesome_website/views/snippets/static_banner.xml
new file mode 100644
index 00000000000..be29fde2a4f
--- /dev/null
+++ b/awesome_website/views/snippets/static_banner.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+