[REF] web: BurgerMenu, review and simplify scss

Part of the overall v16 SCSS optimization/restyle, task-2704984

It also introduces BS5 utility-classes for font sizes.

Requires:
- https://github.com/odoo/odoo/pull/87448

task-2812594

--
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr

closes odoo/odoo#88073

Related: odoo/enterprise#31048
Signed-off-by: Pierre Paridans (app) <app@odoo.com>
This commit is contained in:
Odoo's Mergebot
2022-09-05 09:31:51 +02:00
committed by GitHub
6 changed files with 98 additions and 232 deletions
@@ -1,6 +1,5 @@
/** @odoo-module **/
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { registry } from "@web/core/registry";
import { Transition } from "@web/core/transition";
import { useService } from "@web/core/utils/hooks";
@@ -82,7 +81,6 @@ export class BurgerMenu extends Component {
}
BurgerMenu.template = "web.BurgerMenu";
BurgerMenu.components = {
DropdownItem,
BurgerUserMenu,
MobileSwitchCompanyMenu,
Transition,
@@ -3,181 +3,79 @@
//------------------------------------------------------------------------------
.o_burger_menu {
top: 0;
bottom: 0;
left: 100%;
width: 90%;
z-index: $zindex-tooltip + 10;
transition: transform .2s ease;
width: 90%;
z-index: $zindex-tooltip + 10;
transition: transform .2s ease;
// Menu Toggle-Animations
transform: translateX(-100%);
// Menu Toggle-Animations
transform: translateX(-100%);
&.burgerslide-enter, &.burgerslide-leave {
transform: translateX(0);
}
// Scoped pseudo classes
%-main-entries-size {
padding-top: 0;
padding-bottom: 0;
min-height: $o-navbar-height-xs;
font-size: $font-size-lg;
line-height: $o-navbar-height-xs;
}
// Scoped variables
$-base-bg: $o-brand-odoo; // change to get variations on the fly (eg. 'dark mode')
$-base-color: color-contrast($-base-bg);
// ====== Top-Bar
.o_burger_menu_topbar {
flex: 0 0 $o-navbar-height-xs;
background: $-base-bg;
color: $-base-color;
@extend %-main-entries-size;
.dropdown-toggle, .o_burger_menu_close {
padding: 0 $o-horizontal-padding;
&.burgerslide-enter, &.burgerslide-leave {
transform: translateX(0);
}
.o_burger_menu_close {
font-size: $h2-font-size;
}
// Scoped variables
$-base-bg: $o-brand-odoo; // change to get variations on the fly (eg. 'dark mode')
$-base-color: color-contrast($-base-bg);
.dropdown-toggle.active {
background: $o-view-background-color;
color: $o-main-headings-color;
}
}
// ====== Menu content container (both App's and User's entries)
.o_burger_menu_content {
background: $o-view-background-color;
&.o_burger_menu_dark {
background-color: darken($-base-bg, 5%);
}
// Menu entries size and layout
.dropdown-item, .dropdown-toggle {
&, > span {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
> span {
// ====== Top-Bar
.o_burger_menu_topbar {
min-height: $o-navbar-height-xs;
padding-left: $o-horizontal-padding;
line-height: $o-navbar-height-xs;
.fa {
padding: $o-horizontal-padding;
font-size: $font-size-sm;
.dropdown-toggle, .o_burger_menu_close {
padding: 0 $o-horizontal-padding;
}
}
}
// Handle menu text-indentation
.dropdown-menu {
margin-top: 0;
text-indent: 1em;
width: 100%;
max-height: none;
.dropdown-toggle {
text-indent: 1em;
}
.dropdown-menu {
text-indent: 2em;
}
.dropdown-item:last-child {
padding-bottom: 1em;
}
}
// First menu level entries are always bigger
.o_user_menu_mobile > .dropdown-item,
.o_menu_sections > .dropdown-item > span,
.o_menu_sections > .o_burger_menu_section > .dropdown-toggle > span {
@extend %-main-entries-size;
}
// ====== 'App menu' spefic design rules
.o_burger_menu_app {
// Reset inner components
.dropdown-menu, .dropdown-item, .dropdown-toggle {
padding: 0;
border: 0;
position: relative;
background-color: initial;
&:after {
display: none; // Remove inner dropdown caret
// ====== Menu content container (both App's and User's entries)
.o_burger_menu_content {
&.o_burger_menu_dark {
background-color: darken($-base-bg, 5%);
}
}
.dropdown-item span, .dropdown-toggle {
@include o-hover-text-color(rgba($-base-color, .8), $-base-color);
}
// Menu entries size and layout
ul {
background-color: rgba(invert($-base-color), .1);
box-shadow: inset 0 -1px 0 rgba($-base-color, .1);
.o_dropdown_active > span {
box-shadow: inset 0 1px 0 rgba(invert($-base-color), .1);
}
li > div, li {
padding-left: $o-horizontal-padding;
}
.o_dropdown_active, .dropdown-menu {
background-color: rgba(invert($-base-color), .1);
}
// Handle menu text-indentation
li {
ul > li {
&, > div {
text-indent: 2em;
}
ul > li {
&, > div {
text-indent: 3em;
}
}
}
}
}
.dropdown-menu {
box-shadow: inset 0 -1px 0 rgba($-base-color, .1);
}
li, button {
@include o-hover-text-color(rgba($-base-color, .8), $-base-color);
}
// ====== 'User Menu' spefic design rules
.o_user_menu_mobile .dropdown-divider {
margin-left: $dropdown-item-padding-x;
margin-right: $dropdown-item-padding-x;
}
}
// ====== 'User Menu' spefic design rules
.o_user_menu_mobile .dropdown-divider {
margin-left: $dropdown-item-padding-x;
margin-right: $dropdown-item-padding-x;
}
}
}
// Burger background
.o_burger_menu_backdrop {
position: fixed;
top: 0;
left: 0;
z-index: $zindex-modal-backdrop;
width: 100vw;
height: 100vh;
background-color: $modal-backdrop-bg;
opacity: $modal-backdrop-opacity;
}
//------------------------------------------------------------------------------
// Design rules not scoped within the main component
//------------------------------------------------------------------------------
.o_web_client .o_main_navbar {
.o_mobile_menu_toggle {
@extend %-main-navbar-entry-base;
@extend %-main-navbar-entry-spacing;
}
}
// Apps Switcher adjustments
body.o_home_menu_background .o_burger_menu_topbar .dropdown-toggle {
background: $o-view-background-color;
color: $o-main-headings-color;
}
@include media-breakpoint-down(md) {
.o_debug_dropdown {
z-index: $zindex-tooltip + 10;
}
.o_debug_dropdown {
z-index: $zindex-tooltip + 10;
}
}
@@ -4,66 +4,65 @@
<!-- Owl Templates -->
<div t-name="web.BurgerMenu" owl="1">
<a type="button"
class="o_mobile_menu_toggle dropdown-toggle o-no-caret d-md-none"
<button
class="o_mobile_menu_toggle o-no-caret d-md-none border-0"
title="Toggle menu" aria-label="Toggle menu"
t-on-click="_openBurger">
<i class="oi oi-panel-right"/>
</a>
</button>
<t t-portal="'body'">
<Transition name="'burgerslide'" visible="state.isBurgerOpened" leaveDuration="200" t-slot-scope="transition">
<div class="o_burger_menu d-flex flex-column flex-nowrap position-fixed" t-att-class="transition.className" t-on-touchstart.stop="_onSwipeStart" t-on-touchend.stop="_onSwipeEnd">
<div class="o_burger_menu_topbar d-flex align-items-center justify-content-between"
<div class="o_burger_menu position-fixed top-0 bottom-0 start-100 d-flex flex-column flex-nowrap" t-att-class="transition.className" t-on-touchstart.stop="_onSwipeStart" t-on-touchend.stop="_onSwipeEnd">
<div class="o_burger_menu_topbar d-flex align-items-center justify-content-between flex-shrink-0 py-0 text-bg-odoo fs-4"
t-on-click.stop='_toggleUserMenu'>
<span class="dropdown-toggle small d-flex align-items-center justify-content-between o-no-caret" t-att-class="{active: isUserMenuUnfolded}">
<small class="o-no-caret dropdown-toggle d-flex align-items-center justify-content-between" t-att-class="{'active bg-white': isUserMenuUnfolded }">
<img class="o_burger_menu_avatar o_image_24_cover rounded-circle" t-att-src="'/web/image?model=res.users&amp;field=avatar_128&amp;id=' + user.userId" alt="Menu"/>
<span class="o_burger_menu_username px-2"><t t-esc="user.name"/></span>
<i t-if="isUserMenuTogglable" class="fa" t-att-class="state.isUserMenuOpened ? 'fa-caret-down' : 'fa-caret-left'"/>
</span>
<span type="button" class="o_burger_menu_close oi oi-close" aria-label="Close menu" title="Close menu" t-on-click.stop="_closeBurger"/>
</small>
<button class="o_burger_menu_close oi oi-close btn d-flex align-items-center h-100 bg-transparent border-0 fs-2 text-reset" aria-label="Close menu" title="Close menu" t-on-click.stop="_closeBurger"/>
</div>
<div class="o_burger_menu_content flex-grow-1 flex-shrink-1 overflow-auto"
t-att-class="{o_burger_menu_dark: !isUserMenuUnfolded}">
<div t-if="isUserMenuUnfolded" class="o_burger_menu_user">
<nav class="o_burger_menu_content flex-grow-1 flex-shrink-1 overflow-auto"
t-att-class="{o_burger_menu_dark: !isUserMenuUnfolded, 'bg-white': isUserMenuUnfolded}">
<!-- -->
<t t-if="isUserMenuUnfolded">
<MobileSwitchCompanyMenu t-if="Object.values(company.availableCompanies).length > 1" />
<BurgerUserMenu/>
</div>
</t>
<!-- Current App Sections -->
<div class="o_burger_menu_app" t-if="!isUserMenuUnfolded">
<div class="o_menu_sections">
<t t-foreach="currentAppSections" t-as="subMenu" t-key="subMenu_index">
<t t-call="web.BurgerSection">
<t t-set="section" t-value="subMenu" />
</t>
</t>
</div>
</div>
</div>
<ul t-if="!isUserMenuUnfolded" class="ps-0 mb-0">
<t t-foreach="currentAppSections" t-as="subMenu" t-key="subMenu_index">
<t t-call="web.BurgerSection">
<t t-set="section" t-value="subMenu" />
</t>
</t>
</ul>
</nav>
</div>
</Transition>
</t>
<t t-portal="'body'">
<div t-if="state.isBurgerOpened" class="o_burger_menu_backdrop d-md-none" t-on-click.stop="_closeBurger" t-on-touchstart.stop="_onSwipeStart" t-on-touchend.stop="_onSwipeEnd" />
<div t-if="state.isBurgerOpened" class="o_burger_menu_backdrop modal-backdrop show d-block d-md-none" t-on-click.stop="_closeBurger" t-on-touchstart.stop="_onSwipeStart" t-on-touchend.stop="_onSwipeEnd" />
</t>
</div>
<t t-name="web.BurgerSection" owl="1">
<div t-if="section.childrenTree.length" t-key="section.id" class="dropdown o_burger_menu_section show">
<button class="dropdown-toggle" t-att-data-menu-xmlid="section.xmlid">
<span t-esc="section.name"/>
</button>
<div class="dropdown-menu d-block">
<li t-if="section.childrenTree.length" class="ps-0">
<div class="py-3 bg-transparent" t-att-class="{ 'fs-4': !isNested }"
t-att-data-menu-xmlid="section.xmlid" t-esc="section.name"/>
<ul class="ps-0">
<t t-foreach="section.childrenTree" t-as="subSection" t-key="subSection_index">
<t t-call="web.BurgerSection">
<t t-set="section" t-value="subSection" />
<t t-set="section" t-value="subSection"/>
<t t-set="isNested" t-value="true"/>
</t>
</t>
</div>
</div>
<DropdownItem t-else="" t-key="section.id" onSelected="() => this._onMenuClicked(section)" dataset="{ menuXmlid: section.xmlid }">
<span t-esc="section.name" />
</DropdownItem>
</ul>
</li>
<li t-else="" t-on-click="() => this._onMenuClicked(section)" t-att-data-menu-xmlid="section.xmlid"
class="py-3" t-att-class="{ 'fs-4': !isNested }">
<t t-esc="section.name"/>
</li>
</t>
</templates>
@@ -6,7 +6,7 @@
<t t-foreach="getElements()" t-as="element" t-key="element_index">
<t t-if="!element.hide">
<t t-if="element.type == 'item'">
<a t-att-class="'dropdown-item'" t-att-href="element.href or ''" t-esc="element.description" t-on-click.stop.prevent="() => this._onItemClicked(element.callback)"/>
<a class="dropdown-item py-3 fs-4" t-att-href="element.href or ''" t-esc="element.description" t-on-click.stop.prevent="() => this._onItemClicked(element.callback)"/>
</t>
<div t-if="element.type == 'separator'" role="separator" class="dropdown-divider"/>
</t>
@@ -69,11 +69,11 @@ QUnit.test("Burger Menu on an App", async (assert) => {
assert.containsOnce(document.body, ".o_burger_menu");
assert.containsOnce(
document.body,
".o_burger_menu .o_burger_menu_app .o_menu_sections .dropdown-item"
".o_burger_menu nav.o_burger_menu_content li"
);
assert.strictEqual(
document.body.querySelector(
".o_burger_menu .o_burger_menu_app .o_menu_sections .dropdown-item"
".o_burger_menu nav.o_burger_menu_content li"
).textContent,
"SubMenu"
);
@@ -90,7 +90,7 @@ QUnit.test("Burger Menu on an App", async (assert) => {
});
QUnit.test("Burger Menu on an App without SubMenu", async (assert) => {
assert.expect(6);
assert.expect(4);
await createWebClient({ serverData });
await click(document.body, ".o_navbar_apps_menu .dropdown-toggle");
@@ -103,8 +103,6 @@ QUnit.test("Burger Menu on an App without SubMenu", async (assert) => {
await click(document.body, ".o_mobile_menu_toggle");
assert.containsOnce(document.body, ".o_burger_menu");
assert.containsOnce(document.body, ".o_user_menu_mobile");
assert.containsOnce(document.body, ".o_burger_menu_user");
assert.containsNone(document.body, ".o_burger_menu_app");
await click(document.body, ".o_burger_menu_close");
assert.containsNone(document.body, ".o_burger_menu");
});
@@ -148,11 +146,11 @@ QUnit.test("Burger menu closes when click on menu item", async (assert) => {
assert.containsOnce(document.body, ".o_burger_menu");
assert.strictEqual(
document.body.querySelector(
".o_burger_menu .o_burger_menu_app .o_menu_sections .dropdown-item"
".o_burger_menu nav.o_burger_menu_content li"
).textContent,
"SubMenu"
);
await click(document.body, ".o_burger_menu .o_burger_menu_app .o_menu_sections .dropdown-item");
await click(document.body, ".o_burger_menu nav.o_burger_menu_content li");
await legacyExtraNextTick();
await legacyExtraNextTick();
assert.containsNone(document.body, ".o_burger_menu");
@@ -13,12 +13,13 @@ tour.register('main_flow_tour', {
tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Quotations')"),
{
// Add Stockable product
mobile: false,
trigger: ".o_menu_sections .dropdown-toggle span:contains('Products')",
extra_trigger: '.o_main_navbar',
content: _t("Let's create products."),
position: "bottom",
}, {
trigger: ".o_menu_sections .dropdown-item:contains('Products')",
trigger: ".o_menu_sections .dropdown-item:contains('Products'), nav.o_burger_menu_content li[data-menu-xmlid='sale.menu_product_template_action']",
content: _t("Let's create products."),
position: "bottom"
}, {
@@ -634,26 +635,9 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Inventory Ove
content: _t("Go to Configuration"),
position: "bottom"
}, {
mobile: false,
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='stock.menu_reordering_rules_config']",
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='stock.menu_reordering_rules_config'], nav.o_burger_menu_content li[data-menu-xmlid='stock.menu_reordering_rules_config']",
content: _t("Reordering Rules"),
position: "bottom"
}, {
mobile: true,
trigger: ".o_menu_sections button:contains('Configuration')",
extra_trigger: '.o_main_navbar',
content: _t("Go to Configuration"),
position: "bottom"
}, {
mobile: true,
trigger: ".o_menu_sections button[data-menu-xmlid='stock.menu_product_in_config_stock']",
content: _t("Click on Product Section"),
position: "bottom"
}, {
mobile: true,
trigger: ".o_menu_sections .dropdown-item:not(.o_dropdown):contains('Reordering Rules')",
content: _t("Click on Product Section"),
position: "bottom"
}, {
mobile: false,
trigger: ".o_list_button_add",
@@ -767,8 +751,7 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Manufacturing
content: _t('Click on Operations menuitem'),
position: 'bottom',
}, {
mobile: false,
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='mrp.menu_mrp_production_action']",
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='mrp.menu_mrp_production_action'], nav.o_burger_menu_content li[data-menu-xmlid='mrp.menu_mrp_production_action']",
content: _t('Open manufacturing orders'),
position: 'bottom',
}, {
@@ -776,17 +759,6 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Manufacturing
trigger: '.o_data_row:has(.o_data_cell:contains("the_flow.product")):first .o_data_cell:first',
content: _t('Select the generated manufacturing order'),
position: 'bottom',
}, {
mobile: true,
trigger: ".o_menu_sections button:contains('Operations')",
extra_trigger: '.o_main_navbar',
content: _t("Let's go to manufacturing order."),
position: "bottom",
}, {
mobile: true,
trigger: ".o_menu_sections .dropdown-item:contains('Manufacturing Orders')",
content: _t("Let's go to manufacturing order."),
position: "bottom"
}, {
mobile: true,
trigger: '.o_kanban_record:has(.o_kanban_record_title:contains("the_flow.product")):first',
@@ -814,11 +786,12 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Manufacturing
...tour.stepUtils.goToAppSteps('sale.sale_menu_root', Markup(_t('Organize your sales activities with the <b>Sales app</b>.'))),
tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('Quotations')"),
{
mobile: false,
trigger: ".o_menu_sections button[data-menu-xmlid='sale.sale_order_menu']",
content: _t("Go to Sales menu"),
position: "bottom"
}, {
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='sale.menu_sale_order']",
trigger: ".o_menu_sections .dropdown-item[data-menu-xmlid='sale.menu_sale_order'], nav.o_burger_menu_content li[data-menu-xmlid='sale.menu_sale_order']",
content: _t("Go to the sales orders"),
position: "bottom"
}, {