diff --git a/web_responsive/README.rst b/web_responsive/README.rst index e0c580845..8ef85d0b9 100644 --- a/web_responsive/README.rst +++ b/web_responsive/README.rst @@ -17,13 +17,13 @@ Web Responsive :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github - :target: https://github.com/OCA/web/tree/16.0/web_responsive + :target: https://github.com/OCA/web/tree/17.0/web_responsive :alt: OCA/web .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_responsive + :target: https://translation.odoo-community.org/projects/web-17-0/web-17-0-web_responsive :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=17.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -32,75 +32,76 @@ This module adds responsiveness to web backend. **Features for all devices**: -* New navigation with the fullscreen app menu +- New navigation with the fullscreen app menu - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appmenu.gif + |image| -* Quick menu search inside the app menu +- Quick menu search inside the app menu - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appsearch.gif + |image1| -* Sticky header & footer in list view +- Sticky header & footer in list view - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/listview.gif + |image2| -* Sticky statusbar in form view +- Sticky statusbar in form view - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/formview.gif + |image3| -* Bigger checkboxes in list view +- Bigger checkboxes in list view - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/listview.gif + |image4| +**Features for mobile**: \* View type picker dropdown displays +comfortably -**Features for mobile**: -* View type picker dropdown displays comfortably +- Control panel buttons use icons to save space. - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/viewtype.gif + |image5| -* Control panel buttons use icons to save space. +- Followers and send button is displayed on mobile. Avatar is hidden. - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/form_buttons.gif + |image6| -* Search panel is collapsed to mobile version on small screens. - - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/search_panel.gif - -* Followers and send button is displayed on mobile. Avatar is hidden. - - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/chatter.gif - -* Big inputs on form in edit mode +- Big inputs on form in edit mode **Features for desktop computers**: -* Keyboard shortcuts for easier navigation, - **using `Alt + Shift + [NUM]`** combination instead of - just `Alt + [NUM]` to avoid conflict with Firefox Tab switching. - Standard Odoo keyboard hotkeys changed to be more intuitive or - accessible by fingers of one hand. - F.x. `Alt + S` for `Save` +- Keyboard shortcuts for easier navigation, **using \`Alt + Shift + + [NUM]\`** combination instead of just Alt + [NUM] to avoid conflict + with Firefox Tab switching. Standard Odoo keyboard hotkeys changed to + be more intuitive or accessible by fingers of one hand. F.x. Alt + S + for Save - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/shortcuts.gif + |image7| -* Autofocus on search menu box when opening the app menu +- Autofocus on search menu box when opening the app menu - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appsearch.gif + |image8| -* Full width form sheets +- When the chatter is on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still + put it on full width preview clicking on the new maximize button. - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/formview.gif + |image9| -* When the chatter is on the side part, the document viewer fills that - part for side-by-side reading instead of full screen. You can still put it on full - width preview clicking on the new maximize button. +- When the user chooses to send a public message the color of the + composer is different from the one when the message is an internal + log. - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/document_viewer.gif + |image10| -* When the user chooses to send a public message the color of the composer is different - from the one when the message is an internal log. - - .. image:: https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/chatter-colors.gif +.. |image| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appmenu.gif +.. |image1| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appsearch.gif +.. |image2| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/listview.gif +.. |image3| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/formview.gif +.. |image4| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/listview.gif +.. |image5| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/form_buttons.gif +.. |image6| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/chatter.png +.. |image7| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/shortcuts.gif +.. |image8| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appsearch.gif +.. |image9| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/document_viewer.gif +.. |image10| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/chatter-colors.png **Table of contents** @@ -112,15 +113,15 @@ Usage The following keyboard shortcuts are implemented: -* Navigate app search results - Arrow keys -* Choose app result - ``Enter`` -* ``Esc`` to close app drawer +- Navigate app search results - Arrow keys +- Choose app result - ``Enter`` +- ``Esc`` to close app drawer Known issues / Roadmap ====================== -* App navigation with keyboard. -* Handle long titles on forms in a better way +- App navigation with keyboard. +- Handle long titles on forms in a better way Bug Tracker =========== @@ -128,7 +129,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -136,7 +137,7 @@ Credits ======= Authors -~~~~~~~ +------- * LasLabs * Tecnativa @@ -144,22 +145,33 @@ Authors * Onestein Contributors -~~~~~~~~~~~~ +------------ -* Dave Lasley -* Jairo Llopis -* `Onestein `_: - * Dennis Sluijk - * Anjeel Haria -* Sergio Teruel -* Alexandre Díaz -* Mathias Markl -* Iván Todorovich -* Sergey Shebanin -* David Vidal +- Dave Lasley + +- Jairo Llopis + +- `Onestein `__: + + - Dennis Sluijk + - Anjeel Haria + +- Sergio Teruel + +- Alexandre Díaz + +- Mathias Markl + +- Iván Todorovich + +- Sergey Shebanin + +- David Vidal + +- Taras Shabaranskyi Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -185,6 +197,6 @@ Current `maintainers `__: |maintainer-Yajo| |maintainer-Tardo| |maintainer-SplashS| -This module is part of the `OCA/web `_ project on GitHub. +This module is part of the `OCA/web `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_responsive/__init__.py b/web_responsive/__init__.py index e69de29bb..f115f756a 100644 --- a/web_responsive/__init__.py +++ b/web_responsive/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import models diff --git a/web_responsive/__manifest__.py b/web_responsive/__manifest__.py index ee217d38a..1fbbdad44 100644 --- a/web_responsive/__manifest__.py +++ b/web_responsive/__manifest__.py @@ -3,12 +3,13 @@ # Copyright 2018-2019 Tecnativa - Alexandre Díaz # Copyright 2021 ITerra - Sergey Shebanin # Copyright 2023 Onestein - Anjeel Haria +# Copyright 2023 Taras Shabaranskyi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). { "name": "Web Responsive", "summary": "Responsive web client, community-supported", - "version": "16.0.1.2.3", + "version": "17.0.1.0.0", "category": "Website", "website": "https://github.com/OCA/web", "author": "LasLabs, Tecnativa, ITerra, Onestein, " @@ -19,35 +20,45 @@ "development_status": "Production/Stable", "maintainers": ["Yajo", "Tardo", "SplashS"], "excludes": ["web_enterprise"], - "data": ["views/web.xml"], + "data": [ + "views/res_users_views.xml", + ], "assets": { + "web._assets_primary_variables": { + "/web_responsive/static/src/legacy/scss/form_variable.scss", + "/web_responsive/static/src/legacy/scss/primary_variable.scss", + }, "web.assets_backend": [ - "/web_responsive/static/src/views/form/form_controller.esm.js", + "web_responsive/static/src/lib/fuse/fuse.basic.min.js", "/web_responsive/static/src/legacy/scss/web_responsive.scss", - "/web_responsive/static/src/legacy/js/web_responsive.js", - "/web_responsive/static/src/components/ui_context.esm.js", - "/web_responsive/static/src/components/apps_menu/apps_menu.scss", - "/web_responsive/static/src/components/apps_menu/apps_menu.esm.js", - "/web_responsive/static/src/components/control_panel/control_panel.scss", - "/web_responsive/static/src/components/control_panel/control_panel.esm.js", - "/web_responsive/static/src/components/search_panel/search_panel.scss", - "/web_responsive/static/src/components/search_panel/search_panel.esm.js", - "/web_responsive/static/src/components/hotkey/hotkey.scss", + "/web_responsive/static/src/legacy/scss/big_boxes.scss", + "/web_responsive/static/src/legacy/scss/list_sticky_header.scss", + "/web_responsive/static/src/legacy/js/web_responsive.esm.js", "/web_responsive/static/src/legacy/xml/form_buttons.xml", - "/web_responsive/static/src/components/apps_menu/apps_menu.xml", - "/web_responsive/static/src/components/control_panel/control_panel.xml", - "/web_responsive/static/src/components/search_panel/search_panel.xml", - "/web_responsive/static/src/components/hotkey/hotkey.xml", - "/web_responsive/static/src/components/chatter_topbar/chatter_topbar.esm.js", - "/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml", - "/web_responsive/static/src/components/attachment_viewer/attachment_viewer.scss", - "/web_responsive/static/src/components/attachment_viewer/attachment_viewer.esm.js", - "/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml", + "/web_responsive/static/src/legacy/xml/custom_favorite_item.xml", + "/web_responsive/static/src/components/apps_menu_tools.esm.js", + "/web_responsive/static/src/components/apps_menu/*", + "/web_responsive/static/src/components/apps_menu_item/*", + "/web_responsive/static/src/components/menu_canonical_searchbar/*", + "/web_responsive/static/src/components/menu_odoo_searchbar/*", + "/web_responsive/static/src/components/menu_fuse_searchbar/*", + "/web_responsive/static/src/components/menu_searchbar/*", + "/web_responsive/static/src/components/hotkey/*", + "/web_responsive/static/src/components/file_viewer/*", + "/web_responsive/static/src/components/chatter/*", + "/web_responsive/static/src/components/control_panel/*", + "/web_responsive/static/src/components/command_palette/*", "/web_responsive/static/src/views/form/form_controller.scss", + "/web_responsive/static/src/views/form/status_bar_buttons.xml", + "/web_responsive/static/src/views/form/form_statusbar.scss", ], "web.assets_tests": [ "/web_responsive/static/tests/test_patch.js", ], + "web.qunit_suite_tests": [ + "/web_responsive/static/tests/apps_menu_tests.esm.js", + "/web_responsive/static/tests/apps_menu_search_tests.esm.js", + ], }, "sequence": 1, } diff --git a/web_responsive/i18n/uk_UA.po b/web_responsive/i18n/uk_UA.po new file mode 100644 index 000000000..20b265b55 --- /dev/null +++ b/web_responsive/i18n/uk_UA.po @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0-20231123\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-11-25 15:27+0000\n" +"PO-Revision-Date: 2023-11-25 15:27+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/views/form/status_bar_buttons.xml:0 +#, python-format +msgid "Action" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "App Icon" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Головне меню" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter/chatter.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Збільшити" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Згорнути" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Новий" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "Nothing to show" +msgstr "Нема чого показати" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Зберегти" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Пошук..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter/chatter.xml:0 +#, python-format +msgid "Send message" +msgstr "Надіслати повідомлення" diff --git a/web_responsive/models/__init__.py b/web_responsive/models/__init__.py new file mode 100644 index 000000000..c6b5178dd --- /dev/null +++ b/web_responsive/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import res_users +from . import ir_http diff --git a/web_responsive/models/ir_http.py b/web_responsive/models/ir_http.py new file mode 100644 index 000000000..98fff28ac --- /dev/null +++ b/web_responsive/models/ir_http.py @@ -0,0 +1,19 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import models + + +class IrHttp(models.AbstractModel): + _inherit = "ir.http" + + def session_info(self): + session = super().session_info() + user = self.env.user + return { + **session, + "apps_menu": { + "search_type": user.apps_menu_search_type, + "theme": user.apps_menu_theme, + }, + } diff --git a/web_responsive/models/res_users.py b/web_responsive/models/res_users.py new file mode 100644 index 000000000..7b67ccaaa --- /dev/null +++ b/web_responsive/models/res_users.py @@ -0,0 +1,26 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + apps_menu_search_type = fields.Selection( + [ + ("canonical", "Canonical"), + ("fuse", "Fuse"), + ("command_palette", "Command Palette"), + ], + default="canonical", + required=True, + ) + apps_menu_theme = fields.Selection( + [ + ("milk", "Milk"), + ("community", "Community"), + ], + default="milk", + required=True, + ) diff --git a/web_responsive/pyproject.toml b/web_responsive/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/web_responsive/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_responsive/readme/CONTRIBUTORS.md b/web_responsive/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..dc659b2fa --- /dev/null +++ b/web_responsive/readme/CONTRIBUTORS.md @@ -0,0 +1,21 @@ +- Dave Lasley \<\> + +- Jairo Llopis \<\> + +- [Onestein](https://www.onestein.nl): + - Dennis Sluijk \<\> + - Anjeel Haria + +- Sergio Teruel \<\> + +- Alexandre Díaz \<\> + +- Mathias Markl \<\> + +- Iván Todorovich \<\> + +- Sergey Shebanin \<\> + +- David Vidal \<\> + +- Taras Shabaranskyi \<\> diff --git a/web_responsive/readme/CONTRIBUTORS.rst b/web_responsive/readme/CONTRIBUTORS.rst deleted file mode 100644 index ade0547bc..000000000 --- a/web_responsive/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,11 +0,0 @@ -* Dave Lasley -* Jairo Llopis -* `Onestein `_: - * Dennis Sluijk - * Anjeel Haria -* Sergio Teruel -* Alexandre Díaz -* Mathias Markl -* Iván Todorovich -* Sergey Shebanin -* David Vidal diff --git a/web_responsive/readme/DESCRIPTION.md b/web_responsive/readme/DESCRIPTION.md new file mode 100644 index 000000000..d7e22a902 --- /dev/null +++ b/web_responsive/readme/DESCRIPTION.md @@ -0,0 +1,62 @@ +This module adds responsiveness to web backend. + +**Features for all devices**: + +- New navigation with the fullscreen app menu + + ![image](../static/img/appmenu.gif) + +- Quick menu search inside the app menu + + ![image](../static/img/appsearch.gif) + +- Sticky header & footer in list view + + ![image](../static/img/listview.gif) + +- Sticky statusbar in form view + + ![image](../static/img/formview.gif) + +- Bigger checkboxes in list view + + ![image](../static/img/listview.gif) + +**Features for mobile**: \* View type picker dropdown displays +comfortably + +- Control panel buttons use icons to save space. + + ![image](../static/img/form_buttons.gif) + +- Followers and send button is displayed on mobile. Avatar is hidden. + + ![image](../static/img/chatter.png) + +- Big inputs on form in edit mode + +**Features for desktop computers**: + +- Keyboard shortcuts for easier navigation, **using \`Alt + Shift + + \[NUM\]\`** combination instead of just Alt + \[NUM\] to avoid + conflict with Firefox Tab switching. Standard Odoo keyboard hotkeys + changed to be more intuitive or accessible by fingers of one hand. + F.x. Alt + S for Save + + ![image](../static/img/shortcuts.gif) + +- Autofocus on search menu box when opening the app menu + + ![image](../static/img/appsearch.gif) + +- When the chatter is on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still + put it on full width preview clicking on the new maximize button. + + ![image](../static/img/document_viewer.gif) + +- When the user chooses to send a public message the color of the + composer is different from the one when the message is an internal + log. + + ![image](../static/img/chatter-colors.png) diff --git a/web_responsive/readme/DESCRIPTION.rst b/web_responsive/readme/DESCRIPTION.rst deleted file mode 100644 index f4f800de4..000000000 --- a/web_responsive/readme/DESCRIPTION.rst +++ /dev/null @@ -1,73 +0,0 @@ -This module adds responsiveness to web backend. - -**Features for all devices**: - -* New navigation with the fullscreen app menu - - .. image:: ../static/img/appmenu.gif - -* Quick menu search inside the app menu - - .. image:: ../static/img/appsearch.gif - -* Sticky header & footer in list view - - .. image:: ../static/img/listview.gif - -* Sticky statusbar in form view - - .. image:: ../static/img/formview.gif - -* Bigger checkboxes in list view - - .. image:: ../static/img/listview.gif - - -**Features for mobile**: -* View type picker dropdown displays comfortably - - .. image:: ../static/img/viewtype.gif - -* Control panel buttons use icons to save space. - - .. image:: ../static/img/form_buttons.gif - -* Search panel is collapsed to mobile version on small screens. - - .. image:: ../static/img/search_panel.gif - -* Followers and send button is displayed on mobile. Avatar is hidden. - - .. image:: ../static/img/chatter.gif - -* Big inputs on form in edit mode - -**Features for desktop computers**: - -* Keyboard shortcuts for easier navigation, - **using `Alt + Shift + [NUM]`** combination instead of - just `Alt + [NUM]` to avoid conflict with Firefox Tab switching. - Standard Odoo keyboard hotkeys changed to be more intuitive or - accessible by fingers of one hand. - F.x. `Alt + S` for `Save` - - .. image:: ../static/img/shortcuts.gif - -* Autofocus on search menu box when opening the app menu - - .. image:: ../static/img/appsearch.gif - -* Full width form sheets - - .. image:: ../static/img/formview.gif - -* When the chatter is on the side part, the document viewer fills that - part for side-by-side reading instead of full screen. You can still put it on full - width preview clicking on the new maximize button. - - .. image:: ../static/img/document_viewer.gif - -* When the user chooses to send a public message the color of the composer is different - from the one when the message is an internal log. - - .. image:: ../static/img/chatter-colors.gif diff --git a/web_responsive/readme/ROADMAP.md b/web_responsive/readme/ROADMAP.md new file mode 100644 index 000000000..5772fcad3 --- /dev/null +++ b/web_responsive/readme/ROADMAP.md @@ -0,0 +1,2 @@ +- App navigation with keyboard. +- Handle long titles on forms in a better way diff --git a/web_responsive/readme/ROADMAP.rst b/web_responsive/readme/ROADMAP.rst deleted file mode 100644 index f27d826e4..000000000 --- a/web_responsive/readme/ROADMAP.rst +++ /dev/null @@ -1,2 +0,0 @@ -* App navigation with keyboard. -* Handle long titles on forms in a better way diff --git a/web_responsive/readme/USAGE.md b/web_responsive/readme/USAGE.md new file mode 100644 index 000000000..4b2b6b3cc --- /dev/null +++ b/web_responsive/readme/USAGE.md @@ -0,0 +1,5 @@ +The following keyboard shortcuts are implemented: + +- Navigate app search results - Arrow keys +- Choose app result - `Enter` +- `Esc` to close app drawer diff --git a/web_responsive/readme/USAGE.rst b/web_responsive/readme/USAGE.rst deleted file mode 100644 index ef87cbe59..000000000 --- a/web_responsive/readme/USAGE.rst +++ /dev/null @@ -1,5 +0,0 @@ -The following keyboard shortcuts are implemented: - -* Navigate app search results - Arrow keys -* Choose app result - ``Enter`` -* ``Esc`` to close app drawer diff --git a/web_responsive/static/description/index.html b/web_responsive/static/description/index.html index 99b5a2334..94d762b35 100644 --- a/web_responsive/static/description/index.html +++ b/web_responsive/static/description/index.html @@ -369,68 +369,59 @@ ul.auto-toc { !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:9b3ae1467041b443396d6062ed0af40d96c2fa5e97cbce6b17e7daa93a3ee53f !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Production/Stable License: LGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

Production/Stable License: LGPL-3 OCA/web Translate me on Weblate Try me on Runboat

This module adds responsiveness to web backend.

Features for all devices:

  • New navigation with the fullscreen app menu

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appmenu.gif +

    image

  • Quick menu search inside the app menu

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appsearch.gif +

    image1

  • Sticky header & footer in list view

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/listview.gif +

    image2

  • Sticky statusbar in form view

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/formview.gif +

    image3

  • Bigger checkboxes in list view

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/listview.gif +

    image4

-

Features for mobile: -* View type picker dropdown displays comfortably

-
-https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/viewtype.gif -
+

Features for mobile: * View type picker dropdown displays +comfortably

  • Control panel buttons use icons to save space.

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/form_buttons.gif -
  • -
  • Search panel is collapsed to mobile version on small screens.

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/search_panel.gif +

    image5

  • Followers and send button is displayed on mobile. Avatar is hidden.

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/chatter.gif +

    image6

  • Big inputs on form in edit mode

Features for desktop computers:

    -
  • Keyboard shortcuts for easier navigation, -using `Alt + Shift + [NUM]` combination instead of -just Alt + [NUM] to avoid conflict with Firefox Tab switching. -Standard Odoo keyboard hotkeys changed to be more intuitive or -accessible by fingers of one hand. -F.x. Alt + S for Save

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/shortcuts.gif +
  • Keyboard shortcuts for easier navigation, using `Alt + Shift + +[NUM]` combination instead of just Alt + [NUM] to avoid conflict +with Firefox Tab switching. Standard Odoo keyboard hotkeys changed to +be more intuitive or accessible by fingers of one hand. F.x. Alt + S +for Save

    +

    image7

  • Autofocus on search menu box when opening the app menu

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/appsearch.gif -
  • -
  • Full width form sheets

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/formview.gif +

    image8

  • When the chatter is on the side part, the document viewer fills that -part for side-by-side reading instead of full screen. You can still put it on full -width preview clicking on the new maximize button.

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/document_viewer.gif +part for side-by-side reading instead of full screen. You can still +put it on full width preview clicking on the new maximize button.

    +

    image9

  • -
  • When the user chooses to send a public message the color of the composer is different -from the one when the message is an internal log.

    -https://raw.githubusercontent.com/OCA/web/16.0/web_responsive/static/img/chatter-colors.gif +
  • When the user chooses to send a public message the color of the +composer is different from the one when the message is an internal +log.

    +

    image10

Table of contents

@@ -468,7 +459,7 @@ from the one when the message is an internal log.

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.

+feedback.

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

@@ -487,14 +478,10 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
@@ -513,7 +501,7 @@ mission is to support the collaborative development of Odoo features and promote its widespread use.

Current maintainers:

Yajo Tardo SplashS

-

This module is part of the OCA/web project on GitHub.

+

This module is part of the OCA/web project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/web_responsive/static/img/appmenu.gif b/web_responsive/static/img/appmenu.gif index 697368242..9cb67bf1e 100644 Binary files a/web_responsive/static/img/appmenu.gif and b/web_responsive/static/img/appmenu.gif differ diff --git a/web_responsive/static/img/appsearch.gif b/web_responsive/static/img/appsearch.gif index 4817916b3..412fc8944 100644 Binary files a/web_responsive/static/img/appsearch.gif and b/web_responsive/static/img/appsearch.gif differ diff --git a/web_responsive/static/img/chatter-colors.gif b/web_responsive/static/img/chatter-colors.gif deleted file mode 100644 index 0720a263c..000000000 Binary files a/web_responsive/static/img/chatter-colors.gif and /dev/null differ diff --git a/web_responsive/static/img/chatter-colors.png b/web_responsive/static/img/chatter-colors.png new file mode 100644 index 000000000..e07af30d2 Binary files /dev/null and b/web_responsive/static/img/chatter-colors.png differ diff --git a/web_responsive/static/img/chatter.gif b/web_responsive/static/img/chatter.gif deleted file mode 100644 index c638dbeba..000000000 Binary files a/web_responsive/static/img/chatter.gif and /dev/null differ diff --git a/web_responsive/static/img/chatter.png b/web_responsive/static/img/chatter.png new file mode 100644 index 000000000..23182827f Binary files /dev/null and b/web_responsive/static/img/chatter.png differ diff --git a/web_responsive/static/img/form_buttons.gif b/web_responsive/static/img/form_buttons.gif index c1a2e5986..93f989722 100644 Binary files a/web_responsive/static/img/form_buttons.gif and b/web_responsive/static/img/form_buttons.gif differ diff --git a/web_responsive/static/img/listview.gif b/web_responsive/static/img/listview.gif index 95ace8d3b..96ed91cf3 100644 Binary files a/web_responsive/static/img/listview.gif and b/web_responsive/static/img/listview.gif differ diff --git a/web_responsive/static/img/viewtype.gif b/web_responsive/static/img/viewtype.gif deleted file mode 100644 index 058859059..000000000 Binary files a/web_responsive/static/img/viewtype.gif and /dev/null differ diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.esm.js b/web_responsive/static/src/components/apps_menu/apps_menu.esm.js index 9044b5b80..b9c9e3e0b 100644 --- a/web_responsive/static/src/components/apps_menu/apps_menu.esm.js +++ b/web_responsive/static/src/components/apps_menu/apps_menu.esm.js @@ -2,64 +2,44 @@ /* Copyright 2018 Tecnativa - Jairo Llopis * Copyright 2021 ITerra - Sergey Shebanin * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ +import {Component, useState} from "@odoo/owl"; +import {session} from "@web/session"; +import {useBus, useService} from "@web/core/utils/hooks"; +import {AppMenuItem} from "@web_responsive/components/apps_menu_item/apps_menu_item.esm"; +import {AppsMenuSearchBar} from "@web_responsive/components/menu_searchbar/searchbar.esm"; import {NavBar} from "@web/webclient/navbar/navbar"; -import {useAutofocus, useBus, useService} from "@web/core/utils/hooks"; -import {useHotkey} from "@web/core/hotkeys/hotkey_hook"; -import {scrollTo} from "@web/core/utils/scrolling"; -import {debounce} from "@web/core/utils/timing"; -import {fuzzyLookup} from "@web/core/utils/search"; import {WebClient} from "@web/webclient/webclient"; -import {patch} from "web.utils"; -import {escapeRegExp} from "@web/core/utils/strings"; - -const {Component, useState, onPatched, onWillPatch} = owl; +import {patch} from "@web/core/utils/patch"; +import {useHotkey} from "@web/core/hotkeys/hotkey_hook"; // Patch WebClient to show AppsMenu instead of default app -patch(WebClient.prototype, "web_responsive.DefaultAppsMenu", { +patch(WebClient.prototype, { setup() { - this._super(); + super.setup(); useBus(this.env.bus, "APPS_MENU:STATE_CHANGED", ({detail: state}) => { document.body.classList.toggle("o_apps_menu_opened", state); }); }, }); -/** - * @extends Dropdown - */ export class AppsMenu extends Component { setup() { super.setup(); this.state = useState({open: false}); + this.theme = session.apps_menu.theme || "milk"; this.menuService = useService("menu"); useBus(this.env.bus, "ACTION_MANAGER:UI-UPDATED", () => { - this.setOpenState(false, false); + this.setOpenState(false); }); this._setupKeyNavigation(); } - setOpenState(open_state, from_home_menu_click) { + + setOpenState(open_state) { this.state.open = open_state; - // Load home page with proper systray when opening it from website - if (from_home_menu_click) { - var currentapp = this.menuService.getCurrentApp(); - if (currentapp && currentapp.name == "Website") { - if (window.location.pathname != "/web") { - const icon = $( - document.querySelector(".o_navbar_apps_menu button > i") - ); - icon.removeClass("fa fa-th-large").append( - $("", {class: "fa fa-spin fa-spinner"}) - ); - } - window.location.href = "/web#home"; - } else { - this.env.bus.trigger("APPS_MENU:STATE_CHANGED", open_state); - } - } else { - this.env.bus.trigger("APPS_MENU:STATE_CHANGED", open_state); - } + this.env.bus.trigger("APPS_MENU:STATE_CHANGED", open_state); } /** @@ -103,18 +83,18 @@ export class AppsMenu extends Component { } _onWindowKeydown(direction) { - const focusableInputElements = document.querySelectorAll(`.o_app`); + const focusableInputElements = document.querySelectorAll(".o-app-menu-item"); if (focusableInputElements.length) { const focusable = [...focusableInputElements]; const index = focusable.indexOf(document.activeElement); let nextIndex = 0; - if (direction == "prev" && index >= 0) { + if (direction === "prev" && index >= 0) { if (index > 0) { nextIndex = index - 1; } else { nextIndex = focusable.length - 1; } - } else if (direction == "next") { + } else if (direction === "next") { if (index + 1 < focusable.length) { nextIndex = index + 1; } else { @@ -124,212 +104,20 @@ export class AppsMenu extends Component { focusableInputElements[nextIndex].focus(); } } -} -/** - * Reduce menu data to a searchable format understandable by fuzzyLookup - * - * `menuService.getMenuAsTree()` returns array in a format similar to this (only - * relevant data is shown): - * - * ```js - * // This is a menu entry: - * { - * actionID: 12, // Or `false` - * name: "Actions", - * childrenTree: {0: {...}, 1: {...}}}, // List of inner menu entries - * // in the same format or `undefined` - * } - * ``` - * - * This format is very hard to process to search matches, and it would - * slow down the search algorithm, so we reduce it with this method to be - * able to later implement a simpler search. - * - * @param {Object} memo - * Reference to current result object, passed on recursive calls. - * - * @param {Object} menu - * A menu entry, as described above. - * - * @returns {Object} - * Reduced object, without entries that have no action, and with a - * format like this: - * - * ```js - * { - * "Discuss": {Menu entry Object}, - * "Settings": {Menu entry Object}, - * "Settings/Technical/Actions/Actions": {Menu entry Object}, - * ... - * } - * ``` - */ -function findNames(memo, menu) { - if (menu.actionID) { - var result = ""; - if (menu.webIconData) { - const prefix = menu.webIconData.startsWith("P") - ? "data:image/svg+xml;base64," - : "data:image/png;base64,"; - result = menu.webIconData.startsWith("data:image") - ? menu.webIconData - : prefix + menu.webIconData.replace(/\s/g, ""); - } - menu.webIconData = result; - memo[menu.name.trim()] = menu; - } - if (menu.childrenTree) { - const innerMemo = _.reduce(menu.childrenTree, findNames, {}); - for (const innerKey in innerMemo) { - memo[menu.name.trim() + " / " + innerKey] = innerMemo[innerKey]; - } - } - return memo; -} - -/** - * @extends Component - */ -export class AppsMenuSearchBar extends Component { - setup() { - super.setup(); - this.state = useState({ - results: [], - offset: 0, - hasResults: false, - }); - this.searchBarInput = useAutofocus({refName: "SearchBarInput"}); - this._searchMenus = debounce(this._searchMenus, 100); - // Store menu data in a format searchable by fuzzy.js - this._searchableMenus = []; - this.menuService = useService("menu"); - for (const menu of this.menuService.getApps()) { - Object.assign( - this._searchableMenus, - _.reduce([this.menuService.getMenuAsTree(menu.id)], findNames, {}) - ); - } - // Set up key navigation - this._setupKeyNavigation(); - onWillPatch(() => { - // Allow looping on results - if (this.state.offset < 0) { - this.state.offset = this.state.results.length + this.state.offset; - } else if (this.state.offset >= this.state.results.length) { - this.state.offset -= this.state.results.length; - } - }); - onPatched(() => { - // Scroll to selected element on keyboard navigation - if (this.state.results.length) { - const listElement = document.querySelector(".search-results"); - const activeElement = listElement.querySelector(".highlight"); - if (activeElement) { - scrollTo(activeElement, listElement); - } - } - }); - } - - /** - * Search among available menu items, and render that search. - */ - _searchMenus() { - const query = this.searchBarInput.el.value; - this.state.hasResults = query !== ""; - this.state.results = this.state.hasResults - ? fuzzyLookup(query, _.keys(this._searchableMenus), (k) => k) - : []; - } - - /** - * Get menu object for a given key. - * @param {String} key Full path to requested menu. - * @returns {Object} Menu object. - */ - _menuInfo(key) { - return this._searchableMenus[key]; - } - - /** - * Setup navigation among search results - */ - _setupKeyNavigation() { - useHotkey("Home", () => { - this.state.offset = 0; - }); - useHotkey("End", () => { - this.state.offset = this.state.results.length - 1; - }); - } - - _onKeyDown(ev) { - if (ev.code === "Escape") { - ev.stopPropagation(); - ev.preventDefault(); - const query = this.searchBarInput.el.value; - if (query) { - this.searchBarInput.el.value = ""; - this.state.results = []; - this.state.hasResults = false; - } else { - this.env.bus.trigger("ACTION_MANAGER:UI-UPDATED"); - } - } else if (ev.code === "Tab") { - if (document.querySelector(".search-results")) { - ev.preventDefault(); - if (ev.shiftKey) { - this.state.offset--; - } else { - this.state.offset++; - } - } - } else if (ev.code === "ArrowUp") { - if (document.querySelector(".search-results")) { - ev.preventDefault(); - this.state.offset--; - } - } else if (ev.code === "ArrowDown") { - if (document.querySelector(".search-results")) { - ev.preventDefault(); - this.state.offset++; - } - } else if (ev.code === "Enter") { - if (this.state.results.length) { - ev.preventDefault(); - document.querySelector(".search-results .highlight").click(); - } - } - } - - _splitName(name) { - const searchValue = this.searchBarInput.el.value; - if (name) { - const splitName = name.split( - new RegExp(`(${escapeRegExp(searchValue)})`, "ig") - ); - return searchValue.length && splitName.length > 1 ? splitName : [name]; - } - return []; + onMenuClick() { + this.setOpenState(!this.state.open); } } -// Patch Navbar to add proper icon for apps -patch(NavBar.prototype, "web_responsive.navbar", { - getWebIconData(menu) { - var result = "/web_responsive/static/img/default_icon_app.png"; - if (menu.webIconData) { - const prefix = menu.webIconData.startsWith("P") - ? "data:image/svg+xml;base64," - : "data:image/png;base64,"; - result = menu.webIconData.startsWith("data:image") - ? menu.webIconData - : prefix + menu.webIconData.replace(/\s/g, ""); - } - return result; +Object.assign(AppsMenu, { + template: "web_responsive.AppsMenu", + props: { + slots: { + type: Object, + optional: true, + }, }, }); -AppsMenu.template = "web_responsive.AppsMenu"; -AppsMenuSearchBar.template = "web_responsive.AppsMenuSearchResults"; -Object.assign(NavBar.components, {AppsMenu, AppsMenuSearchBar}); + +Object.assign(NavBar.components, {AppsMenu, AppMenuItem, AppsMenuSearchBar}); diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.scss b/web_responsive/static/src/components/apps_menu/apps_menu.scss index d8611336f..6ddfe5790 100644 --- a/web_responsive/static/src/components/apps_menu/apps_menu.scss +++ b/web_responsive/static/src/components/apps_menu/apps_menu.scss @@ -1,12 +1,34 @@ /* Copyright 2018 Tecnativa - Jairo Llopis * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ +:root { + .o_grid_apps_menu[data-theme="milk"] { + --app-menu-background: url("../../img/home-menu-bg-overlay.svg"), + linear-gradient( + to bottom, + #{$app-menu-background-color}, + #{desaturate(lighten($app-menu-background-color, 20%), 15)} + ); + } + + .o_grid_apps_menu[data-theme="community"] { + --app-menu-background: url("../../img/home-menu-bg-overlay.svg"), + linear-gradient( + to bottom, + #{$o-brand-primary}, + #{desaturate(lighten($o-brand-primary, 20%), 15)} + ); + } +} + @mixin full-screen-dropdown { border: none; box-shadow: none; - min-height: calc(100vh - #{$o-navbar-height}); - min-height: calc(var(--vh100, 100vh) - #{$o-navbar-height}); + height: 100%; + max-height: calc(var(--vh100, 100vh) - #{$o-navbar-height}); + max-height: calc(100dvh - #{$o-navbar-height}); position: fixed; margin: 0; width: 100vw; @@ -21,185 +43,67 @@ } } +// hide and save odoo default QUnit tests +.o_navbar_apps_menu.hide .dropdown-toggle { + position: absolute !important; + z-index: -100 !important; +} + // Iconized full screen apps menu -.o_navbar_apps_menu { - .fade-enter-active, - .fade-leave-active { - transition: opacity 100ms ease; +.o_grid_apps_menu { + &__button { + background: unset; + border: unset; + outline: unset; + margin-right: 0.25rem; + min-height: $o-navbar-height; + height: $o-navbar-height; + width: $o-navbar-height; + color: $o-navbar-brand-color; + + &:hover, + &:focus { + background: $o-navbar-entry-bg--hover; + } } - .fade-enter, - .fade-leave-to { - opacity: 0; - } - .dropdown-menu-custom { - @include full-screen-dropdown(); - cursor: pointer; - background: url("../../img/home-menu-bg-overlay.svg"), - linear-gradient( - to bottom, - $o-brand-odoo, - desaturate(lighten($o-brand-odoo, 20%), 15) - ); - background-size: cover; - border-radius: 0; - // Display apps in a grid - align-content: flex-start; - display: flex !important; - flex-direction: row; - flex-wrap: wrap; - justify-content: flex-start; - @include media-breakpoint-up(lg) { - padding: { - left: calc((100vw - 850px) / 2); - right: calc((100vw - 850px) / 2); - } - } + .o-app-menu-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); + width: 100%; + gap: 0.25rem; - .dropdown-item { - padding: 0; - } - - .o_app { - outline: 0; - height: 100%; - display: flex; - align-items: center; - text-align: center; - flex-direction: column; - justify-content: flex-start; - white-space: normal; - color: $white !important; - padding: 15px 0 10px; - font-size: 1.25rem; - text-shadow: 1px 1px 1px rgba($black, 0.4); - border-radius: 4px; - transition: 300ms ease; - transition-property: background-color; - &:focus { - background-color: rgba($white, 0.05) !important; - } - img { - box-shadow: none; - margin-bottom: 5px; - transition: 300ms ease; - transition-property: box-shadow, transform; - } - - &:hover img, - a:focus img { - transform: translateY(-3px); - box-shadow: 0 9px 12px -4px rgba($black, 0.3); - } - - // Size depends on screen - width: 33.33333333%; - @include media-breakpoint-up(sm) { - width: 25%; - } - @include media-breakpoint-up(md) { - width: 16.6666666%; - } - } - - // Hide app icons when searching - .has-results ~ .o_app { - display: none; - } - - .o-app-icon { - height: auto; - max-width: 6rem; - padding: 0; - } - - // Search input for menus - .form-row { - width: 100%; - } - - .search-container { - width: 100%; - margin: 1rem 1.5rem 0; - - .search-input { - display: flex; - justify-items: center; - box-shadow: inset 0 1px 0 rgba($white, 0.1), 0 1px 0 rgba($black, 0.1); - text-shadow: 0 1px 0 rgba($black, 0.5); - border-radius: 4px; - padding: 0.4rem 0.8rem; - margin-bottom: 1rem; - background-color: rgba($white, 0.1); - - @include media-breakpoint-up(md) { - padding: 0.8rem 1.2rem; - } - - .search-icon { - color: $white; - font-size: 1.5rem; - margin-right: 1rem; - padding-top: 1px; - } - - .form-control { - height: 2rem; - background: none; - border: none; - color: $white; - display: block; - padding: 1px 2px 2px 2px; - box-shadow: none; - - &::placeholder { - color: $white; - opacity: 0.5; - } - } - } - // Allow to scroll only on results, keeping static search box above - .search-results { - .text-ellipsis { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - } - .text-primary { - color: red !important; - } - margin-top: 1rem; - max-height: calc(100vh - #{$o-navbar-height} - 8rem) !important; - overflow: auto; - position: relative; - } - .search-result { - display: block; - align-items: center; - background-position: left; - background-repeat: no-repeat; - background-size: contain; - color: $white; - cursor: pointer; - line-height: 2.5rem; - padding-left: 3.5rem; - white-space: normal; - font-weight: 100; - &.highlight, - &:hover { - background-color: rgba($black, 0.11); - } - b { - font-weight: 700; - } - } + @include media-breakpoint-up(sm) { + grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); } } } -.dropdown-menu-custom { - max-height: 70vh; +.app-menu-container { + @include full-screen-dropdown(); overflow: auto; background-clip: border-box; - box-shadow: $o-dropdown-box-shadow; + padding: 1rem 0.5rem; + gap: 1rem; + background: var(--app-menu-background); + background-size: cover; + border-radius: 0; + // Display apps in a grid + align-content: flex-start; + display: flex !important; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + + // Hide app icons when searching + .has-results ~ .o-app-menu-list { + display: none; + } + + @include media-breakpoint-up(lg) { + padding: { + left: calc((100vw - 850px) / 2); + right: calc((100vw - 850px) / 2); + } + } } diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.xml b/web_responsive/static/src/components/apps_menu/apps_menu.xml index b5f70d4ea..7e0a877f5 100644 --- a/web_responsive/static/src/components/apps_menu/apps_menu.xml +++ b/web_responsive/static/src/components/apps_menu/apps_menu.xml @@ -2,95 +2,49 @@ - - - + + + 'o_navbar_apps_menu hide' + true + + + - - + + + - -
- + onClick="onNavBarDropdownItemSelection.bind(this)" + /> - - - - - - -
-
- - -
-
- - - - - - - - - - - + + +
+ +
+ +
+ +
diff --git a/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js b/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js new file mode 100644 index 000000000..9f6678ff4 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js @@ -0,0 +1,39 @@ +/** @odoo-module **/ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, xml} from "@odoo/owl"; +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; + +class AppsMenuPreferences extends Component { + setup() { + this.action = useService("action"); + this.user = useService("user"); + } + + async _onClick() { + const onClose = () => this.action.doAction("reload_context"); + const action = await this.action.loadAction( + "web_responsive.res_users_view_form_apps_menu_preferences_action" + ); + this.action.doAction({...action, res_id: this.user.userId}, {onClose}).then(); + } +} + +AppsMenuPreferences.template = xml` + +`; + +registry + .category("systray") + .add("AppMenuTheme", {Component: AppsMenuPreferences}, {sequence: 100}); diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js new file mode 100644 index 000000000..70b271240 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js @@ -0,0 +1,53 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, onWillUpdateProps} from "@odoo/owl"; +import {getWebIconData} from "@web_responsive/components/apps_menu_tools.esm"; + +export class AppMenuItem extends Component { + setup() { + super.setup(); + this.webIconData = getWebIconData(this.props.app); + onWillUpdateProps(this.onUpdateProps); + } + + get isActive() { + const {currentApp} = this.props; + return currentApp && currentApp.id === this.props.app.id; + } + + get className() { + const classItems = ["o-app-menu-item"]; + if (this.isActive) { + classItems.push("active"); + } + return classItems.join(" "); + } + + onUpdateProps(nextProps) { + this.webIconData = getWebIconData(nextProps.app); + } + + onClick() { + if (typeof this.props.onClick === "function") { + this.props.onClick(this.props.app); + } + } +} + +Object.assign(AppMenuItem, { + template: "web_responsive.AppMenuItem", + props: { + app: Object, + href: String, + currentApp: { + type: Object, + optional: true, + }, + onClick: Function, + }, +}); diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss new file mode 100644 index 000000000..029a0df29 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss @@ -0,0 +1,73 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +:root { + .o_grid_apps_menu[data-theme="milk"] { + --app-menu-text-color: #{$app-menu-text-color}; + --app-menu-text-shadow: 1px 1px 1px #{rgba($white, 0.4)}; + --app-menu-hover-background: #{rgba(white, 0.4)}; + } + + .o_grid_apps_menu[data-theme="community"] { + --app-menu-text-color: white; + --app-menu-text-shadow: 1px 1px 1px #{rgba(black, 0.4)}; + --app-menu-hover-background: #{rgba(white, 0.2)}; + } +} + +.o-app-menu-item { + display: flex; + flex-direction: column; + border-radius: 4px; + gap: 0.25rem; + transition: ease box-shadow, transform, 0.3s; + background: unset; + outline: unset; + border: unset; + padding: 0.75rem 0.5rem; + justify-content: flex-start; + align-items: center; + white-space: normal; + user-select: none; + height: -moz-available; + height: max-content; + + &__name { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 1em; + text-shadow: var(--app-menu-text-shadow); + color: var(--app-menu-text-color); + text-align: center; + } + + &__icon { + height: auto; + max-width: 64px; + width: 64px; + aspect-ratio: 1; + padding: 10px; + background-color: white; + box-shadow: $app-menu-box-shadow; + } + + &__active { + position: absolute; + bottom: 2px; + right: 2px; + text-shadow: 0 0 2px rgba(250, 250, 250, 0.6); + color: $app-menu-text-color; + } + + &:focus, + &:hover { + transform: translateY(-4px); + box-shadow: 0 6px 12px -8px transparentize($app-menu-text-color, 0.6); + background-color: var(--app-menu-hover-background) !important; + backdrop-filter: blur(2px); + } +} diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml new file mode 100644 index 000000000..a25834bc7 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml @@ -0,0 +1,33 @@ + + + + + +
+ + +
+ + + +
+
+
diff --git a/web_responsive/static/src/components/apps_menu_tools.esm.js b/web_responsive/static/src/components/apps_menu_tools.esm.js new file mode 100644 index 000000000..6749dd71a --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_tools.esm.js @@ -0,0 +1,77 @@ +/** @odoo-module **/ + +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +export function getWebIconData(menu) { + const result = "/web_responsive/static/img/default_icon_app.png"; + const iconData = menu.webIconData; + if (!iconData) { + return result; + } + const prefix = iconData.startsWith("P") + ? "data:image/svg+xml;base64," + : "data:image/png;base64,"; + if (iconData.startsWith("data:image")) { + return iconData; + } + return prefix + iconData.replace(/\s/g, ""); +} + +/** + * @param {Object} menu + */ +export function updateMenuWebIconData(menu) { + menu.webIconData = menu.webIconData ? getWebIconData(menu) : ""; +} + +export function updateMenuDisplayName(menu) { + menu.displayName = menu.name.trim(); +} + +/** + * @param {Object} menu + * @returns {Boolean} + */ +export function isRootMenu(menu) { + return menu.actionID && menu.appID === menu.id; +} + +/** + * @param {Object[]} memo + * @param {Object|null} parentMenu + * @param {Object} menu + * @returns {Object[]} + */ +export function collectSubMenuItems(memo, parentMenu, menu) { + const menuCopy = Object.assign({}, menu); + updateMenuDisplayName(menuCopy); + if (parentMenu) { + menuCopy.displayName = `${parentMenu.displayName} / ${menuCopy.displayName}`; + } + if (menuCopy.actionID && !isRootMenu(menuCopy)) { + memo.push(menuCopy); + } + for (const child of menuCopy.childrenTree || []) { + collectSubMenuItems(memo, menuCopy, child); + } + return memo; +} + +/** + * @param {Object[]} memo + * @param {Object} menu + * @returns {Object} + */ +export function collectRootMenuItems(memo, menu) { + if (isRootMenu(menu)) { + const menuCopy = Object.assign({}, menu); + updateMenuWebIconData(menuCopy); + updateMenuDisplayName(menuCopy); + memo.push(menuCopy); + } + return memo; +} diff --git a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.esm.js b/web_responsive/static/src/components/attachment_viewer/attachment_viewer.esm.js deleted file mode 100644 index 52068df25..000000000 --- a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.esm.js +++ /dev/null @@ -1,37 +0,0 @@ -/** @odoo-module **/ -/* Copyright 2021 ITerra - Sergey Shebanin - * Copyright 2023 Onestein - Anjeel Haria - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -import {AttachmentViewer} from "@mail/components/attachment_viewer/attachment_viewer"; -import {patch} from "web.utils"; -import {registerPatch} from "@mail/model/model_core"; -const {useState} = owl; - -// Patch attachment viewer to add min/max buttons capability -patch(AttachmentViewer.prototype, "web_responsive.AttachmentViewer", { - setup() { - this._super(); - this.state = useState({ - maximized: false, - }); - }, -}); - -registerPatch({ - name: "Dialog", - fields: { - isCloseable: { - compute() { - if (this.attachmentViewer) { - /** - * Prevent closing the dialog when clicking on the mask when the user is - * currently dragging the image. - */ - return false; - } - return this._super(); - }, - }, - }, -}); diff --git a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.scss b/web_responsive/static/src/components/attachment_viewer/attachment_viewer.scss deleted file mode 100644 index c92690adb..000000000 --- a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.scss +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 2019 Tecnativa - Alexandre Díaz - * Copyright 2021 ITerra - Sergey Shebanin - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -// Attachment Viewer -.o_web_client .o_DialogManager_dialog { - /* Show sided viewer on large screens */ - @media (min-width: 1533px) { - &:not(:has(.o_AttachmentDeleteConfirm)) { - position: static; - } - .o_AttachmentViewer_main { - padding-bottom: 20px; - } - .o_AttachmentViewer { - // On-top of navbar - z-index: 10; - position: absolute; - right: 0; - top: 0; - bottom: 0; - margin-left: auto; - background-color: rgba(0, 0, 0, 0.7); - - width: $chatter_zone_width; - &.o_AttachmentViewer_maximized { - width: 100% !important; - } - - /* Show/Hide control buttons (next, prev, etc..) */ - &:hover .o_AttachmentViewer_buttonNavigation, - &:hover .o_AttachmentViewer_toolbar { - display: flex; - } - .o_AttachmentViewer_buttonNavigation, - .o_AttachmentViewer_toolbar { - display: none; - } - .o_AttachmentViewer_viewIframe { - width: 95%; - } - } - } - @media (max-width: 1533px) { - .o_AttachmentViewer_headerItemButtonMinimize, - .o_AttachmentViewer_headerItemButtonMaximize { - display: none !important; - } - } -} -/* Attachment Viewer Max/Min buttons only are useful in sided mode */ -.o_FormRenderer_chatterContainer:not(.o-aside) { - .o_AttachmentViewer_headerItemButtonMinimize, - .o_AttachmentViewer_headerItemButtonMaximize { - display: none !important; - } -} - -.o_apps_menu_opened .o_AttachmentViewer { - display: none !important; -} diff --git a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml b/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml deleted file mode 100644 index 57f3b6c99..000000000 --- a/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/web_responsive/static/src/components/chatter/chatter.esm.js b/web_responsive/static/src/components/chatter/chatter.esm.js new file mode 100644 index 000000000..b12fc7ae0 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.esm.js @@ -0,0 +1,28 @@ +/** @odoo-module **/ +/* Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Chatter} from "@mail/core/web/chatter"; +import {patch} from "@web/core/utils/patch"; +import {useEffect} from "@odoo/owl"; + +patch(Chatter.prototype, { + setup() { + super.setup(); + useEffect(this._resetScrollToAttachmentsEffect.bind(this), () => [ + this.state.isAttachmentBoxOpened, + ]); + }, + /** + * Prevent scrollIntoView error + * @param {Boolean} isAttachmentBoxOpened + * @private + */ + _resetScrollToAttachmentsEffect(isAttachmentBoxOpened) { + if (!isAttachmentBoxOpened) { + this.state.scrollToAttachments = 0; + } + }, +}); diff --git a/web_responsive/static/src/components/chatter/chatter.scss b/web_responsive/static/src/components/chatter/chatter.scss new file mode 100644 index 000000000..6ea395863 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.scss @@ -0,0 +1,42 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o-mail-Composer { + grid-template-areas: + "sidebar-header core-header" + "core-main core-main" + "sidebar-footer core-footer"; + + .o-mail-Composer-sidebarMain { + display: none; + } + + @include media-breakpoint-up(sm) { + grid-template-areas: + "sidebar-header core-header" + "sidebar-main core-main" + "sidebar-footer core-footer"; + + .o-mail-Composer-sidebarMain { + display: block; + } + + .o-mail-SuggestedRecipient { + margin-left: 42px; + } + } +} + +.o-mail-Form-chatter { + .o-mail-SuggestedRecipient, + .o-mail-Chatter-recipientList { + margin-left: 0; + } + + @include media-breakpoint-up(sm) { + .o-mail-SuggestedRecipient, + .o-mail-Chatter-recipientList { + margin-left: 42px; + } + } +} diff --git a/web_responsive/static/src/components/chatter/chatter.xml b/web_responsive/static/src/components/chatter/chatter.xml new file mode 100644 index 000000000..689004572 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.xml @@ -0,0 +1,69 @@ + + + + + + '' + + + + + + + + + + + + + + + + + + + diff --git a/web_responsive/static/src/components/chatter_topbar/chatter_topbar.esm.js b/web_responsive/static/src/components/chatter_topbar/chatter_topbar.esm.js deleted file mode 100644 index b4140a11f..000000000 --- a/web_responsive/static/src/components/chatter_topbar/chatter_topbar.esm.js +++ /dev/null @@ -1,15 +0,0 @@ -/** @odoo-module **/ -/* Copyright 2023 Onestein - Anjeel Haria - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -import {ChatterTopbar} from "@mail/components/chatter_topbar/chatter_topbar"; -import {deviceContext} from "@web_responsive/components/ui_context.esm"; -import {patch} from "web.utils"; - -// Patch chatter topbar to add ui device context -patch(ChatterTopbar.prototype, "web_responsive.ChatterTopbar", { - setup() { - this._super(); - this.ui = deviceContext; - }, -}); diff --git a/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml b/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml deleted file mode 100644 index a36780f16..000000000 --- a/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - - - - - -
- - - - - - - - -
-
-
-
-
- - -
-
- - - -
- -
- - - - - - - - -
-
-
-
-
- - - diff --git a/web_responsive/static/src/components/command_palette/main.esm.js b/web_responsive/static/src/components/command_palette/main.esm.js new file mode 100644 index 000000000..a23fe795e --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.esm.js @@ -0,0 +1,21 @@ +/** @odoo-module **/ + +import {useState} from "@odoo/owl"; +import {useService} from "@web/core/utils/hooks"; +import {CommandPalette} from "@web/core/commands/command_palette"; +import {patch} from "@web/core/utils/patch"; + +export const unpatchCommandPalette = patch(CommandPalette.prototype, { + setup() { + super.setup(); + this.ui = useState(useService("ui")); + }, + + get small() { + return this.ui.size < 2; + }, + + get contentClass() { + return `o_command_palette ${this.small ? "" : "mt-5"}`; + }, +}); diff --git a/web_responsive/static/src/components/command_palette/main.scss b/web_responsive/static/src/components/command_palette/main.scss new file mode 100644 index 000000000..834b8b8db --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.scss @@ -0,0 +1,28 @@ +.o_command_palette { + .o_command_palette_exit { + display: none; + } + + @include media-breakpoint-down(sm) { + .o_command_palette_root { + display: flex; + max-height: 100vh; + max-height: 100dvh; + flex-direction: column; + height: 100%; + justify-content: space-between; + } + .o_command_palette_exit { + display: block; + } + .o_command_palette_search { + flex-shrink: 0; + } + .o_command_palette_listbox { + max-height: unset; + } + .o_command_palette_footer { + flex-shrink: 0; + } + } +} diff --git a/web_responsive/static/src/components/command_palette/main.xml b/web_responsive/static/src/components/command_palette/main.xml new file mode 100644 index 000000000..a49723e7e --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.xml @@ -0,0 +1,24 @@ + + + + + contentClass + + + o_command_palette_root + + +
+ +
+
+
+
diff --git a/web_responsive/static/src/components/control_panel/control_panel.esm.js b/web_responsive/static/src/components/control_panel/control_panel.esm.js index f0c774f23..b1bfb4dca 100644 --- a/web_responsive/static/src/components/control_panel/control_panel.esm.js +++ b/web_responsive/static/src/components/control_panel/control_panel.esm.js @@ -1,45 +1,73 @@ /** @odoo-module **/ -/* Copyright 2021 ITerra - Sergey Shebanin - * Copyright 2023 Onestein - Anjeel Haria +/* Copyright 2023 Taras Shabaranskyi * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ -import LegacyControlPanel from "web.ControlPanel"; import {ControlPanel} from "@web/search/control_panel/control_panel"; -import {deviceContext} from "@web_responsive/components/ui_context.esm"; -import {patch} from "web.utils"; -import {Dropdown} from "@web/core/dropdown/dropdown"; +import {patch} from "@web/core/utils/patch"; +import {browser} from "@web/core/browser/browser"; -const {useState} = owl; +export const STICKY_CLASS = "o_mobile_sticky"; -// In v15.0 there are two ControlPanel's. They are mostly the same and are used in legacy and new owl views. -// We extend them two mostly the same way. +/** + * @param {Number} delay + * @returns {{collect: function(Number, (function(Number, Number): void)): void}} + */ +export function minMaxCollector(delay = 100) { + const state = { + id: null, + items: [], + }; -// Patch legacy control panel to add states for mobile quick search -patch(LegacyControlPanel.prototype, "web_responsive.LegacyControlPanelMobile", { + function min() { + return Math.min.apply(null, state.items); + } + + function max() { + return Math.max.apply(null, state.items); + } + + return { + collect(value, callback) { + clearTimeout(state.id); + state.items.push(value); + state.id = setTimeout(() => { + callback(min(), max()); + state.items = []; + state.id = null; + }, delay); + }, + }; +} + +export const unpatchControlPanel = patch(ControlPanel.prototype, { + scrollValueCollector: undefined, + /** @type {Number}*/ + scrollHeaderGap: undefined, setup() { - this._super(); - this.state = useState({ - mobileSearchMode: this.props.withBreadcrumbs ? "" : "quick", - }); - this.ui = deviceContext; + super.setup(); + this.scrollValueCollector = minMaxCollector(100); + this.scrollHeaderGap = 2; }, - setMobileSearchMode(ev) { - this.state.mobileSearchMode = ev.detail; + onScrollThrottled() { + if (this.isScrolling) { + return; + } + this.isScrolling = true; + browser.requestAnimationFrame(() => (this.isScrolling = false)); + + /** @type {HTMLElement}*/ + const rootEl = this.root.el; + const scrollTop = this.getScrollingElement().scrollTop; + const activeAnimation = scrollTop > this.initialScrollTop; + + rootEl.classList.toggle(STICKY_CLASS, activeAnimation); + this.scrollValueCollector.collect(scrollTop - this.oldScrollTop, (min, max) => { + const delta = min + max; + if (delta < -this.scrollHeaderGap || delta > this.scrollHeaderGap) { + rootEl.style.top = `${delta < 0 ? -rootEl.clientHeight : 0}px`; + } + }); + + this.oldScrollTop = scrollTop; }, }); - -// Patch control panel to add states for mobile quick search -patch(ControlPanel.prototype, "web_responsive.ControlPanelMobile", { - setup() { - this._super(); - this.state = useState({ - mobileSearchMode: "", - }); - this.ui = deviceContext; - }, - setMobileSearchMode(ev) { - this.state.mobileSearchMode = ev.detail; - }, -}); - -Object.assign(LegacyControlPanel.components, {Dropdown}); diff --git a/web_responsive/static/src/components/control_panel/control_panel.scss b/web_responsive/static/src/components/control_panel/control_panel.scss deleted file mode 100644 index 2b7b4e409..000000000 --- a/web_responsive/static/src/components/control_panel/control_panel.scss +++ /dev/null @@ -1,306 +0,0 @@ -/* Copyright 2018 Tecnativa - Jairo Llopis - * Copyright 2021 ITerra - Sergey Shebanin - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -// Make enough space for search panel filters buttons -.o_control_panel { - // There is no media breakpoint for XL upper bound - @include media-breakpoint-up(lg) { - @media (max-width: 1360px) { - .o_cp_top_left, - .o_cp_bottom_left { - width: 40%; - } - .o_cp_top_right, - .o_cp_bottom_right { - width: 60%; - } - } - } - // For FULL HD devices - @media (min-width: 1900px) { - .o_cp_top_left, - .o_cp_bottom_left { - width: 60%; - } - .o_cp_top_right, - .o_cp_bottom_right { - width: 40%; - } - } - @include media-breakpoint-only(md) { - .o_search_options_hide_labels .o_dropdown_title { - display: none; - } - } - .o_cp_bottom_right { - height: 10%; - } - // Mobile Control panel (breadcrumbs, search box, buttons...) - @include media-breakpoint-down(sm) { - // Avoid horizontal scrolling of control panel. - // It doesn't work on iOS Safari, but it looks similar as - // without this patch. With this patch it looks better for - // other browsers. - - // Arrange buttons to use space better - .o_cp_top_left, - .o_cp_top_right { - flex: 1 1 100%; - } - - .o_cp_top_left { - flex-basis: 89%; - max-width: 89%; - } - - .o_cp_top_right { - flex-basis: 11%; - } - - .o_cp_bottom { - position: relative; // Necessary for dropdown menu positioning - display: block; - margin: 0; - min-height: 30px !important; - } - - .o_cp_bottom_left { - float: left; - margin: 5px 0; - } - - .o_cp_bottom_right { - float: right; - padding-left: 10px; - margin: 5px 0; - } - - .o_cp_bottom_right, - .o_cp_pager { - white-space: nowrap; - } - .o_cp_pager { - margin-bottom: 0; - } - .o_list_selection_box { - padding-left: 5px !important; - padding-right: 5px; - } - - .o_cp_action_menus { - padding-right: 0; - .o_dropdown_title, - .fa-chevron-right, - .fa-chevron-down { - display: none; - } - .dropdown-toggle { - margin: 0px 2px; - height: 100%; - } - .dropdown { - height: 100%; - } - @include media-breakpoint-down(xs) { - .dropdown { - position: static; - } - .dropdown-menu { - right: 0; - left: 0; - top: 35px; - } - } - } - - // Hide all but 2 last breadcrumbs, and render 2nd-to-last as arrow - .breadcrumb-item { - &:not(.active):not(.o_back_button) { - padding-left: 0; - display: none; - } - - &::before { - content: none; - padding-right: 0; - } - - &.o_back_button { - &::before { - color: var(--primary); - content: "\f060"; // .fa-arrow-left - cursor: pointer; - font-family: FontAwesome; - } - - a { - display: none; - } - } - } - - // Ellipsize long breadcrumbs - .breadcrumb { - max-width: 100%; - text-overflow: ellipsis; - } - - // In case you install `mail`, there is a mess on BS vs inline styles - // we need to fix - .o_cp_buttons .btn.d-block:not(.d-none) { - display: inline-block !important; - } - - .o_searchview_input_container > .o_searchview_autocomplete { - left: 0; - right: 0; - > li { - padding: 10px 0px; - } - } - .o_searchview_quick { - display: flex; - flex: 1 1 auto; - align-items: center; - .o_searchview_input_container { - flex: 1 1 auto; - margin-left: 5px; - } - } - .o_searchview { - padding: 1px 0px 3px 0px; - &.o_searchview_mobile { - cursor: pointer; - } - } - } - // Filter Menu - // Cut long filters names in the filters menu - .o_filter_menu { - .o_menu_item { - @include media-breakpoint-up(md) { - max-width: 250px; - } - a { - overflow: hidden; - text-overflow: ellipsis; - } - } - } - // Enable scroll on dropdowns - .o_cp_buttons .dropdown-menu { - max-height: 70vh; - overflow-y: auto; - overflow-x: hidden; - } - // Dropdown with buttons to switch the view type - .o_cp_switch_buttons.dropdown-menu { - align-content: center; - display: flex; - flex-direction: row; - justify-content: space-around; - padding: 0; - - .btn { - border: { - bottom: 0; - radius: 0; - top: 0; - } - font-size: 1.3em; - } - } -} -// Mobile search bar full screen mode -.o_cp_mobile_search { - position: fixed; - top: 0; - left: 0; - bottom: 0; - padding: 0; - width: 100%; - background-color: white; - z-index: $zindex-modal; - overflow: auto; - .o_mobile_search_header { - background-color: var(--mobileSearch__header-bg, #{$o-brand-odoo}); - display: flex; - min-height: $o-navbar-height; - justify-content: space-between; - width: 100%; - - .o_mobile_search_button { - color: white; - - &:active { - background-color: darken($o-brand-primary, 10%); - } - } - } - .o_searchview_input_container { - display: flex; - padding: 15px 20px 0 20px; - position: relative; - .o_searchview_input { - width: 100%; - margin-bottom: 15px; - border-bottom: 1px solid $o-brand-primary; - } - .o_searchview_facet { - display: inline-flex; - order: 1; - } - .o_searchview_autocomplete { - top: 3rem; - } - } - .o_mobile_search_filter { - padding-bottom: 15%; - > .dropdown { - flex-direction: column; - line-height: 2rem; - width: 100%; - margin: 15px 5px 0px 5px; - border: solid 1px darken($gray-200, 20%); - } - .dropdown.show > .dropdown-toggle { - background-color: $gray-200; - } - .dropdown-toggle { - width: 100%; - text-align: left; - &:after { - top: auto; - } - } - .dropdown-item:before { - top: auto; - } - .dropdown-item.focus { - background-color: white; - } - .dropdown-menu { - // Here we use !important because of popper js adding custom style - // to element so to override it use !important - position: relative !important; - top: 0 !important; - left: 0 !important; - width: 100%; - max-height: 100%; - box-shadow: none; - border: none; - color: $gray-600; - .divider { - margin: 0px; - } - > li > a { - padding: 10px 26px; - } - } - } - .o_mobile_search_show_result { - padding: 10px; - font-size: 15px; - } -} diff --git a/web_responsive/static/src/components/control_panel/control_panel.xml b/web_responsive/static/src/components/control_panel/control_panel.xml deleted file mode 100644 index 5ecbdbfa2..000000000 --- a/web_responsive/static/src/components/control_panel/control_panel.xml +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - ui.isSmall and state.mobileSearchMode == 'quick' ? 'o_hidden' : '' - - - !ui.isSmall - ui.size == ui.SIZES.MD ? 'o_search_options_hide_labels' : '' - - - - - - - -
- - - -
-
-
- - - - - -
-
- -
- -
-
-
diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.esm.js b/web_responsive/static/src/components/file_viewer/file_viewer.esm.js new file mode 100644 index 000000000..145a84445 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.esm.js @@ -0,0 +1,77 @@ +/** @odoo-module **/ +/* Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {onMounted, onWillStart, useExternalListener, useRef} from "@odoo/owl"; +import {FileViewer} from "@web/core/file_viewer/file_viewer"; +import {patch} from "@web/core/utils/patch"; + +const formChatterClassName = ".o-mail-Form-chatter"; +const formViewSheetClassName = ".o_form_view_container .o_form_sheet_bg"; + +export function useFileViewerContainerSize(ref) { + function updateActualFormChatterSize() { + /** @type {HTMLDivElement}*/ + const chatterElement = document.querySelector(formChatterClassName); + /** @type {HTMLDivElement}*/ + const formSheetElement = document.querySelector(formViewSheetClassName); + if (chatterElement && formSheetElement && ref.el) { + /** @type {CSSStyleDeclaration}*/ + const elStyle = ref.el.style; + const width = `${chatterElement.clientWidth}px`; + const height = `${chatterElement.clientHeight}px`; + const left = `${formSheetElement.clientWidth}px`; + elStyle.setProperty("--o-FileViewerContainer-width", width); + elStyle.setProperty("--o-FileViewerContainer-height", height); + elStyle.setProperty("--o-FileViewerContainer-left", left); + } + } + + useExternalListener(window, "resize", () => { + requestAnimationFrame(updateActualFormChatterSize); + }); + onMounted(() => { + requestAnimationFrame(updateActualFormChatterSize); + }); +} + +/** + * Patch attachment viewer to add min/max buttons capability + * @property {Function} resizeUpdateActualFormChatterWidth + */ +patch(FileViewer.prototype, { + setup() { + super.setup(); + this.root = useRef("root"); + Object.assign(this.state, { + allowMinimize: false, + maximized: true, + }); + useFileViewerContainerSize(this.root); + onWillStart(this.setDefaultMaximizeState); + }, + + get rootClass() { + return { + modal: this.props.modal, + "o-FileViewerContainer__maximized": this.state.maximized, + "o-FileViewerContainer__minimized": !this.state.maximized, + }; + }, + + setDefaultMaximizeState() { + this.state.allowMinimize = Boolean( + document.querySelector(`${formChatterClassName}.o-aside`) + ); + this.state.maximized = !this.state.allowMinimize; + }, + + /** + * @param {Boolean} value + */ + setMaximized(value) { + this.state.maximized = value; + }, +}); diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.scss b/web_responsive/static/src/components/file_viewer/file_viewer.scss new file mode 100644 index 000000000..f528e8333 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.scss @@ -0,0 +1,56 @@ +/* Copyright 2019 Tecnativa - Alexandre Díaz + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o-FileViewerContainer { + --o-FileViewerContainer-width: #{$o-mail-Chatter-minWidth}; + --o-FileViewerContainer-height: var(--100vh, calc(100vh - #{$o-navbar-height})); + --o-FileViewerContainer-left: unset; + --o-FileViewerContainer-right: 0; + + position: fixed; + right: 0; + z-index: $zindex-fixed; + + &__maximized { + top: 0; + left: 0; + right: 0; + } + + &__minimized { + width: 100%; + max-width: var(--o-FileViewerContainer-width, #{$o-mail-Chatter-minWidth}); + height: var(--o-FileViewerContainer-height); + top: unset; + right: var(--o-FileViewerContainer-right, 0); + left: var(--o-FileViewerContainer-left, unset); + bottom: 0; + + .o-FileViewer-main { + padding: $o-navbar-height 0 0 0; + } + + .o-FileViewer-viewPdf { + width: 100% !important; + } + } + + .o-FileViewer-navigation { + background-color: rgba(255, 255, 255, 0.2); + text-shadow: 0 0 rgba(30, 30, 30, 0.8); + box-shadow: 0 0 1px 0 rgba(30, 30, 30, 0.4); + transition: background-color 0.2s, box-shadow 0.2s; + + &:hover { + background-color: rgba(255, 255, 255, 0.8); + text-shadow: 0 0 black; + box-shadow: 0 0 2px 0 rgba(30, 30, 30, 0.8); + } + } +} + +.o_apps_menu_opened .o-FileViewerContainer { + display: none !important; +} diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.xml b/web_responsive/static/src/components/file_viewer/file_viewer.xml new file mode 100644 index 000000000..ace2e1d10 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.xml @@ -0,0 +1,47 @@ + + + diff --git a/web_responsive/static/src/components/hotkey/hotkey.xml b/web_responsive/static/src/components/hotkey/hotkey.xml index f7a484ca0..d9b615c92 100644 --- a/web_responsive/static/src/components/hotkey/hotkey.xml +++ b/web_responsive/static/src/components/hotkey/hotkey.xml @@ -1,6 +1,7 @@ @@ -11,7 +12,6 @@ > 'shift+' + ((section_index + 1) % 10).toString() 'shift+' + (sectionsVisibleCount + 1 % 10).toString() diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js new file mode 100644 index 000000000..265778e43 --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js @@ -0,0 +1,207 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, onPatched, onWillPatch, useRef, useState} from "@odoo/owl"; +import { + collectRootMenuItems, + collectSubMenuItems, +} from "@web_responsive/components/apps_menu_tools.esm"; +import {useAutofocus, useService} from "@web/core/utils/hooks"; +import {debounce} from "@web/core/utils/timing"; +import {escapeRegExp} from "@web/core/utils/strings"; +import {fuzzyLookup} from "@web/core/utils/search"; +import {scrollTo} from "@web/core/utils/scrolling"; + +/** + * @extends Component + */ +export class AppsMenuCanonicalSearchBar extends Component { + setup() { + super.setup(); + this.state = useState({ + rootItems: [], + subItems: [], + offset: 0, + hasResults: false, + }); + this.searchBarInput = useAutofocus({refName: "SearchBarInput"}); + this._searchMenus = debounce(this._searchMenus, 200); + this.menuService = useService("menu"); + this.searchItemsRef = useRef("searchItems"); + this.rootMenuItems = this.getRootMenuItems(); + this.subMenuItems = this.getSubMenuItems(); + onWillPatch(this._computeResultOffset); + onPatched(this._scrollToHighlight); + } + + /** + * @returns {String} + */ + get inputValue() { + const {el} = this.searchBarInput; + return el ? el.value : ""; + } + + /** + * @returns {Boolean} + */ + get hasItemsToDisplay() { + return this.totalItemsCount > 0; + } + + /** + * @returns {Number} + */ + get totalItemsCount() { + const {rootItems, subItems} = this.state; + return rootItems.length + subItems.length; + } + + /** + * @param {Number} index + * @param {Boolean} isSubMenu + * @returns {String} + */ + highlighted(index, isSubMenu = false) { + const {state} = this; + let _index = index; + if (isSubMenu) { + _index = state.rootItems.length + index; + } + return _index === state.offset ? "highlight" : ""; + } + + /** + * @returns {Object[]} + */ + getRootMenuItems() { + return this.menuService.getApps().reduce(collectRootMenuItems, []); + } + + /** + * @returns {Object[]} + */ + getSubMenuItems() { + const response = []; + for (const menu of this.menuService.getApps()) { + const menuTree = this.menuService.getMenuAsTree(menu.id); + collectSubMenuItems(response, null, menuTree); + } + return response; + } + + /** + * Search among available menu items, and render that search. + */ + _searchMenus() { + const {state} = this; + const query = this.inputValue; + state.hasResults = query !== ""; + if (!state.hasResults) { + state.rootItems = []; + state.subItems = []; + return; + } + const searchField = (item) => item.displayName; + state.rootItems = fuzzyLookup(query, this.rootMenuItems, searchField); + state.subItems = fuzzyLookup(query, this.subMenuItems, searchField); + } + + _onKeyDown(ev) { + const code = ev.code; + if (code === "Escape") { + ev.stopPropagation(); + ev.preventDefault(); + if (this.inputValue) { + this.searchBarInput.el.value = ""; + Object.assign(this.state, {rootItems: [], subItems: []}); + this.state.hasResults = false; + } else { + this.env.bus.trigger("ACTION_MANAGER:UI-UPDATED"); + } + } else if (code === "Tab") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + if (ev.shiftKey) { + this.state.offset--; + } else { + this.state.offset++; + } + } + } else if (code === "ArrowUp") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + this.state.offset--; + } + } else if (code === "ArrowDown") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + this.state.offset++; + } + } else if (code === "Enter") { + const element = this.searchItemsRef.el; + if (this.hasItemsToDisplay && element) { + ev.preventDefault(); + this._selectHighlightedSearchItem(element); + } + } else if (code === "Home") { + this.state.offset = 0; + } else if (code === "End") { + this.state.offset = this.totalItemsCount - 1; + } + } + + /** + * @param {HTMLElement} element + * @private + */ + _selectHighlightedSearchItem(element) { + const highlightedElement = element.querySelector( + ".highlight > .search-item__link" + ); + if (highlightedElement) { + highlightedElement.click(); + } else { + console.warn("Highlighted search item is not found"); + } + } + + _splitName(name) { + if (!name) { + return []; + } + const value = this.inputValue; + const splitName = name.split(new RegExp(`(${escapeRegExp(value)})`, "ig")); + return value.length && splitName.length > 1 ? splitName : [name]; + } + + _scrollToHighlight() { + // Scroll to selected element on keyboard navigation + const element = this.searchItemsRef.el; + if (!(this.totalItemsCount && element)) { + return; + } + const activeElement = element.querySelector(".highlight"); + if (activeElement) { + scrollTo(activeElement, element); + } + } + + _computeResultOffset() { + // Allow looping on results + const {state} = this; + const total = this.totalItemsCount; + if (state.offset < 0) { + state.offset = total + state.offset; + } else if (state.offset >= total) { + state.offset -= total; + } + } +} + +AppsMenuCanonicalSearchBar.props = {}; +AppsMenuCanonicalSearchBar.template = "web_responsive.AppsMenuCanonicalSearchBar"; diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss new file mode 100644 index 000000000..e8d9be180 --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss @@ -0,0 +1,112 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +:root { + .o_grid_apps_menu[data-theme="milk"] { + --apps-menu-scrollbar-background: #{$o-brand-odoo}; + --apps-menu-empty-search-color: $app-menu-text-color; + } + + .o_grid_apps_menu[data-theme="community"] { + --apps-menu-scrollbar-background: white; + --apps-menu-empty-search-color: white; + } +} + +.o_grid_apps_menu .search-container { + // Allow to scroll only on results, keeping static search box above + .search-list { + display: flex; + flex-direction: column; + gap: calc(0.25rem + 1px); + overflow: auto; + padding: 0.25rem 0; + margin: 0.25rem 0; + max-height: calc(100vh - #{$o-navbar-height} - 5.25rem); + max-height: calc(100dvh - #{$o-navbar-height} - 5.25rem); + max-width: calc(100vw - 1rem); + position: relative; + width: 100%; + height: 100%; + + &::-webkit-scrollbar { + width: 10px; + } + + &::-webkit-scrollbar-thumb { + background: var(--apps-menu-scrollbar-background); + border-radius: 6px; + } + + @include media-breakpoint-down(md) { + &::-webkit-scrollbar { + width: 4px; + } + } + } + + .search-item-divider { + margin: 0 4px; + + hr { + margin: 0.5rem 0; + background-color: $o-brand-odoo; + } + } + + .search-item { + display: block; + align-items: center; + background-position: left; + background-repeat: no-repeat; + background-size: contain; + white-space: normal; + font-weight: 100; + background-color: white; + box-shadow: $app-menu-box-shadow; + margin: 0 4px; + border-radius: 4px; + + &__link { + display: flex; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + align-items: center; + cursor: pointer; + } + + &__name { + color: $app-menu-text-color; + text-shadow: 0 0 $app-menu-text-color; + } + + &__image { + max-height: 40px; + max-width: 40px; + width: 40px; + object-fit: contain; + padding: 4px; + } + + &.highlight, + &:hover { + background-color: $app-menu-item-highlight; + box-shadow: $app-menu-box-shadow-highlight; + font-weight: 300; + } + + b { + font-weight: 700; + } + } + + .empty-search-item { + display: inline-block; + width: 100%; + text-align: center; + padding: 0.25rem 0.5rem; + color: var(--apps-menu-empty-search-color); + } +} diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml new file mode 100644 index 000000000..023864a0f --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml @@ -0,0 +1,99 @@ + + + + + +
+
+ + +
+ +
    +
  • + Nothing to show +
  • +
+
+
+
diff --git a/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js new file mode 100644 index 000000000..3aa7da63e --- /dev/null +++ b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ +/* global Fuse */ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {AppsMenuCanonicalSearchBar} from "@web_responsive/components/menu_canonical_searchbar/searchbar.esm"; + +/** + * @extends AppsMenuCanonicalSearchBar + */ +export class AppsMenuFuseSearchBar extends AppsMenuCanonicalSearchBar { + setup() { + super.setup(); + this.fuseOptions = { + keys: ["displayName"], + threshold: 0.43, + }; + this.rootMenuItems = new Fuse(this.getRootMenuItems(), this.fuseOptions); + this.subMenuItems = new Fuse(this.getSubMenuItems(), this.fuseOptions); + } + + _searchMenus() { + const {state} = this; + const query = this.inputValue; + state.hasResults = query !== ""; + state.rootItems = this.rootMenuItems.search(query); + state.subItems = this.subMenuItems.search(query); + } +} + +AppsMenuFuseSearchBar.props = {}; +AppsMenuFuseSearchBar.template = "web_responsive.AppsMenuFuseSearchBar"; diff --git a/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml new file mode 100644 index 000000000..50945226c --- /dev/null +++ b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml @@ -0,0 +1,36 @@ + + + + + + + result + result.item.xmlid + + + + + + search-item {{highlighted(result_index)}} + + + result + result.item.xmlid + + + + + + search-item {{highlighted(result_index, true)}} + + + diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js new file mode 100644 index 000000000..c0b5e7b9b --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js @@ -0,0 +1,65 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, useState} from "@odoo/owl"; +import {useAutofocus, useService} from "@web/core/utils/hooks"; + +/** + * @extends Component + * @property {{el: HTMLInputElement}} searchBarInput + */ +export class AppsMenuOdooSearchBar extends Component { + setup() { + super.setup(); + this.state = useState({ + rootItems: [], + subItems: [], + offset: 0, + hasResults: false, + }); + this.searchBarInput = useAutofocus({refName: "SearchBarInput"}); + this.command = useService("command"); + } + + /** + * @returns {String} + */ + get inputValue() { + const {el} = this.searchBarInput; + return el ? el.value : ""; + } + + set inputValue(value) { + const {el} = this.searchBarInput; + if (el) { + el.value = value; + } + } + + _onSearchInput() { + if (this.inputValue) { + this._openSearchMenu(this.inputValue); + this.inputValue = ""; + } + } + + _onSearchClick() { + this._openSearchMenu(); + } + + /** + * @param {String} [value] + * @private + */ + _openSearchMenu(value) { + const searchValue = value ? `/${value}` : "/"; + this.command.openMainPalette({searchValue}, null); + } +} + +AppsMenuOdooSearchBar.props = {}; +AppsMenuOdooSearchBar.template = "web_responsive.AppsMenuOdooSearchBar"; diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss new file mode 100644 index 000000000..b503e575b --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss @@ -0,0 +1,4 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml new file mode 100644 index 000000000..4b2ccf552 --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml @@ -0,0 +1,25 @@ + + + + + +
+
+ + +
+
+
+
diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js new file mode 100644 index 000000000..a976b4125 --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js @@ -0,0 +1,26 @@ +/** @odoo-module **/ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {AppsMenuCanonicalSearchBar} from "@web_responsive/components/menu_canonical_searchbar/searchbar.esm"; +import {AppsMenuOdooSearchBar} from "@web_responsive/components/menu_odoo_searchbar/searchbar.esm"; +import {AppsMenuFuseSearchBar} from "@web_responsive/components/menu_fuse_searchbar/searchbar.esm"; +import {Component} from "@odoo/owl"; +import {session} from "@web/session"; + +export class AppsMenuSearchBar extends Component { + setup() { + super.setup(); + this.searchType = session.apps_menu.search_type || "canonical"; + } +} + +Object.assign(AppsMenuSearchBar, { + props: {}, + template: "web_responsive.AppsMenuSearchBar", + components: { + AppsMenuOdooSearchBar, + AppsMenuCanonicalSearchBar, + AppsMenuFuseSearchBar, + }, +}); diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_searchbar/searchbar.scss new file mode 100644 index 000000000..0b4c25e1a --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.scss @@ -0,0 +1,45 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o_grid_apps_menu .search-container { + width: 100%; + + .search-input { + display: flex; + justify-items: center; + gap: 0.75rem; + box-shadow: $app-menu-box-shadow; + border-radius: 4px; + padding: 0.5rem 0.75rem; + background-color: white; + + .search-icon { + color: $app-menu-text-color; + font-size: 1.5rem; + padding-top: 1px; + } + + .form-control { + height: 1.75rem; + background: none; + border: none; + color: $app-menu-text-color; + display: block; + padding: 0; + box-shadow: none; + + &::placeholder { + color: $app-menu-text-color; + opacity: 0.5; + } + } + } +} + +.o_command_palette_search .form-control { + &:focus { + box-shadow: unset; + } +} diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_searchbar/searchbar.xml new file mode 100644 index 000000000..76214f221 --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/web_responsive/static/src/components/search_panel/search_panel.esm.js b/web_responsive/static/src/components/search_panel/search_panel.esm.js deleted file mode 100644 index c6999e2b6..000000000 --- a/web_responsive/static/src/components/search_panel/search_panel.esm.js +++ /dev/null @@ -1,55 +0,0 @@ -/** @odoo-module **/ -/* Copyright 2021 ITerra - Sergey Shebanin - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -import SearchPanel from "@web/legacy/js/views/search_panel"; -import {deviceContext} from "@web_responsive/components/ui_context.esm"; -import {patch} from "web.utils"; - -// Patch search panel to add functionality for mobile view -patch(SearchPanel.prototype, "web_responsive.SearchPanelMobile", { - setup() { - this._super(); - this.state.mobileSearch = false; - this.ui = deviceContext; - }, - getActiveSummary() { - const selection = []; - for (const filter of this.model.get("sections")) { - let filterValues = []; - if (filter.type === "category") { - if (filter.activeValueId) { - const parentIds = this._getAncestorValueIds( - filter, - filter.activeValueId - ); - filterValues = [...parentIds, filter.activeValueId].map( - (valueId) => filter.values.get(valueId).display_name - ); - } - } else { - let values = []; - if (filter.groups) { - values = [ - ...[...filter.groups.values()].map((g) => g.values), - ].flat(); - } - if (filter.values) { - values = [...filter.values.values()]; - } - filterValues = values - .filter((v) => v.checked) - .map((v) => v.display_name); - } - if (filterValues.length) { - selection.push({ - values: filterValues, - icon: filter.icon, - color: filter.color, - type: filter.type, - }); - } - } - return selection; - }, -}); diff --git a/web_responsive/static/src/components/search_panel/search_panel.scss b/web_responsive/static/src/components/search_panel/search_panel.scss deleted file mode 100644 index eccca4547..000000000 --- a/web_responsive/static/src/components/search_panel/search_panel.scss +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2021 ITerra - Sergey Shebanin - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -.o_web_client { - .o_mobile_search { - position: fixed; - top: 0; - left: 0; - bottom: 0; - padding: 0; - width: 100%; - background-color: white; - z-index: $zindex-modal; - overflow: auto; - .o_mobile_search_header { - height: 46px; - margin-bottom: 10px; - width: 100%; - background-color: $o-brand-odoo; - color: white; - span:active { - background-color: darken($o-brand-primary, 10%); - } - span { - cursor: pointer; - } - } - .o_searchview_input_container { - display: flex; - padding: 15px 20px 0 20px; - position: relative; - .o_searchview_input { - width: 100%; - margin-bottom: 15px; - border-bottom: 1px solid $o-brand-secondary; - } - .o_searchview_facet { - border-radius: 10px; - display: inline-flex; - order: 1; - .o_searchview_facet_label { - border-radius: 2em 0em 0em 2em; - } - } - .o_searchview_autocomplete { - top: 100%; - > li { - margin: 5px 0px; - } - } - } - .o_mobile_search_filter { - padding-bottom: 15%; - .o_dropdown { - width: 100%; - margin: 15px 5px 0px 5px; - border: solid 1px darken($gray-200, 20%); - } - .o_dropdown_toggler_btn { - width: 100%; - text-align: left; - - &:after { - display: none; - } - } - - // We disable the backdrop in this case because it prevents any - // interaction outside of a dropdown while it is open. - .dropdown-backdrop { - z-index: -1; - } - .dropdown-menu { - // Here we use !important because of popper js adding custom style - // to element so to override it use !important - position: relative !important; - width: 100% !important; - transform: translate3d(0, 0, 0) !important; - box-shadow: none; - border: none; - color: $gray-600; - .divider { - margin: 0px; - } - > li > a { - padding: 10px 26px; - } - } - } - .o_mobile_search_show_result { - padding: 10px; - font-size: 15px; - } - } -} -// Search panel -@include media-breakpoint-down(sm) { - .o_controller_with_searchpanel { - display: block; - .o_search_panel { - height: auto; - padding: 8px; - border-left: 1px solid $gray-300; - section { - padding: 0px 16px; - } - } - .o_search_panel_summary { - cursor: pointer; - } - } -} diff --git a/web_responsive/static/src/components/search_panel/search_panel.xml b/web_responsive/static/src/components/search_panel/search_panel.xml deleted file mode 100644 index a30d39cfa..000000000 --- a/web_responsive/static/src/components/search_panel/search_panel.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
-
- - - - - - - All -
-
-
- - -
- - - FILTER - -
- -
- SEE RESULT -
-
- - diff --git a/web_responsive/static/src/components/ui_context.esm.js b/web_responsive/static/src/components/ui_context.esm.js deleted file mode 100644 index 445fbd777..000000000 --- a/web_responsive/static/src/components/ui_context.esm.js +++ /dev/null @@ -1,47 +0,0 @@ -/** @odoo-module **/ -/* Copyright 2021 ITerra - Sergey Shebanin - * Copyright 2023 Onestein - Anjeel Haria - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ - -import {registry} from "@web/core/registry"; -import {debounce} from "@web/core/utils/timing"; -import config from "web.config"; -import core from "web.core"; - -import Context from "web.Context"; - -// Legacy variant -// TODO: remove when legacy code will dropped from odoo -// TODO: then move context definition inside service start function -export const deviceContext = new Context({ - isSmall: config.device.isMobile, - size: config.device.size_class, - SIZES: config.device.SIZES, -}).eval(); - -// New wowl variant -// TODO: use default odoo device context when it will be realized -const uiContextService = { - dependencies: ["ui"], - start(env, {ui}) { - window.addEventListener( - "resize", - debounce(() => { - const state = deviceContext; - if (state.size !== ui.size) { - state.size = ui.size; - } - if (state.isSmall !== ui.isSmall) { - state.isSmall = ui.isSmall; - config.device.isMobile = state.isSmall; - config.device.size_class = state.size; - core.bus.trigger("UI_CONTEXT:IS_SMALL_CHANGED"); - } - }, 150) // UIService debounce for this event is 100 - ); - - return deviceContext; - }, -}; - -registry.category("services").add("ui_context", uiContextService); diff --git a/web_responsive/static/src/legacy/js/web_responsive.esm.js b/web_responsive/static/src/legacy/js/web_responsive.esm.js new file mode 100644 index 000000000..3c5c8520c --- /dev/null +++ b/web_responsive/static/src/legacy/js/web_responsive.esm.js @@ -0,0 +1,27 @@ +/** @odoo-module **/ + +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {debounce} from "@web/core/utils/timing"; + +// Fix for iOS Safari to set correct viewport height +// https://github.com/Faisal-Manzer/postcss-viewport-height-correction +export function setViewportProperty(doc) { + function handleResize() { + requestAnimationFrame(function () { + doc.style.setProperty("--vh100", doc.clientHeight + "px"); + }); + } + + handleResize(); + return handleResize; +} + +window.addEventListener( + "resize", + debounce(setViewportProperty(document.documentElement), 25) +); diff --git a/web_responsive/static/src/legacy/js/web_responsive.js b/web_responsive/static/src/legacy/js/web_responsive.js deleted file mode 100644 index e96dc3010..000000000 --- a/web_responsive/static/src/legacy/js/web_responsive.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2018 Tecnativa - Jairo Llopis - * Copyright 2021 ITerra - Sergey Shebanin - * Copyright 2023 Onestein - Anjeel Haria - * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ -odoo.define("web_responsive", function () { - "use strict"; - // Fix for iOS Safari to set correct viewport height - // https://github.com/Faisal-Manzer/postcss-viewport-height-correction - function setViewportProperty(doc) { - function handleResize() { - requestAnimationFrame(function updateViewportHeight() { - doc.style.setProperty("--vh100", doc.clientHeight + "px"); - }); - } - handleResize(); - return handleResize; - } - window.addEventListener( - "resize", - _.debounce(setViewportProperty(document.documentElement), 100) - ); -}); diff --git a/web_responsive/static/src/legacy/scss/big_boxes.scss b/web_responsive/static/src/legacy/scss/big_boxes.scss new file mode 100644 index 000000000..180a3bdfe --- /dev/null +++ b/web_responsive/static/src/legacy/scss/big_boxes.scss @@ -0,0 +1,95 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$big-checkbox-size: 1.5em; + +// Big checkboxes +.o_list_view, +.o_setting_container .o_setting_box { + .o_setting_right_pane { + margin-left: 34px; + } + + .o-checkbox:not(.o_boolean_toggle) { + margin-right: 10px; + margin-top: -6px; + + &.d-inline-block { + display: block !important; + } + + .form-check-input { + height: $big-checkbox-size; + width: $big-checkbox-size; + } + } + + .o_optional_columns_dropdown { + .o-dropdown--menu { + display: flex !important; + flex-direction: column; + margin: 0; + } + + .o-checkbox { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin: 0; + } + + .form-check-input { + margin-bottom: 2px; + } + } +} + +.o_add_favorite + .o_accordion_values { + .o_add_favorite_props { + display: flex; + flex-direction: column; + margin: 0; + } + + .o_add_favorite_name { + margin-bottom: 0.5rem; + max-width: 100%; + } + + .form-check-input { + height: $big-checkbox-size; + width: $big-checkbox-size; + } + + .form-check-label { + line-height: normal; + } + + .o-checkbox { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin: 0; + } +} + +.o_setting_container .o_setting_box { + .o-checkbox:not(.o_boolean_toggle) { + .form-check-label { + &::after { + width: 24px; + height: 24px; + } + + &::before { + outline: none !important; + border: 1px solid #4c4c4c; + width: 24px; + height: 24px; + } + } + } +} diff --git a/web_responsive/static/src/legacy/scss/form_variable.scss b/web_responsive/static/src/legacy/scss/form_variable.scss new file mode 100644 index 000000000..442e98a87 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/form_variable.scss @@ -0,0 +1,5 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$o-form-renderer-max-width: 3840px; +$o-form-view-sheet-max-width: 2560px; diff --git a/web_responsive/static/src/legacy/scss/list_sticky_header.scss b/web_responsive/static/src/legacy/scss/list_sticky_header.scss new file mode 100644 index 000000000..63cd160f9 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/list_sticky_header.scss @@ -0,0 +1,26 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o_mobile_sticky { + transition: top 0.5s; +} + +// Sticky Header & Footer in List View +.o_list_view { + .o_list_table { + thead { + box-shadow: 0 1px 0 0 var(--ListRenderer-thead-border-end-color); + } + + .o_list_footer { + position: sticky; + bottom: 0; + z-index: 2; + background-color: var(--ListRenderer-thead-bg-color); + box-shadow: 0 -1px 0 -1px var(--ListRenderer-thead-border-end-color); + } + } +} diff --git a/web_responsive/static/src/legacy/scss/primary_variable.scss b/web_responsive/static/src/legacy/scss/primary_variable.scss new file mode 100644 index 000000000..bb1f12852 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/primary_variable.scss @@ -0,0 +1,12 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$app-menu-text-color: #374151 !default; +$app-menu-background-color: rgb(233, 230, 249) !default; +$app-menu-item-highlight: rgb(243, 240, 259) !default; +$app-menu-box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16), + 0 2px 2px rgba(0, 0, 0, 0.016), 0 4px 4px rgba(0, 0, 0, 0.016), + 0 8px 8px rgba(0, 0, 0, 0.016), 0 16px 16px rgba(0, 0, 0, 0.016) !default; +$app-menu-box-shadow-highlight: inset 0 0 0 1px rgba(0, 0, 0, 0.26), + 0 2px 2px rgba(0, 0, 0, 0.026), 0 4px 4px rgba(0, 0, 0, 0.026), + 0 8px 8px rgba(0, 0, 0, 0.026), 0 16px 16px rgba(0, 0, 0, 0.026) !default; diff --git a/web_responsive/static/src/legacy/scss/web_responsive.scss b/web_responsive/static/src/legacy/scss/web_responsive.scss index 38da47f3a..092faba20 100644 --- a/web_responsive/static/src/legacy/scss/web_responsive.scss +++ b/web_responsive/static/src/legacy/scss/web_responsive.scss @@ -1,89 +1,42 @@ /* Copyright 2018 Tecnativa - Jairo Llopis * Copyright 2021 ITerra - Sergey Shebanin * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ $chatter_zone_width: 35% !important; -// Support for long titles -@include media-breakpoint-up(md) { - .o_form_view .oe_button_box + .oe_title, - .o_form_view .oe_button_box + .oe_avatar + .oe_title { - /* Button-box has a hardcoded width of 132px per button and have three columns */ - width: calc(100% - 450px); - } -} +// Allow sticky header +.o_action_manager { + .o_form_view { + overflow: unset; -// Scroll all but top bar -html .o_web_client .o_action_manager .o_action { - @include media-breakpoint-down(sm) { - overflow: auto; - - .o_content { - overflow: visible !important; + .o_form_view_container { + overflow: auto; } } - max-width: 100%; } @include media-breakpoint-down(sm) { - .ui-menu .ui-menu-item { + .ui-menu-item-wrapper { + display: inline-flex !important; + align-items: center; height: 35px; - font-size: 15px; } - .o_calendar_view .o_calendar_widget { - .fc-timeGridDay-view .fc-axis, - .fc-timeGridWeek-view .fc-axis { - padding-left: 0px; - } + .o_calendar_widget { .fc-dayGridMonth-view { - padding-left: 0px; .fc-week-number { display: none; } } - .fc-dayGridYear-view { - padding-left: 0px; - > .fc-month-container { - width: 95%; - } - } + .fc-timeGridDay-view { - .fc-week-number { - padding: 0 4px; - width: 1em; - white-space: normal; - text-align: center; - } .fc-day-header { vertical-align: middle; } } - .fc-timeGridWeek-view .fc-widget-header { - word-spacing: 4em; - white-space: normal; - text-align: center; - } } - .o_base_settings .o_setting_container { - display: block; - .settings_tab { - flex-flow: row nowrap; - padding-top: 0px; - .tab { - padding-right: 16px; - } - .selected { - background-color: #212529; - box-shadow: inset 0 -5px #7c7bad; - } - } - .settings > .app_settings_block .o_settings_container { - padding-left: 0; - padding-right: 0; - } - } - .o_kanban_view .o_control_panel .o_cp_bottom_right .o_cp_pager .btn-group { + .o_kanban_view .o_cp_pager .btn-group { top: -1px; } .o_kanban_renderer { @@ -98,42 +51,35 @@ html .o_web_client .o_action_manager .o_action { // Form views .o_form_editable { - .o_form_sheet { - max-width: calc(100% - 32px) !important; - overflow-x: auto; - } - .o_cell .o_form_label:not(.o_status):not(.o_calendar_invitation) { min-height: 23px; @include media-breakpoint-up(md) { margin-bottom: 10px; } } + .o_horizontal_separator { font-size: 14px; } // Some UX improvements for form in edit mode @include media-breakpoint-down(sm) { - .nav-item { - border-bottom: 1px solid #dee2e6; - } - .nav-tabs { - border-bottom: none; - } &.o_form_editable .o_field_widget { &:not(.o_stat_info):not(.o_readonly_modifier):not(.oe_form_field_html):not(.o_field_image) { min-height: 35px; } + .o_x2m_control_panel { - margin-bottom: 10px; + margin-bottom: 10px !important; } + &.o_field_float_percentage, &.o_field_monetary, &.o_field_many2many_selection, .o_field_many2one_selection { align-items: center; } + .o_field_many2one_selection .o_input_dropdown, &.o_datepicker, &.o_partner_autocomplete_info { @@ -141,43 +87,17 @@ html .o_web_client .o_action_manager .o_action { min-height: 35px; } } + .o_external_button { - margin-left: 10px; + margin-left: 5px; } + .o_dropdown_button, .o_datepicker_button { - top: 8px; + top: 50%; right: 6px; bottom: auto; - } - .o_field_many2many_selection .o_dropdown_button { - top: 0 !important; - } - } - } - - // Sticky statusbar - - .o_form_statusbar { - position: sticky !important; - top: 0; - z-index: 2; - } - - // Support for long title (with ellipsis) - .oe_title { - .o_field_widget:not(.oe_inline) { - display: block; - span:not(.o_field_translate) { - display: block; - max-width: 100%; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - width: initial; - &:active { - white-space: normal; - } + transform: translateY(-50%); } } } @@ -185,20 +105,6 @@ html .o_web_client .o_action_manager .o_action { @include media-breakpoint-down(sm) { min-width: auto; - // More buttons border - .oe_button_box { - .o_dropdown_more { - button:last-child { - border-right: 1px solid $gray-400 !important; - } - } - } - - .oe_button_box + .oe_title, - .oe_button_box + .oe_avatar + .oe_title { - width: 100%; - } - // Avoid overflow on modals .o_form_sheet { min-width: auto; @@ -209,43 +115,13 @@ html .o_web_client .o_action_manager .o_action { // Overrides another !important width: auto !important; } - - // Full width in form sheets - .o_form_sheet, - .o_FormRenderer_chatterContainer { - min-width: auto; - max-width: 98% !important; - } - - // Settings pages - .app_settings_block { - .row { - margin: 0; - } - } - - .o_FormRenderer_chatterContainer { - padding-top: initial; - - // Display send button on small screens - .o_Chatter_composer { - &.o-has-current-partner-avatar { - grid-template-columns: 0px 1fr; - padding: 1rem 1rem 1.5rem 1rem !important; - } - - .o_Composer_sidebarMain { - display: none; - } - } - } } } //No content message improvements on mobile @include media-breakpoint-down(md) { .o_view_nocontent { - top: 80px; + top: 53px; } .o_nocontent_help { box-shadow: none; @@ -256,112 +132,16 @@ html .o_web_client .o_action_manager .o_action { } } -// Sticky Header & Footer in List View -.o_list_view { - .table-responsive { - overflow: visible; - .o_list_table { - // th & td are here for compatibility with chrome - thead tr:nth-child(1) th { - position: sticky !important; - top: 0; - z-index: 999; - } - thead tr:nth-child(1) th { - background-color: var(--ListRenderer-thead-bg-color); - border-top: none !important; - border-bottom: none !important; - border-left: transparent; - box-shadow: inset 0 0 0 $o-community-color, - inset 0 -1px 0 $o-community-color; - } - tfoot, - tfoot tr:nth-child(1) td { - position: sticky; - bottom: 0; - } - tfoot tr:nth-child(1) td { - background-color: $o-list-footer-bg-color; - border-top: none !important; - border-bottom: none !important; - box-shadow: inset 0 1px 0 $o-community-color, - inset 0 0 0 $o-community-color; - } - } - .table { - thead tr:nth-child(1) th { - z-index: 1; - } - } - } -} - -// Big checkboxes -.o_list_view, -.o_setting_container .o_setting_box { - .o_setting_right_pane { - margin-left: 34px; - } - .o-checkbox:not(.o_boolean_toggle) { - margin-right: 10px; - margin-top: -6px; - &.d-inline-block { - display: block !important; - } - .form-check-input { - height: 24px; - width: 24px; - } - } - .o_optional_columns_dropdown, - .o_add_favorite { - .o-checkbox { - margin-top: 0; - } - .form-check-input { - height: 1em !important; - width: 1em !important; - } - } -} - -.o_setting_container .o_setting_box { - .o_setting_right_pane { - margin-left: 34px; - } - .o-checkbox:not(.o_boolean_toggle) { - margin-right: 10px; - .form-check-label { - &::after { - width: 24px; - height: 24px; - } - &::before { - outline: none !important; - border: 1px solid #4c4c4c; - width: 24px; - height: 24px; - } - } - } -} - -.o_chatter_header_container { - padding-top: $grid-gutter-width * 0.5; - top: 0; - position: sticky; - background-color: $o-view-background-color; - z-index: 1; -} - -.o_FormRenderer_chatterContainer { +.o-mail-Form-chatter { &.o-isInFormSheetBg:not(.o-aside) { background-color: $white; + &:not(.o-aside) { width: auto; border-top: 1px solid $border-color; } } + &.o-aside { flex: 0 0 $chatter_zone_width; max-width: initial; @@ -380,20 +160,56 @@ body:not(.o_statusbar_buttons) { margin-bottom: 0 !important; } -.w-26 { - width: 26%; -} - -// Color clue to tell the difference between a note and a public message -.o_Chatter_composer { - // HACK: has() pseudo class is broadly supported in desktop, even FF will deploy - // full support soon (now it's available behind a config flag) - // https://caniuse.com/css-has - &:has(div.o_Composer_coreHeader) { - background-color: lighten($o-brand-primary, 40%); - } -} - .o_searchview_autocomplete { z-index: 999; } + +// Color clue to tell the difference between a note and a public message +// HACK: has() pseudo class is broadly supported in desktop, even FF will deploy +// full support soon (now it's available behind a config flag) +// https://caniuse.com/css-has +.o-mail-Chatter-top:has(.o-mail-Chatter-sendMessage.active) { + .o-mail-Composer { + background-color: lighten($o-brand-primary, 35%); + padding-top: 0.25rem !important; + } + + @include media-breakpoint-up(sm) { + .o-mail-Composer { + padding-top: 0.5rem !important; + } + } +} + +@include media-breakpoint-up(md) { + .app_settings_block > h2, + .app_settings_block > div > h2 { + @include o-position-sticky(0); + z-index: 10; + } +} + +.o_list_table { + .o_handle_cell, + .o_list_record_remove { + vertical-align: middle; + } +} + +.o_action_manager { + .dropdown-menu { + max-height: 70vh; + max-height: 70dvh; + } + + .o_searchview_input { + padding-top: 0; + padding-bottom: 0; + } + + .o_control_panel_main { + .btn { + white-space: nowrap; + } + } +} diff --git a/web_responsive/static/src/legacy/xml/custom_favorite_item.xml b/web_responsive/static/src/legacy/xml/custom_favorite_item.xml new file mode 100644 index 000000000..be79500c6 --- /dev/null +++ b/web_responsive/static/src/legacy/xml/custom_favorite_item.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/web_responsive/static/src/legacy/xml/form_buttons.xml b/web_responsive/static/src/legacy/xml/form_buttons.xml index a8cd9a372..c8ca382ff 100644 --- a/web_responsive/static/src/legacy/xml/form_buttons.xml +++ b/web_responsive/static/src/legacy/xml/form_buttons.xml @@ -5,37 +5,121 @@ Copyright 2018 Tecnativa - Jairo Llopis Copyright 2021 ITerra - Sergey Shebanin Copyright 2023 Onestein - Anjeel Haria + Copyright 2023 Taras Shabaranskyi License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). --> - + - + - New + New - + - Save + Save - - - Discard + + + Discard - + d + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + - + d - + - + + + + - +