DEV: Refactor header offset calculations (#29398)
This commit is contained in:
parent
6c91148db8
commit
041ac3d8b7
|
@ -22,6 +22,7 @@ import Header from "./header";
|
|||
|
||||
let _menuPanelClassesToForceDropdown = [];
|
||||
const PANEL_WIDTH = 340;
|
||||
const DEBOUNCE_HEADER_DELAY = 10;
|
||||
|
||||
export default class GlimmerSiteHeader extends Component {
|
||||
@service appEvents;
|
||||
|
@ -36,6 +37,7 @@ export default class GlimmerSiteHeader extends Component {
|
|||
@tracked _dockedHeader = false;
|
||||
_animate = false;
|
||||
_headerWrap;
|
||||
_mainOutletWrapper;
|
||||
_swipeMenuOrigin;
|
||||
_applicationElement;
|
||||
_resizeObserver;
|
||||
|
@ -69,42 +71,51 @@ export default class GlimmerSiteHeader extends Component {
|
|||
}
|
||||
|
||||
@bind
|
||||
updateHeaderOffset() {
|
||||
// Safari likes overscolling the page (on both iOS and macOS).
|
||||
// This shows up as a negative value in window.scrollY.
|
||||
// We can use this to offset the headerWrap's top offset to avoid
|
||||
// jitteriness and bad positioning.
|
||||
const windowOverscroll = Math.min(0, window.scrollY);
|
||||
|
||||
// The headerWrap's top offset can also be a negative value on Safari,
|
||||
// because of the changing height of the viewport (due to the URL bar).
|
||||
// For our use case, it's best to ensure this is clamped to 0.
|
||||
const headerWrapTop = Math.max(
|
||||
updateOffsets() {
|
||||
// clamping to 0 to prevent negative values (hello, Safari)
|
||||
const headerWrapBottom = Math.max(
|
||||
0,
|
||||
Math.floor(this._headerWrap.getBoundingClientRect().top)
|
||||
Math.floor(this._headerWrap.getBoundingClientRect().bottom)
|
||||
);
|
||||
|
||||
let mainOutletOffsetTop = Math.max(
|
||||
0,
|
||||
Math.floor(this._mainOutletWrapper.getBoundingClientRect().top) -
|
||||
headerWrapBottom
|
||||
);
|
||||
let offsetTop = headerWrapTop + windowOverscroll;
|
||||
|
||||
if (DEBUG && isTesting()) {
|
||||
offsetTop -= document
|
||||
mainOutletOffsetTop -= document
|
||||
.getElementById("ember-testing-container")
|
||||
.getBoundingClientRect().top;
|
||||
|
||||
offsetTop -= 1; // For 1px border on testing container
|
||||
mainOutletOffsetTop -= 1; // For 1px border on testing container
|
||||
}
|
||||
|
||||
const documentStyle = document.documentElement.style;
|
||||
const currentValue =
|
||||
parseInt(documentStyle.getPropertyValue("--header-offset"), 10) || 0;
|
||||
const newValue = this._headerWrap.offsetHeight + offsetTop;
|
||||
if (currentValue !== newValue) {
|
||||
documentStyle.setProperty("--header-offset", `${newValue}px`);
|
||||
const docStyle = document.documentElement.style;
|
||||
const currentHeaderOffset =
|
||||
parseInt(docStyle.getPropertyValue("--header-offset"), 10) || 0;
|
||||
const newHeaderOffset = headerWrapBottom;
|
||||
if (currentHeaderOffset !== newHeaderOffset) {
|
||||
docStyle.setProperty("--header-offset", `${newHeaderOffset}px`);
|
||||
}
|
||||
|
||||
const currentMainOutletOffset =
|
||||
parseInt(docStyle.getPropertyValue("--main-outlet-offset"), 10) || 0;
|
||||
const newMainOutletOffset = headerWrapBottom + mainOutletOffsetTop;
|
||||
if (currentMainOutletOffset !== newMainOutletOffset) {
|
||||
docStyle.setProperty("--main-outlet-offset", `${newMainOutletOffset}px`);
|
||||
}
|
||||
}
|
||||
|
||||
@debounce(DEBOUNCE_HEADER_DELAY)
|
||||
_recalculateHeaderOffset() {
|
||||
this._scheduleUpdateOffsets();
|
||||
}
|
||||
|
||||
@bind
|
||||
_onScroll() {
|
||||
schedule("afterRender", this.updateHeaderOffset);
|
||||
_scheduleUpdateOffsets() {
|
||||
schedule("afterRender", this.updateOffsets);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -119,17 +130,13 @@ export default class GlimmerSiteHeader extends Component {
|
|||
}
|
||||
|
||||
this._headerWrap = document.querySelector(".d-header-wrap");
|
||||
this._mainOutletWrapper = document.querySelector("#main-outlet-wrapper");
|
||||
if (this._headerWrap) {
|
||||
schedule("afterRender", () => {
|
||||
this.headerElement = this._headerWrap.querySelector("header.d-header");
|
||||
this.updateHeaderOffset();
|
||||
document.documentElement.style.setProperty(
|
||||
"--header-top",
|
||||
`${this.headerElement.offsetTop}px`
|
||||
);
|
||||
});
|
||||
|
||||
window.addEventListener("scroll", this._onScroll, {
|
||||
window.addEventListener("scroll", this._recalculateHeaderOffset, {
|
||||
passive: true,
|
||||
});
|
||||
|
||||
|
@ -137,20 +144,11 @@ export default class GlimmerSiteHeader extends Component {
|
|||
const dirs = ["up", "down"];
|
||||
this._itsatrap.bind(dirs, (e) => this._handleArrowKeysNav(e));
|
||||
|
||||
this._resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
if (entry.contentRect) {
|
||||
const headerTop = this.headerElement?.offsetTop;
|
||||
document.documentElement.style.setProperty(
|
||||
"--header-top",
|
||||
`${headerTop}px`
|
||||
);
|
||||
this.updateHeaderOffset();
|
||||
}
|
||||
}
|
||||
this._resizeObserver = new ResizeObserver(() => {
|
||||
this._recalculateHeaderOffset();
|
||||
});
|
||||
|
||||
this._resizeObserver.observe(this._headerWrap);
|
||||
this._resizeObserver.observe(document.querySelector(".discourse-root"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,7 +408,7 @@ export default class GlimmerSiteHeader extends Component {
|
|||
this._itsatrap?.destroy();
|
||||
this._itsatrap = null;
|
||||
|
||||
window.removeEventListener("scroll", this._onScroll);
|
||||
window.removeEventListener("scroll", this._recalculateHeaderOffset);
|
||||
this._resizeObserver?.disconnect();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// positions are relative to the .d-header .panel div
|
||||
top: 100%; // directly underneath .panel
|
||||
right: -10px; // 10px to the right of .panel - adjust as needed
|
||||
max-height: 80vh;
|
||||
max-height: calc(100dvh - var(--header-offset) - 1em);
|
||||
border-radius: var(--d-border-radius-large);
|
||||
}
|
||||
|
||||
|
@ -660,14 +660,14 @@
|
|||
width: 100%;
|
||||
position: fixed;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
top: var(--header-top);
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: none;
|
||||
touch-action: pan-y pinch-zoom;
|
||||
}
|
||||
|
||||
.menu-panel.slide-in {
|
||||
top: var(--header-top);
|
||||
top: 0;
|
||||
box-sizing: border-box;
|
||||
// ensure there's always space to click outside on tiny devices
|
||||
max-width: 90vw;
|
||||
|
@ -678,11 +678,5 @@
|
|||
}
|
||||
box-shadow: 0px 0 30px -2px rgba(0, 0, 0, 0.5);
|
||||
|
||||
--base-height: calc(var(--100dvh) - var(--header-top));
|
||||
|
||||
height: var(--base-height);
|
||||
|
||||
html.footer-nav-ipad & {
|
||||
height: calc(var(--base-height) - var(--footer-nav-height));
|
||||
}
|
||||
height: var(--100dvh);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
display: flex;
|
||||
grid-area: sidebar;
|
||||
position: sticky;
|
||||
top: var(--header-offset);
|
||||
top: var(--main-outlet-offset);
|
||||
background: var(--d-sidebar-background);
|
||||
|
||||
@include unselectable;
|
||||
|
@ -57,7 +57,7 @@
|
|||
}
|
||||
|
||||
height: calc(
|
||||
var(--composer-vh, var(--1dvh)) * 100 - var(--header-offset, 0px)
|
||||
var(--composer-vh, var(--1dvh)) * 100 - var(--main-outlet-offset, 0px)
|
||||
);
|
||||
|
||||
align-self: start;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
&.drop-down {
|
||||
.panel-body {
|
||||
max-height: calc(100vh - var(--header-offset));
|
||||
max-width: calc(100vw - 2em);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ body.has-full-page-chat {
|
|||
|
||||
.c-navbar-container {
|
||||
position: sticky;
|
||||
top: var(--header-offset);
|
||||
top: var(--main-outlet-offset);
|
||||
}
|
||||
|
||||
.chat-messages-scroller {
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
resize: none;
|
||||
max-height: calc(
|
||||
(
|
||||
var(--100dvh) - var(--header-offset, 0px) -
|
||||
var(--100dvh) - var(--main-outlet-offset, 0px) -
|
||||
var(--chat-header-offset, 0px)
|
||||
) / 100 * 25
|
||||
);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
// desktop and mobile
|
||||
// -1px is for the bottom border of the chat navbar
|
||||
$base-height: calc(
|
||||
var(--composer-vh, 1vh) * 100 - var(--header-offset, 0px) - 1px - $inset
|
||||
var(--composer-vh, 1vh) * 100 - var(--main-outlet-offset, 0px) - 1px -
|
||||
$inset
|
||||
);
|
||||
|
||||
height: calc($base-height - var(--composer-height, 0px));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.has-full-page-chat:not(.discourse-sidebar) {
|
||||
.full-page-chat {
|
||||
.channels-list {
|
||||
height: calc(100vh - var(--header-offset));
|
||||
height: calc(100vh - var(--main-outlet-offset));
|
||||
border-right: 1px solid var(--primary-low);
|
||||
background: var(--secondary);
|
||||
overflow-y: auto;
|
||||
|
|
Loading…
Reference in New Issue