[IMP] website: partially hide content in headers on scroll

Following the redesign of website template headers, this commit
introduces a new class `.o_header_hide_on_scroll` to hide some part of
the header when scrolling.

task-3474743

Part-of: odoo/odoo#119650
This commit is contained in:
Robin Lejeune (role)
2023-10-25 11:37:12 +00:00
committed by qsm-odoo
parent 5cf32b489f
commit 143d475c3a
3 changed files with 98 additions and 61 deletions
+33 -5
View File
@@ -6,6 +6,10 @@ export const extraMenuUpdateCallbacks = [];
import dom from "@web/legacy/js/core/dom";
import { SIZES, utils as uiUtils } from "@web/core/ui/ui_service";
// The header height may vary with sections hidden on scroll (see the class
// `o_header_hide_on_scroll`). To avoid scroll jumps, we cache the value.
let headerHeight;
const BaseAnimatedHeader = animations.Animation.extend({
disabledInEditableMode: false,
effects: [{
@@ -35,6 +39,7 @@ const BaseAnimatedHeader = animations.Animation.extend({
this.$main = this.$el.next('main');
this.isOverlayHeader = !!this.$el.closest('.o_header_overlay, .o_header_overlay_theme').length;
this.$dropdowns = this.$el.find('.dropdown, .dropdown-menu');
this.hiddenOnScrollEl = this.el.querySelector(".o_header_hide_on_scroll");
this.$navbarCollapses = this.$el.find('.navbar-collapse');
// While scrolling through navbar menus on medium devices, body should not be scrolled with it
@@ -164,13 +169,13 @@ const BaseAnimatedHeader = animations.Animation.extend({
* @private
*/
_updateMainPaddingTop: function () {
this.headerHeight = this.$el.outerHeight();
headerHeight ||= this.el.getBoundingClientRect().height;
this.topGap = this._computeTopGap();
if (this.isOverlayHeader) {
return;
}
this.$main.css('padding-top', this.fixedHeader ? this.headerHeight : '');
this.$main.css('padding-top', this.fixedHeader ? headerHeight : '');
},
/**
* Checks if the size of the header will decrease by adding the
@@ -196,7 +201,7 @@ const BaseAnimatedHeader = animations.Animation.extend({
clonedHeader.classList.add('o_header_is_scrolled', 'o_header_affixed', 'o_header_no_transition');
const endHeaderHeight = clonedHeader.offsetHeight;
clonedHeader.remove();
const heightDiff = this.headerHeight - endHeaderHeight;
const heightDiff = headerHeight - endHeaderHeight;
return heightDiff > 0 ? remainingScroll <= heightDiff : false;
},
@@ -273,7 +278,7 @@ publicWidget.registry.StandardAffixedHeader = BaseAnimatedHeader.extend({
* @override
*/
start: function () {
this.headerHeight = this.$el.outerHeight();
headerHeight ||= this.el.getBoundingClientRect().height;
return this._super.apply(this, arguments);
},
/**
@@ -303,7 +308,7 @@ publicWidget.registry.StandardAffixedHeader = BaseAnimatedHeader.extend({
_updateHeaderOnScroll: function (scroll) {
this._super(...arguments);
const mainPosScrolled = (scroll > this.headerHeight + this.topGap);
const mainPosScrolled = (scroll > headerHeight + this.topGap);
const reachPosScrolled = (scroll > this.scrolledPoint + this.topGap) && !this.scrollHeightTooShort;
const fixedUpdate = (this.fixedHeader !== mainPosScrolled);
const showUpdate = (this.fixedHeaderShow !== reachPosScrolled);
@@ -319,6 +324,7 @@ publicWidget.registry.StandardAffixedHeader = BaseAnimatedHeader.extend({
}
this.fixedHeaderShow = reachPosScrolled;
this.hiddenOnScrollEl?.classList.toggle("hidden", mainPosScrolled);
if (fixedUpdate) {
this._toggleFixedHeader(mainPosScrolled);
@@ -353,6 +359,28 @@ publicWidget.registry.FixedHeader = BaseAnimatedHeader.extend({
void this.$el[0].offsetWidth; // Force a paint refresh
this.$el.css('transform', '');
}
if (this.hiddenOnScrollEl) {
const scrollDelta = window.matchMedia(`(prefers-reduced-motion: reduce)`).matches ?
scroll : Math.floor(scroll / 4);
const elHeight = Math.max(0, this.hiddenOnScrollEl.scrollHeight - scrollDelta);
this.hiddenOnScrollEl.classList.toggle("hidden", elHeight === 0);
if (elHeight === 0) {
this.hiddenOnScrollEl.removeAttribute("style");
} else {
this.hiddenOnScrollEl.style.overflow = "hidden";
this.hiddenOnScrollEl.style.height = `${elHeight}px`;
let elPadding = parseInt(getComputedStyle(this.hiddenOnScrollEl).paddingBlock);
if (elHeight < elPadding * 2) {
const heightDifference = elPadding * 2 - elHeight;
elPadding = Math.max(0, elPadding - Math.floor(heightDifference / 2));
this.hiddenOnScrollEl.style
.setProperty("padding-block", `${elPadding}px`, "important");
} else {
this.hiddenOnScrollEl.style.paddingBlock = "";
}
}
}
},
});
@@ -988,6 +988,12 @@ $-transition-duration: 200ms;
}
}
}
.o_header_hide_on_scroll.hidden {
max-height: 0;
padding-block: 0 !important;
overflow: hidden;
}
}
.o_hoverable_dropdown .nav-link.dropdown-toggle:focus {
+59 -56
View File
@@ -725,8 +725,8 @@
<t t-call="website.navbar">
<t t-set="_navbar_classes" t-valuef="d-none d-lg-block pt-3 shadow-sm"/>
<div id="o_main_nav" class="container flex-wrap gap-3">
<div class="d-grid align-items-center w-100 o_grid_header_3_cols">
<div id="o_main_nav" class="container flex-wrap">
<div class="o_header_hide_on_scroll d-grid align-items-center w-100 o_grid_header_3_cols pb-3">
<ul class="navbar-nav align-items-center gap-1">
<!-- Search bar -->
<t t-call="website.placeholder_header_search_box">
@@ -797,7 +797,7 @@
<t t-set="_navbar_classes" t-valuef="d-none d-lg-block p-0 shadow-sm"/>
<div id="o_main_nav" class="flex-wrap">
<div aria-label="Top" class="border-bottom o_border_contrast">
<div aria-label="Top" class="o_header_hide_on_scroll border-bottom o_border_contrast">
<div class="container d-flex justify-content-between flex-wrap w-100">
<ul class="o_header_search_left_col navbar-nav flex-wrap">
<!-- Language Selector -->
@@ -952,7 +952,7 @@
</t>
</ul>
</div>
<div aria-label="Bottom" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links')" class="o_header_sales_one_bot gap-3 py-2">
<div aria-label="Bottom" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links')" class="o_header_sales_one_bot o_header_hide_on_scroll gap-3 py-2">
<ul class="navbar-nav container justify-content-between align-items-center">
<!-- Text element -->
<t t-call="website.placeholder_header_text_element">
@@ -993,57 +993,59 @@
<t t-set="_navbar_classes" t-valuef="d-none d-lg-block p-0 shadow-sm"/>
<div id="o_main_nav">
<div aria-label="Top" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links') or is_view_active('website.header_language_selector')" class="o_header_sales_two_top py-1">
<ul class="navbar-nav container d-grid h-100 px-3 o_grid_header_3_cols">
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_lang_selector_placeholder" t-if="is_view_active('website.header_language_selector') == False"/>
<!-- Language Selector -->
<t t-call="website.placeholder_header_language_selector">
<t t-set="_div_classes" t-valuef="d-flex align-items-center h-100"/>
<t t-set="_btn_class" t-valuef="btn-sm btn-outline-secondary border-0"/>
<div class="o_header_hide_on_scroll">
<div aria-label="Top" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links') or is_view_active('website.header_language_selector')" class="o_header_sales_two_top py-1">
<ul class="navbar-nav container d-grid h-100 px-3 o_grid_header_3_cols">
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_lang_selector_placeholder" t-if="is_view_active('website.header_language_selector') == False"/>
<!-- Language Selector -->
<t t-call="website.placeholder_header_language_selector">
<t t-set="_div_classes" t-valuef="d-flex align-items-center h-100"/>
<t t-set="_btn_class" t-valuef="btn-sm btn-outline-secondary border-0"/>
</t>
<!-- Text element -->
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_txt_elts_placeholder" t-if="is_view_active('website.header_text_element') == False"/>
<t t-call="website.placeholder_header_text_element">
<t t-set="_txt_elt_content" t-valuef="sentence"/>
<t t-set="_div_class" t-valuef="d-flex align-items-center mx-auto"/>
<t t-set="_item_class" t-valuef="d-flex align-items-center"/>
</t>
<!-- Social -->
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_social_links_placeholder" t-if="is_view_active('website.header_social_links') == False"/>
<t t-call="website.header_social_links_no_color">
<t t-set="_div_class" t-valuef="d-flex align-items-center justify-content-end h-100"/>
</t>
</ul>
</div>
<div aria-label="Middle" class="container d-flex justify-content-between align-items-center py-1">
<!-- Brand -->
<t t-call="website.placeholder_header_brand">
<t t-set="_link_class" t-valuef="me-4"/>
</t>
<!-- Text element -->
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_txt_elts_placeholder" t-if="is_view_active('website.header_text_element') == False"/>
<t t-call="website.placeholder_header_text_element">
<t t-set="_txt_elt_content" t-valuef="sentence"/>
<t t-set="_div_class" t-valuef="d-flex align-items-center mx-auto"/>
<t t-set="_item_class" t-valuef="d-flex align-items-center"/>
</t>
<!-- Social -->
<!-- Return empty placeholder if the element is not active to keep the right layout -->
<li class="o_header_sales_two_social_links_placeholder" t-if="is_view_active('website.header_social_links') == False"/>
<t t-call="website.header_social_links_no_color">
<t t-set="_div_class" t-valuef="d-flex align-items-center justify-content-end h-100"/>
</t>
</ul>
</div>
<div aria-label="Middle" class="container d-flex justify-content-between align-items-center py-1">
<!-- Brand -->
<t t-call="website.placeholder_header_brand">
<t t-set="_link_class" t-valuef="me-4"/>
</t>
<ul class="navbar-nav align-items-center gap-1">
<!-- Search bar -->
<t t-call="website.placeholder_header_search_box">
<t t-set="_input_classes" t-valuef="rounded-start-pill ps-3 text-bg-light"/>
<t t-set="_submit_classes" t-valuef="rounded-end-pill p-3 bg-o-color-3 lh-1"/>
</t>
<!-- Sign In -->
<t t-call="portal.placeholder_user_sign_in">
<t t-set="_link_class" t-valuef="btn btn-outline-secondary"/>
</t>
<!-- User Dropdown -->
<t t-call="portal.user_dropdown">
<t t-set="_user_name" t-value="true"/>
<t t-set="_icon" t-value="true"/>
<t t-set="_icon_class" t-valuef="fa-stack"/>
<t t-set="_item_class" t-valuef="dropdown"/>
<t t-set="_link_class" t-valuef="d-flex align-items-center border-0 fw-bold text-reset o_navlink_background_hover"/>
<t t-set="_icon_wrap_class" t-value="'position-relative me-2 rounded-circle border p-2 bg-o-color-3'"/>
<t t-set="_dropdown_menu_class" t-valuef="dropdown-menu-end"/>
</t>
</ul>
<ul class="navbar-nav align-items-center gap-1">
<!-- Search bar -->
<t t-call="website.placeholder_header_search_box">
<t t-set="_input_classes" t-valuef="rounded-start-pill ps-3 text-bg-light"/>
<t t-set="_submit_classes" t-valuef="rounded-end-pill p-3 bg-o-color-3 lh-1"/>
</t>
<!-- Sign In -->
<t t-call="portal.placeholder_user_sign_in">
<t t-set="_link_class" t-valuef="btn btn-outline-secondary"/>
</t>
<!-- User Dropdown -->
<t t-call="portal.user_dropdown">
<t t-set="_user_name" t-value="true"/>
<t t-set="_icon" t-value="true"/>
<t t-set="_icon_class" t-valuef="fa-stack"/>
<t t-set="_item_class" t-valuef="dropdown"/>
<t t-set="_link_class" t-valuef="d-flex align-items-center border-0 fw-bold text-reset o_navlink_background_hover"/>
<t t-set="_icon_wrap_class" t-value="'position-relative me-2 p-2 rounded-circle border bg-o-color-3'"/>
<t t-set="_dropdown_menu_class" t-valuef="dropdown-menu-end"/>
</t>
</ul>
</div>
</div>
<div aria-label="Bottom" class="border-top o_border_contrast">
<div class="container d-flex justify-content-between">
@@ -1094,7 +1096,8 @@
<t t-set="_navbar_classes" t-valuef="d-none d-lg-block p-0 shadow-sm"/>
<div id="o_main_nav">
<div aria-label="Top" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links') or is_view_active('website.header_search_box') or is_view_active('website.header_call_to_action')" class="o_header_sales_three_top position-relative border-bottom z-index-1 o_border_contrast">
<div aria-label="Top" t-if="is_view_active('website.header_text_element') or is_view_active('website.header_social_links') or is_view_active('website.header_search_box') or is_view_active('website.header_call_to_action')"
class="o_header_sales_three_top o_header_hide_on_scroll position-relative border-bottom z-index-1 o_border_contrast">
<div class="container d-flex justify-content-between gap-3 h-100">
<ul class="navbar-nav align-items-center gap-3 py-1">
<!-- Social -->
@@ -1225,7 +1228,7 @@
</t>
</ul>
</div>
<div aria-label="Bottom" class="o_header_sales_four_bot z-index-0">
<div aria-label="Bottom" class="o_header_sales_four_bot o_header_hide_on_scroll z-index-0">
<div class="container">
<ul class="navbar-nav d-grid align-items-center py-2 o_grid_header_3_cols">
<!-- Search bar -->